漏洞
read函数没有限制输入的长度,存在栈溢出。
计算栈溢出偏移量
关键点:sub esp,88h
lea eax,[ebp+buf]
ida说eax是read函数的buf,所以偏移量就是0x88,我们需要覆盖的是ret地址,中间还隔了一个ebp,所以padding为0x88+4。
计算libc偏移量
由于是动态链接库,每次加载的基址都不一样,所以需要使用write泄露出某个libc函数的真实地址,再根据库中函数相当位置相同
推算出别的库函数的实际地址。
write函数
三个参数,通过栈传递,分别为:nbytes,buf,fd。在栈中的顺序大概是这样:
| 栈顶 |
| fd |
| buf |
|nbytes|
因此,我们要伪造的泄露write地址的栈帧为:
| 栈顶 |
| write@plt|
|return_add|
| 1 |
|write@got |
| 4 |
接下来程序输出的就是write的真实地址
ELF.
pwntools中的计算基址的神器,用法:
ELF(“二进制文件路径”)
ELF.symbols[‘’] 查看函数地址
ELF.plt[‘’]同上
ELF.got[‘’]同上
libcsearcher模块:
libc.search(‘’)在库中寻找
基址偏移公式
write真实地址-write在libc中的地址=偏移量
return_addr
计算到了偏移量,我们还不能停,因为重新加载程序会生成一个新的偏移量,所以这时我们要劫持程序
流程,再次进入vuln函数,所以return_add填入vuln的地址,再入vuln函数,再次栈溢出。
getshell
得到偏移量后,根据各函数在libc中的地址,我们很容易就能算出真实地址,接下来只需要调用system(/bin/sh)就完事了
system就一个参数,所以伪造的栈帧为:
| 栈顶 |
|return_add|
| bin_add |
由于执行完就getshell了,所以return_addr瞎填就行,只要是四个字节。
exp
1 | #!/usr/bin/python |