Shellcode

[-] What is Position Independent Code (Shellcode)?

Position Independent Code is code that is designed to execute regardless of where it resides in memory. This is in contrast to most programs, which might need to be loaded at a specific address to function correctly. Shellcode is a type of PIC, often written for exploits and payloads in hacking.

TLDR: Basically we're going to allocate memory with VirtualAlloc, copy the shellcode to that memory and then execute it. And we're treating the blob of PIC (shellcode) code as a function we can call, just like any other function in our program.

Screenshot

The term “Shellcode” originally referred to code that, when executed, would spawn a command shell — hence the name. However, today, it generally refers to any payload used for exploitation.

The advantages of a dll are:

  • structured (exported functions, resources, etc...)
  • you are contained by the PE format (sections, imports, etc...), which has advantages and disadvantages
  • when writing code, upon compilation the compiler will take care of a lot of things for you (linking of imports, relocations, etc...)

The disadvantages of PIC are:

  • no imported functions from DLL's (no LoadLibrary/GetProcAddress)
  • harder to write and debug
  • full control over what the code does (good and bad)
  • smaller size (good for exploits)
  • no PE format (harder to analyze for defenders)
  • no static analysis (harder to analyze for defenders)
  • no compiler (you have to write everything yourself, no linking, no relocations, etc...)
    • no structure (you have to define your own structure, if any)

[-] Uses of Shellcode:

Exploitation: The primary use of shellcode is to exploit vulnerabilities in software, where the attacker can inject and execute their code. Payloads: Once a vulnerability is exploited, shellcode can be used to deliver payloads, which can range from spawning a reverse shell to injecting ransomware or establishing persistence. Bypassing Restrictions: Shellcode can be crafted to bypass security mechanisms, making detection and mitigation difficult.

[-] Shellcode vs. Compiled Code vs. Interpreted Code:

Shellcode: As mentioned, shellcode is position-independent, designed to run from any location in memory. It doesn’t rely on external libraries or functions and should be small and efficient to work within the constraints of an exploit.

Compiled Code: This is code written in languages like C or C++ that is then compiled into machine code by a compiler. The result is a binary executable that the system can run. Unlike shellcode, compiled programs often rely on fixed memory addresses and external libraries.

Interpreted Code: This is code written in languages like Python, Ruby, or JavaScript that is executed line-by-line by an interpreter. It’s not converted into machine code; instead, the interpreter reads and executes it directly. This makes it generally slower than compiled code, but it’s more flexible and platform-independent.

[-] Staged vs. Stageless Shellcode:

Staged (dis)advantages (remotely fetch payload/shellcode)

  • Swap out shellcodes easily (not hardcoded in the loader)
  • No malicious code in the loader binary
  • control access on who can download the shellcode (i.e. IP Filtering)
  • control over the format - mimicking benign web downloads (i.e. json, xml)
  • Behavioral detections might trigger on staging activity (network connections, etc...)
  • Extra step that might fail (network issues, firewall, etc...)
  • First perform recon/ anti-sandboxing checks before fetching the payload

Stageless (dis)advantages (all-in-one shellcode)

  • No network connection needed to fetch the payload
  • Faster execution (no need to wait for network)
  • Less chance of network detection (no outbound connections)
  • Simpler deployment (single payload)
  • More entropy due to larger size, big chunk being shellcode which is more random than a PE file
  • Harder to swap out payload (need to recompile the loader)
  • .Net only has 2 sections .text and .rsrc - making it less suspicious compared to a PE with multiple sections (c/c++)
  • Running high risk tasks such as touching lsass can result in your beacon being killed