Post

Dynamic HTTP(S) Payload Stager

A dynamic HTTP/s Stager that automates updating decryption variables, saving time and effort in managing shellcode loaders.

Table of Contents

  1. Introduction
  2. File Format and Python Script
  3. Dynamic HTTP(S) Stager Code
  4. Enhancing the Stager’s Flexibility
    1. Generating Dynamic, Single-Use URLs
    2. Storing Multiple Domains in Arrays and Obfuscating with IPv4Fuscation
  5. Conclusion

Introduction

While experimenting with different C2 frameworks, I found myself needing to build a new shellcode loader every time I encrypted a new payload to update the decryption variables, such as the decryption key. This quickly became cumbersome, particularly because the shellcode loader took time to build, and then I had to send the updated loader to the victim’s PC.

To avoid the hassle of regenerating shellcode loaders for every new encrypted payload, I developed an HTTP Stager that offers a more practical solution.

A Python script converts the necessary variables into a specific format, encodes them in Base64, and saves them to a file. Upon downloading this file, the HTTP Stager decodes the Base64 content, converts the variables to hexadecimal format, and assigns them to the appropriate decryption variables.

File Format and Python Script

The text file containing these variables must adhere to a specific format to ensure compatibility with the stager:

1
2
# Format
<variable name>-<hexadecimal code>

To simplify converting variables generated by WafflesCrypt into the required format, I created a Python script that handles this conversion. By default, the delimiter is set to -, but this can be customized as needed.

You can view the Python script here: ConvertToFormat.py.

After generating the file, host it on a web server. For quick hosting, use the built-in Python HTTP server with the command:

1
python -m http.server 8080

Alternatively, you can use my enhanced version of the http.server module, httpserver-plus, which offers additional features like HTTPS support and customizable route handling for redirection.

Dynamic HTTP(S) Stager Code

To use the HTTP(S) Stager, you only need to configure three parameters:

  • The number of variables
  • The URL to the hosted file
  • The delimiter used in the Python script

You can view the Stager code here: Dynamic_HTTP_Payload_Stager.cpp.

Here’s a video demo showing the Payload stager in action:

Enhancing the Stager’s Flexibility

The current HTTP Stager relies on a specific URL. If this URL or domain is blocked by defensive measures, the payload will cease to function.

To mitigate this, I thought of two potential solutions:

  1. Generating Dynamic, Single-Use URLs
  2. Storing Multiple Domains in Arrays and Obfuscating with IPv4Fuscation

These solutions are also effective for C2 callbacks when designing implants.

Generating Dynamic, Single-Use URLs

Creating dynamic, single-use URLs makes it more difficult for defenders to detect, block, or reuse URLs.

Here are some techniques to generate unique, one-time URLs:

  1. Time-Based URL Generation:
    • Use the current timestamp and a secret key to generate a URL valid only for a short period.
    • The URL could look like: http://example.com/file/1686584376/ABcdEF12…
  2. Token-Based URL with Expiry:
    • Generate a unique token for each request, encoding a random key, session ID, and expiration time.
    • The URL could look like: http://example.com/file?token=YXNkZmFzZGZhc2RmYXM…
  3. Mathematical Pattern Generation:
    • Utilize a mathematical pattern to create a predictable but hard-to-reverse sequence.
  4. Server-Side Session Tracking:
    • Use a server-side session or database to manage URL validity, mapping each unique URL to an expiration time and client ID.
  5. Hash Chaining or Rolling Hashes:
    • Employ a rolling hash or hash chaining to generate evolving, unique URLs for each session.

Storing Multiple Domains in Arrays and Obfuscating with IPv4Fuscation

Instead of hardcoding a single domain or IP address, you can store multiple potential domains or IP addresses in an array:

1
2
3
4
5
const char* domains[] = {
    "http://example1.com",
    "http://example2.net",
    "http://example3.org",
};

Additionally, you can use IPv4/IPv6 obfuscation methods, as demonstrated in my Waffles Crypt post, to make these addresses harder to detect during static analysis.

For example, converting http://example1.com to hexadecimal yields: 68 74 74 70 3A 2F 2F 65 78 61 6D 70 6C 65 31 2E 63 6F 6D.

This hexadecimal representation can then be converted to an IP address:

1
2
3
4
5
6
7
const char* domains[] = {
    "104.116.116.112",
    "58.47.47.101",
    "120.97.109.112",
    "108.101.49.46",
    "0.99.111.109"
};

Conclusion

This HTTP Stager streamlines the process of managing encrypted payloads by eliminating the need to constantly regenerate shellcode loaders.

While this method can significantly reduce time and effort, it’s important to note that it remains a proof of concept (PoC). From an operational security (OPSEC) standpoint, leaving decryption variables in plaintext isn’t ideal. A better approach might involve using generic variable names, like a, b, c, and d, since the actual names are irrelevant to the decryption process itself and are only placeholders for the values in arrays.

I hope this post has sparked new ideas or provided valuable insights. I’d love to hear your thoughts, suggestions, or any improvements you might have! Feel free to share them in the comments or reach out to me directly.

Happy hacking! :)

This post is licensed under CC BY 4.0 by the author.