2025-12-04

Evasive C2: Talking to our agent

C2NetworkingDNS TunnelingSOCKS5

In the previous post, we looked at the high-level architecture of C24U. Today, we're going to dive deep into the Communication Layer. If the "Agent" is the spy behind enemy lines, the "Transport" is the method they use to send reports back to headquarters.

If a spy always used the same radio frequency, they'd be caught immediately. Similarly, if a malware agent only speaks one protocol, it's easy to block. This brings us to our first core concept: Modularity.

The Chameleon Approach: The Transport Factory

When building software, especially malware, you want to decouple what you are doing (sending data) from how you are doing it (HTTP, DNS, SMB).

We implemented a Transport Factory Pattern. Imagine a vending machine. You ask for "HTTP", and it gives you an object that knows how to talk HTTP. You ask for "DNS", and it gives you a DNS talker. The rest of the agent doesn't care; it just calls Send().

// The Interface (The Contract)
class Transport {
public:
    virtual bool Connect() = 0;
    virtual bool Send(const std::string& data, std::string& response) = 0;
    virtual void Close() = 0;
};

This abstraction is powerful. It means we can add a new protocol (say, Gmail API or Slack Webhooks) next week without rewriting a single line of the core agent logic.

HTTP/S: Hiding in Plain Sight

The most common C2 channel is HTTP(S). Why? Because everyone allows web traffic. A corporate firewall might block port 6667 (IRC) or 22 (SSH), but it almost never blocks port 443 (HTTPS).

The WinINet Advantage

In Windows C++, you have two main ways to do networking:

  1. Winsock: The raw sockets API. This is like building a car from parts. You have total control, but you have to handle everything yourself.
  2. WinINet: The high-level Internet API. This is like taking a taxi.

We chose WinINet. Here's the critical reason: Corporate Proxies. In a big company, you can't just connect to google.com. You have to go through a "Proxy Server" that inspects traffic. If you use Winsock, your connection fails because you didn't ask the proxy nicely. WinINet, however, is part of the OS. It automatically checks the user's registry settings, finds the corporate proxy, and-crucially-authenticates using the logged-in user's credentials (NTLM/Kerberos). This allows our agent to "ride" the legitimate user's session out to the internet.

DNS: The Tunnel of Last Resort

Sometimes, the security team is good. They block all unknown web traffic. But they almost never block DNS. Why? Because if you block DNS, the internet breaks. You can't resolve google.com to an IP address.

We can exploit this trust using DNS Tunneling.

How it Works

DNS is designed to ask "What is the IP of X?". It's not designed to carry files. But we can force it to.

The Concept:

  1. Agent wants to send "SECRET".
  2. Agent encodes "SECRET" into a domain name: SECRET.evil.com.
  3. Agent asks the DNS Server: "What is the IP of SECRET.evil.com?"
  4. DNS Server (controlled by us) sees the query. It logs "SECRET".
  5. DNS Server responds with a TXT record: "CMD: WHOAMI".

The Engineering Challenges

DNS is a hostile environment for data:

  1. Size Limits: A UDP DNS packet is tiny (~512 bytes). If we want to download a 1MB file, we have to chop it into thousands of tiny chunks.
  2. Character Limits: You can't use / or + in a domain name. Standard Base64 encoding breaks.
    • Solution: We wrote a custom "DNS-Safe" Base64 encoder that maps + to - and / to . (using the dot as a separator!).
  3. Statelessness: UDP is "fire and forget". Packets arrive out of order or get lost. Our server has to track every chunk: "I have chunk 1 and 3, but I'm missing 2."
graph LR
    Agent -->|Query: data.1.3.id.com| DNS_Server
    Agent -->|Query: data.2.3.id.com| DNS_Server
    Agent -->|Query: data.3.3.id.com| DNS_Server
    DNS_Server -->|Reassemble| C2_Logic
    C2_Logic -->|TXT Record| Agent

SOCKS5: Tunneling the World

The "Holy Grail" of C2 is a SOCKS proxy. This turns your agent into a VPN. You can run tools on your attacker machine (like nmap or Firefox), and the traffic comes out of the victim machine.

The Protocol Mismatch

This was the hardest feature to build.

  • SOCKS is a Stream protocol. It expects a continuous flow of bytes (TCP).
  • C2 is a Polling protocol. The agent checks in every 5 seconds.

How do you push a stream over a pulse? Buffering.

  1. The Buffer: The agent maintains a list of open TCP connections to internal targets (e.g., the Intranet portal).
  2. The Poll: When the agent checks in, it reads all available data from all open sockets. It bundles this into one big blob.
  3. The Burst: It sends this blob to the server.
  4. The Server: Unpacks the blob and feeds it to your nmap instance.

It feels laggy-like playing a game with 5000ms ping-but it works. It allows you to browse the internal intranet from the comfort of your command server.

In the next post, we'll leave the network layer and dive into the System Internals, exploring how we trick the Windows Kernel itself.