1.6 Shellcoding
What is a Shellcoding
Execution of Shellcode
When an attacker identifies a vulnerable application, their primary goal is often to inject shellcode into the software. Once the shellcode is successfully injected, the attacker manipulates the instruction pointer register (EIP) to point to the shellcode. This enables the shellcode to execute without restrictions, providing the attacker with control over the system.
There are two primary methods by which shellcode can be executed:
1. Remote Buffer Overflows (Network-Based)
Objective: Inject shellcode into the vulnerable application through the network.
Execution: The attacker sends the shellcode remotely, triggering a buffer overflow.
Outcome: When successful, the EIP is adjusted to the location of the injected shellcode.
2. Local Environment Execution
Objective: Inject shellcode into the vulnerable application in the local environment.
Execution: The attacker manipulates the EIP to point to the locally injected shellcode.
Outcome: The shellcode runs within the local system, giving the attacker control.
Alternative Execution Method: Structured Exception Handling (SEH)
While manipulating the EIP is a common method, shellcode can also be triggered to execute when a Structured Exception Handling (SEH) frame activates. SEH frames store the address to jump to when an exception occurs, such as a division by zero.
The steps for execution via SEH manipulation involve:
Overwriting Return Address:
The attacker overwrites the return address stored in the SEH frame.
By doing so, the attacker gains control over the execution flow when an exception is encountered.
Exception Triggering:
The attacker induces an exception, for example, by causing a division by zero.
This activates the SEH mechanism.
Control Transfer:
As the SEH frame is activated, the manipulated return address directs the flow of execution to the attacker's shellcode.
In summary, manipulating the EIP and exploiting SEH frames are common tactics for executing shellcode, providing attackers with unauthorized control over the vulnerable system. This underscores the importance of implementing robust security measures to detect and prevent such attacks.
Types of Shellcode Execution Strategies
Shellcode execution strategies vary based on how the shellcode runs and grants control to the attacker. Here are several types of execution strategies:
Local Shellcode
Objective: Exploit local processes to gain higher privileges on the machine.
Alias: Privilege escalation shellcode.
Usage: Exploited in local code execution vulnerabilities.
Remote Shellcode
Objective: Sent through the network along with an exploit. Aims to be injected into a process and executed remotely.
Usage: Provides remote access to the exploited machine using common network protocols (e.g., TCP/IP).
Sub-divisions based on connection setup:
Connect Back: Initiates a connection back to the attacker's machine.
Bind Shell: Binds a shell or command prompt to a specific port for the attacker to connect.
Staged Shellcode
Usage: Deployed when the shellcode size exceeds the available injection space. Executed in two stages:
Stage 1 (Small Shellcode): Executes and fetches the larger Stage 2 shellcode into the process memory.
Stage 2 (Larger Shellcode): Executed after Stage 1.
Egg-Hunt Shellcode
Scenario: Used when a larger shellcode is injected, but the injection location is unknown.
Components:
Egg-Hunter: Small shellcode tasked with searching for the larger shellcode (egg) in the process address space.
Egg: The actual larger shellcode that gets executed once found.
Omelet Shellcode
Similarity to Egg-Hunt: Similar to egg-hunt shellcode but involves multiple smaller shellcodes (eggs) combined and executed.
Purpose: Used to evade shellcode detectors. While individual eggs may not trigger alarms, collectively they form a complete shellcode.
Download and Execute Shellcode
Functionality: Instead of immediately creating a shell, this type of shellcode downloads an executable from the internet and then executes it.
Executable Content: Can be a data harvesting tool, malware, or a backdoor.
These diverse shellcode execution strategies reflect the adaptability and creativity of attackers seeking unauthorized access and control over systems. Security measures should be implemented to detect and prevent such attacks.
Encoding of Shellcode
In the context of shellcode, encoding is often employed to bypass restrictions or filters that may exist in vulnerable applications. This is particularly relevant when dealing with NULL bytes, as many string functions in programming languages terminate when they encounter NULL.
Consider the following example in C:
In this example, the program concatenates string1
and string2
into StringToPrint
. If string2
contains a NULL character \x00
, the concatenation stops at that point. To ensure the execution of the complete shellcode, NULL-free encoding is often employed.
Types of Shellcode Encoding
Null-Free Encoding:
Objective: Replace machine instructions containing NULL bytes with instructions that do not contain NULL bytes but achieve the same tasks.
Example:
Original:
MOV EAX, 0
Encoded:
XOR EAX, EAX
Alphanumeric and Printable Encoding:
Scenario: In cases where the target process filters out all non-alphanumeric bytes from the data.
Challenge: Alphanumeric shellcodes have limited instruction options.
Solution: Self-modifying Code (SMC) is used. The encoded shellcode is prepended with a small decoder (valid alphanumeric encoded shellcode) that, upon execution, decodes and runs the main body of the shellcode.
Self-Modifying Code (SMC):
Usage: Encode shellcode with a small decoder that, when executed, modifies and executes the main body of the shellcode.
Purpose: Bypass restrictions or filters, especially in cases where only certain types of instructions are allowed.
Example:
Original Shellcode:
MOV EAX, 0x12345678
Encoded Shellcode:
SUB EAX, 0x12345678
In summary, encoding is a technique employed to overcome limitations imposed by the structure of shellcode or the characteristics of the target application. It allows for the successful execution of shellcode even in environments where certain byte patterns are restricted or filtered.
Debugging a Shellcode
Before deploying a shellcode on a target system, it's crucial to verify that it works as intended. One way to test shellcode is to use a simple C program that executes the shellcode. Here's a basic template for such a program:
In this template, the code
array is where you would insert your shellcode. The program then converts this array into a function pointer and executes it.
For testing purposes, let's consider a shellcode that opens the Windows Calculator:
After inserting the shellcode into the code
array in the C program, you can compile and run the program. If the execution is successful, it indicates that the shellcode is functional. The appearance of the Calculator or the expected behavior indicates that the shellcode is working.
Remember, it's not necessary for the program to exit gracefully; a crash is acceptable as long as the intended action of the shellcode is observed during testing. This simple C program serves as a valuable tool for testing and debugging shellcode before deployment on a target system.
Creating Our First Shellcode
In this section, the goal is to manually create a shellcode that causes a thread to sleep for five seconds. To achieve this, the Sleep function from Kernel32.dll is utilized.
Finding Function Addresses
The first step involves obtaining the address of the Sleep function. This can be done using tools like Immunity Debugger or arwin. In Immunity Debugger, you can open the kernel32.dll file, search for the Sleep function, and note its address.
Using arwin, the command to find the address of the Sleep function in kernel32.dll would be:
Creating a Small ASM Code
Now that the Sleep function's address is known, a small ASM code is created to call this function. The ASM code pushes the required parameter onto the stack and calls the Sleep function using its address.
Here's an example ASM code:
The ASM code is then compiled using NASM:
After compiling, the ASM code is disassembled using objdump:
The output provides the byte shellcode on the left and the corresponding ASM code on the right. The final step involves cleaning up the shellcode by removing spaces and adding the \x
prefix.
The resulting shellcode may look like this:
To test the shellcode, a C program is created to execute it:
After compiling and running the program, if the shellcode works, the process will wait for 5 seconds and then crash. Note that the address of the Sleep function may vary between different operating systems, and if ASLR (Address Space Layout Randomization) is enabled, the address will be randomized.
More Advanced Shellcode
In this section, we're diving into more advanced shellcode that uses the ShellExecute
function to spawn a new command prompt and maximize its window.
Dealing With Parameters
The ShellExecute
function requires several parameters, and dealing with strings involves converting them into a suitable format and pushing them onto the stack. The steps include:
Calculating Hex Value and Pushing String:
Split the strings into groups of 4 characters.
Reverse the order.
Convert to ASCII.
Add PUSH bytecode.
Terminate the string.
Example:
Saving String Pointer to Registers:
Pushing Other Parameters:
Push integer value 3.
Zero out the EAX register and push it two times.
Push the strings' pointers.
Push the first parameter 0.
Example:
Finding and Pushing the Address of ShellExecuteA:
Use a tool like arwin to find the address.
Move the address to a register (EAX) and call it.
Example:
NULL-free Shellcode
In the previous chapter, a shellcode was created that spawned a command prompt, but it was not NULL-free. To make it NULL-free, manual editing or encoding and decoding techniques can be employed.
Manual Editing:
Subtract or add a specific value to remove the \x00 byte.
Example: Substracting 11111111 from 00646d63.
Example:
Encoder Tools: You can use tools like msfvenom
as encoder tools to automate the encoding and decoding process.
Shellcode and Payload Generators
Indeed, several tools can help automate the process of generating shellcode and payloads for various purposes. Here are brief descriptions of the mentioned tools:
msfvenom (Metasploit Framework)
Description: Metasploit is a widely used penetration testing framework, and
msfvenom
is a part of it. It is a powerful tool for generating various types of payloads, shellcodes, and exploits.Usage Example:
Note: You can customize the payload type, target platform, IP, and port.
The Backdoor Factory (BDF)
Description: The Backdoor Factory is a Python-based tool that allows for the automatic injection of shellcode into various file types, making them malicious. It can be used to create backdoored executables.
Usage Example:
Note: This tool can transform binaries into backdoored versions.
Description: Veil is a framework designed for generating undetectable payloads for penetration testing purposes. It focuses on evasion techniques to bypass antivirus detection.
Usage Example:
Note: Veil provides a menu-driven interface to generate different types of payloads, including shellcodes and executables.
Last updated