BUILDING A C2 FRAMEWORK: ARCHITECTURE GUIDE
Design patterns for command and control infrastructure - async I/O, operator channels, and agent resilience.
Command-and-control frameworks are studied by red teams to emulate adversaries and by blue teams to detect them. This is an architecture-level look at how a resilient operator-to-agent system is structured - the design trade-offs, not an operational payload.
Three tiers, cleanly separated
Every serious framework splits into the same three layers, and the separation is what makes it maintainable:
- The agent is small, dumb, and resilient. It knows how to reach home and run a task, nothing more.
- The team server brokers state: which agents are alive, what tasks are queued, what results came back.
- The operator client is a thin UI over the server's API. Multiple operators, one shared state.
The interesting engineering is in the team server, and it is fundamentally an async I/O problem: many long-lived, mostly-idle connections.
The check-in loop
An agent's contract with the server is a poll: ask for work, do it, return the result, sleep with jitter, repeat. Jitter is what breaks the fixed-interval beacon that network defenders alert on.
import asyncio, random
async def check_in(server):
while True:
task = await server.poll() # long-poll for queued work
if task:
result = await run(task)
await server.report(result)
# jittered sleep defeats fixed-beacon detection
await asyncio.sleep(60 * random.uniform(0.5, 1.5))
That single uniform(0.5, 1.5) is the difference between a beacon that stands out in a NetFlow histogram and one that blends into noise - which is exactly the signal defenders learn to reconstruct.
Resilience is the hard part
Real deployments care less about features than about survival: redirectors so the agent never sees the real server, graceful reconnection, and profiles that shape traffic to look like ordinary HTTPS.
Detailed write-up coming soon.