A C2 agent is just a delivery system. The real value comes from the tools it can deliver. In the old days, you would upload mimikatz.exe to the disk and run it. Today, that gets you caught instantly. We need to run tools in memory, leaving no trace on the hard drive.
The Power of .NET
Hackers love C# (.NET). Why? Because the Common Language Runtime (CLR)-the engine that runs C# code-is installed on every Windows machine. It gives us powerful access to the system. Tools like Seatbelt (system survey) and Rubeus (Kerberos abuse) are the gold standard.
But how do we run a C# .exe without putting it on disk?
The "Fork and Run" Pattern
We could run the tool inside our own agent process. But what if the tool crashes? Our agent dies, and we lose access. Instead, we use the Fork and Run pattern:
- Fork: Spawn a new, temporary process (a "sacrificial" process).
- Inject: Copy our tool into that process.
- Run: Execute it.
- Cleanup: When it finishes, the process dies, and the evidence vanishes.
The Challenge: PPID Spoofing & Handles
We want our sacrificial process to look normal. If malware.exe spawns notepad.exe, that looks weird. If explorer.exe spawns notepad.exe, that looks normal.
We use PPID Spoofing to lie about who the parent is. We tell Windows: "Launch this process, but pretend explorer.exe is the parent."
The "Handle Inheritance" Nightmare
This creates a big problem.
To capture the output of the tool (stdout), we normally create a "Pipe" and tell the child process to use it. This requires the child to inherit the pipe handle from us.
But when we spoof the parent, the child tries to inherit handles from the spoofed parent (explorer.exe), not us! explorer.exe doesn't know about our pipe, so the child gets nothing, and we get no output.
The Solution: The Named Pipe Redirector
We solved this with a clever two-stage injection.
Stage 1: The Redirector We created a tiny piece of shellcode that does one thing:
- Connects to a specific Named Pipe (e.g.,
\\.\pipe\C24U-1234). - Forces the current process's
stdoutto point to that pipe.
Stage 2: The Payload (Donut) We use a tool called Donut to turn our .NET tool into shellcode.
The Dance:
- Agent: Creates a Named Pipe listener.
- Agent: Spawns the sacrificial process (spoofed PPID, no handle inheritance).
- Agent: Injects Stage 1 (Redirector). It runs, connects to our pipe, and fixes the plumbing.
- Agent: Injects Stage 2 (Payload). It runs, thinks it's printing to the screen, but is actually printing to our pipe.
graph TD
Agent[Agent] -- 1. Create Pipe Listener --> Pipe[Named Pipe]
Agent -- 2. Spawn (PPID Spoofed) --> Sacrificial[Sacrificial Process]
Agent -- 3. Inject Redirector --> Sacrificial
Sacrificial -- 4. Connect Pipe --> Pipe
Agent -- 5. Inject Donut/Assembly --> Sacrificial
Sacrificial -- 6. Write Output --> Pipe
Pipe -- 7. Read Output --> Agent
This is complex engineering, but the result is beautiful: We can run any .NET tool, with a perfectly blended process tree, and still capture all the output.
In the final post, we'll look at the cutting edge of evasion: Beacon Object Files and Sleep Obfuscation.