堆栈平衡

堆栈平衡是指在函数调用过程中,确保堆栈在进入和结束时保持一致。函数执行前到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字节。因为栈中地址都是以08结尾,0已经对齐16字节,因此只需要进行奇数次pop或者push操作,就能把地址是8结尾的rsp变为0结尾,使其16字节对齐。

  1. 去将system函数地址+1,也就是跳过一条栈操作指令,使rsp对齐。
  2. 直接在调用system函数地址之前去调用一个ret指令。ret指令等同于pop rip,该指令使rsp+8,从而完成rsp16字节对齐,实现了栈对齐。
    pwn技术分享—执行system前为何要执行retn指令
    关于ubuntu18版本以上调用64位程序中的system函数的栈对齐问题

偏移量计算

GDB-peda计算偏移

64位程序

1
2
gdb ./pwn
pattern create 200

复制生成的200个测试字节,下断点到输入函数
alt text

1
ni

输入刚刚的测试字符
alt text
可以看到,程序崩溃,若程序未崩溃,则要添加更多的测试字节数。
alt text
复制RBP这里的八个字节,然后

1
pattern offset 6AALAAhA

alt text
得到计算出得偏移为96
alt text
我们验证一下:
输入96+8字节(因为是64位程序),刚好覆盖掉RBP寄存器
alt text

GDB-PWNdbg计算偏移

1
2
gdb ./pwn
cyclic 200

生成200个字节,然后下断点运行到输入点,输入上述生成的200字节,程序报错,找到RBP的地址,复制。
alt text

1
cyclic -l 0x616161616161616d

同样计算出偏移为96
alt text

ret2libc工具

ROPgadget

获取gadget地址,--binary参数指定文件,可以是可执行文件或libc文件,grep用于筛选,--string用于筛选字符串

1
2
3
4
5
$ROPgadget --binary ./pwn --only 'pop|ret' | grep 'rdi' #控制寄存器的值
$ROPgadget --binary ./pwn --string '/bin/sh' #查找字符串
$ROPgadget --binary ./libc-2.35.so --only 'leave|ret' | grep 'leave' #查找leave ret指令地址
$ROPgadget --binary ./pwn --ropchain #生成现成的rop利用链直接getshell,适用于静态编译的程序
$ROPgadget --binary ./pwn --only 'ret' #查找ret指令的地址

patchelf

更改可执行文件的动态链接文件,更改ld可以直接指定ld文件,而更改libc需要先使用ldd查看原libc作为--replace-needed选项的第一个参数,一般默认是libc.so.6

1
2
$patchelf --replace-needed libc.so.6 ./2.38/libc.so.6 ./pwn #更改libc
$patchelf --set-interpreter ./2.35/ld-linux-x86-64.so.2 ./pwn #更改ld

onegadget

能直接getshell的gadget,添加参数-l2可以获得更多

1
one_gadget ./libc.so.6