pwn的补充知识
堆栈平衡
堆栈平衡是指在函数调用过程中,确保堆栈在进入和结束时保持一致。函数执行前到ret执行之前,堆栈栈顶的地址必须是call
指令的下一个地址。如果堆栈变化了,需要在ret执行前将堆栈恢复称原来的样子,以确保程序能回到正确的位置。
64位ubuntu18以上系统调用system函数时是需要栈对齐的。因为64位下system函数存在movaps
指令,这个指令要求内存地址必需16字节对齐。
因为64位程序的地址是8字节的,而十六进制是满16进位,所以64位程序的栈地址末尾为0或8
,只有当地址末尾是0的时候,才算是与16字节对齐了,如果末尾是8,就是没有对齐,所以如果要在ubuntu18以上的64位程序中执行system函数,必须要保证system地址末尾为0。
程序在执行一个对栈指令(如pop、ret、push
等,mov
这样的不算对栈的操作指令),则栈地址就会+8
或-8
,为了使rsp对齐16字节,核心思想就是增加或者减少栈内容,使rsp
地址能相应的增加或减少8字节,利用这样的方式来对齐16字节。因为栈中地址都是以0
或8
结尾,0已经对齐16字节,因此只需要进行奇数次pop或者push操作,就能把地址是8结尾的rsp变为0结尾,使其16字节对齐。
- 去将system函数地址+1,也就是跳过一条栈操作指令,使rsp对齐。
- 直接在调用system函数地址之前去调用一个ret指令。ret指令等同于pop rip,该指令使rsp+8,从而完成rsp16字节对齐,实现了栈对齐。
pwn技术分享—执行system前为何要执行retn指令
关于ubuntu18版本以上调用64位程序中的system函数的栈对齐问题
偏移量计算
GDB-peda计算偏移
64位程序
1 | gdb ./pwn |
复制生成的200个测试字节,下断点到输入函数
1 | ni |
输入刚刚的测试字符
可以看到,程序崩溃,若程序未崩溃,则要添加更多的测试字节数。
复制RBP这里的八个字节,然后
1 | pattern offset 6AALAAhA |
得到计算出得偏移为96
我们验证一下:
输入96+8字节(因为是64位程序),刚好覆盖掉RBP寄存器
GDB-PWNdbg计算偏移
1 | gdb ./pwn |
生成200个字节,然后下断点运行到输入点,输入上述生成的200字节,程序报错,找到RBP的地址,复制。
1 | cyclic -l 0x616161616161616d |
同样计算出偏移为96
ret2libc工具
ROPgadget
获取gadget
地址,--binary
参数指定文件,可以是可执行文件或libc
文件,grep
用于筛选,--string
用于筛选字符串
1 | ROPgadget --binary ./pwn --only 'pop|ret' | grep 'rdi' #控制寄存器的值 |
patchelf
更改可执行文件的动态链接文件,更改ld
可以直接指定ld
文件,而更改libc
需要先使用ldd
查看原libc
作为--replace-needed
选项的第一个参数,一般默认是libc.so.6
。
1 | patchelf --replace-needed libc.so.6 ./2.38/libc.so.6 ./pwn #更改libc |
onegadget
能直接getshell的gadget,添加参数-l2
可以获得更多
1 | one_gadget ./libc.so.6 |