Custom C2 Framework
A custom Command and Control research framework with a Python/Flask team server, cross-compiled Go agents, encrypted and authenticated tasking, pinned HTTPS, REALITY/VLESS/uTLS transport, durable result delivery, and extensive security and reliability hardening.
- Active · Phase 3
- April 11, 2026
- c2golangpythonred-teammalware-dev
- github.com/hassan-hamadi/C2-Project ↗
Phase 1 and Phase 2 are complete, with Phase 3 actively expanding the transport and verification model. For the full technical breakdown of the earlier work, read C2 Development from Scratch: Phase 1 Teardown for the original architecture and Fixing Every IOC: Phase 2 Walkthrough for the security and OPSEC hardening that followed.
Overview
This is a custom Command and Control research framework I built to understand C2 architecture at the implementation level rather than treating it as a black box.
The project uses a pull-based model with a Python/Flask team server, SQLite-backed state, a browser operator dashboard, and generated Go agents for Windows, Linux, and macOS. The server builds agents on demand with transport, timing, persistence, browser-profile, authentication, and encryption configuration compiled directly into each binary.
The application protocol is protected with AES-256-GCM regardless of transport. Each build receives its own application encryption key and identifier, while each agent generates a separate random secret during initialization that becomes bound to its identity on the server.
Three transport modes are currently supported:
- Direct HTTP
- HTTPS with SPKI certificate pinning
- REALITY with VLESS and uTLS through an external Xray edge
The REALITY path is the main Phase 3 addition. It uses a focused client implementation adapted from xray-core, a uTLS ClientHello preset, REALITY authentication, and a VLESS TCP stream carrying the framework’s existing HTTP application protocol. The project does not install or configure Xray itself.
The architecture has also grown considerably beyond transport. Recent work added durable encrypted result storage, authenticated result acknowledgements, per-installation process locking, safer file replacement, server-side dashboard sessions, stronger agent authentication, transactional cleanup, improved self-destruct reliability, and a much broader regression test suite.
Architecture
I’m still not an artist.
┌─────────────────────┐
│ Operator │
│ Dashboard │
└──────────┬──────────┘
│
Authenticated session
│
▼
┌─────────────────────┐
│ Flask Server │
│ │
│ Tasks / Results │
│ Builds / Files │
│ Agent Identity │
│ TLS Management │
└───────┬─────┬───────┘
│ │
SQLite │
│
┌────────────────────┼────────────────────┐
│ │ │
▼ ▼ ▼
Direct HTTP Pinned HTTPS REALITY + VLESS
│
▼
External Xray
│
▼
Generated Go Agent
In every transport mode, the higher-level tasking and result protocol stays the same. REALITY changes how the agent reaches Flask, not how tasks, results, or file transfers are represented inside the application.
Key Features
-
Encrypted and Authenticated Beaconing: Agents check in on a randomized jitter interval using AES-256-GCM protected application messages. Build credentials identify the generated payload while a separate per-agent secret binds an enrolled endpoint to its server-side identity.
-
Three Transport Modes: Direct HTTP for isolated labs, HTTPS with SPKI certificate pinning, or REALITY/VLESS/uTLS through an external Xray edge.
-
REALITY + VLESS + uTLS: REALITY mode uses a browser-family uTLS ClientHello preset, REALITY X25519 authentication, and a VLESS version 0 TCP stream to carry the existing HTTP protocol to Flask. The implementation is present and unit tested, while live Xray integration and packet-level browser similarity still require controlled measurement.
-
Pinned HTTPS: HTTPS builds contain the expected certificate SPKI SHA-256 pin. A mismatching certificate causes the connection to fail rather than silently falling back.
-
Cross-Platform Go Agents: Generated as standalone Go binaries for supported Windows, Linux, and macOS targets. Platform-specific persistence and cleanup behavior is selected at build time.
-
Dynamic Agent Builder: The server generates custom Go configuration and cross-compiles agents with transport settings, jitter range, persistence method, application encryption key, randomized routes, browser profile, locale, and other build-specific values.
-
Browser-Inspired Request Profiles: Five selectable Chrome, Firefox, and Safari profiles alter HTTP request metadata. REALITY mode also maps those profiles to uTLS browser families. These are static approximations rather than a claim of perfect browser reproduction.
-
Dual Execution Modes: Direct process execution is the default and avoids inserting a shell between the agent and command. Shell execution remains available when pipes, redirects, chaining, or other shell features are actually needed.
-
Stateful Task Execution: The agent tracks its working directory, supports file upload and staged downloads, and maintains task state across the normal polling workflow.
-
Durable Result Delivery: Completed output is stored locally in encrypted owner-only state before submission. Results survive ordinary restarts and remain queued until the server returns an authenticated acknowledgement bound to the exact agent, task, report, and output digest.
-
Per-Installation Process Locking: A user-scoped operating-system lock prevents two copies using the same installation state from concurrently modifying identity, pending results, or cleanup state.
-
Safer File Handling: Uploads and downloads use stronger collision handling, integrity checks, temporary-file replacement, restrictive permissions, and symlink protections where applicable.
-
Persistence Options: Windows supports a current-user Run key or Task Scheduler entry. Linux supports cron or a systemd user service. macOS persistence is not currently implemented.
-
Resumable Self-Destruct: Self-removal first removes persistence and waits for an authenticated final-result acknowledgement. Cleanup state is durable so a failed local removal can continue after restart. The server retains a hidden 24-hour tombstone to handle a lost final acknowledgement idempotently before permanently deleting the agent state.
-
Operator Authentication: Dashboard HTML is served only after server-side authentication. Browser sessions use an HTTP-only SameSite cookie, while direct API clients can continue using the operator API key.
-
Randomized Agent Endpoints: Agent-facing route paths are generated per server installation and retained in the local database so deployed agents remain compatible across restarts.
-
Local Storage Hardening: Sensitive database, certificate, build, loot, and staging paths use restricted permissions and additional checks around file replacement and deletion.
Agent Capabilities
| Capability | Status |
|---|---|
| HTTP Beaconing with Range-Based Jitter | ✅ Complete |
| AES-256-GCM Application Encryption | ✅ Complete |
| Per-Agent Authentication | ✅ Complete |
| Replay-Nonce Tracking | ✅ Complete |
| Direct HTTP Transport | ✅ Complete |
| HTTPS with SPKI Certificate Pinning | ✅ Complete |
| REALITY + VLESS + uTLS Transport | ✅ Implemented, live integration pending |
| Browser-Inspired HTTP Profiles | ✅ Complete |
| uTLS Browser-Family ClientHello Selection | ✅ Complete |
| Direct Process Execution | ✅ Complete |
| Opt-In Shell Execution | ✅ Complete |
| Stateful Working Directory | ✅ Complete |
| Authenticated File Upload | ✅ Complete |
| Agent-Bound Staged Downloads | ✅ Complete |
| Durable Encrypted Result Queue | ✅ Complete |
| Authenticated Result Acknowledgements | ✅ Complete |
| Per-Installation Process Lock | ✅ Complete |
| Windows Scheduled Task Persistence | ✅ Complete |
| Linux Systemd User Persistence | ✅ Complete |
| Registry Run Key / Cron Persistence | ✅ Complete |
| Resumable Self-Destruct | ✅ Complete |
| Dynamic Cross-Compilation | ✅ Complete |
| Server-Side Dashboard Authentication | ✅ Complete |
| macOS Persistence | 📅 Not implemented |
| Interactive Shell Sessions | 📅 Future research |
| Agent Chaining / Relay | 📅 Future research |
| Packet-Verified Browser/TLS Equivalence | 🧪 Measurement pending |
Phase 3: REALITY Transport
The largest Phase 3 change is the addition of REALITY as a third selectable transport.
Go Agent
│
│ Existing encrypted HTTP application protocol
▼
VLESS TCP stream
│
▼
REALITY-authenticated TLS connection
│
│ uTLS ClientHello preset
▼
External Xray Server
│
▼
Flask on 127.0.0.1:5000
The pieces serve different purposes:
- uTLS controls the ClientHello preset.
- REALITY authenticates the client during the TLS handshake.
- VLESS provides the TCP stream through Xray.
- Xray terminates REALITY/VLESS at the edge.
- Flask continues to process the same encrypted C2 application messages as the direct transports.
The project includes dashboard configuration, build-time validation, VLESS framing, REALITY authentication logic, certificate-path tests, HTTP transport integration, and decoy-domain certificate measurement.
What it does not currently claim is equally important: I have not yet recorded a full live agent-to-Xray-to-Flask integration test or a controlled packet capture proving that the resulting network behavior is indistinguishable from the browser profile being represented.
Those measurements are part of the remaining Phase 3 work.
Security and Reliability Work
A significant part of this project is intentionally finding weaknesses in the architecture and then revisiting them.
Some of the more substantial fixes now in place include:
- Per-agent secrets layered on top of per-build encryption keys
- Replay protection tied to the lifetime of active build credentials
- Authenticated result acknowledgements instead of trusting an HTTP success code
- Durable encrypted result state that survives normal restarts
- OS-backed locking around persistent agent state
- Transactional task dispatch and cleanup behavior
- Hidden self-destruct tombstones for lost final acknowledgements
- Safer upload collision handling and partial-write detection
- Atomic staged-file replacement
- Atomic certificate/key publication
- Server-side dashboard sessions rather than storing the API key in browser JavaScript
- Owner-only permissions for sensitive runtime state
- More accurate transport metadata and legacy-build handling
The project now has dedicated Python, Go, Node, and Chromium regression coverage for these behaviors.
Verification
The project has a much larger test surface than the original Phase 1 implementation.
Current automated coverage includes:
- Python server regression and integration tests
- Generated-agent build tests
- Local HTTP agent integration
- Local pinned-HTTPS integration and bad-pin rejection
- Go unit tests
- Go race-detector runs
- Go vet
- REALITY/VLESS framing and connection tests
- Result retry and acknowledgement tests
- Process-lock tests
- File-transfer and cleanup tests
- Node dashboard tests
- Chromium navigation and layout checks
- Windows and macOS cross-compilation checks
A large portion of the Python regression suite was created with AI assistance while auditing and iterating on the project. Many of those tests intentionally reproduce one specific bug, security condition, failure path, or regression and then lock in the expected behavior. They are especially useful as guardrails during future AI-assisted changes, but they are ordinary tests and can be run, inspected, and extended manually.
The important remaining evidence gap is REALITY itself: the implementation and local tests exist, but a live Xray deployment, version-matched packet comparison, and decoy behavior have not yet been recorded as completed experiments.
Remaining Detection Surfaces and Future Research
The framework tracks remaining observable behavior rather than treating an implemented mitigation as proof of invisibility.
| Surface | Current State | Remaining Question |
|---|---|---|
| TLS / browser fingerprint consistency | 🧪 Measurement pending | Does the REALITY/uTLS ClientHello and surrounding traffic actually match the browser profile in a controlled packet comparison? |
| Static browser profiles | ⚠️ Known limitation | How quickly do the compiled request profiles drift from current browser behavior? |
| Bounded beacon timing | ⚠️ Known limitation | Can long-term observation distinguish the configured jitter distribution from normal application traffic? |
| Process parentage | ⚠️ Known limitation | What endpoint telemetry remains when an unknown parent directly launches common utilities? |
| Windows scheduled-task telemetry | ⚠️ Known limitation | What normal Windows event and EDR telemetry remains even without schtasks.exe? |
| Linux systemd persistence | ⚠️ Known limitation | What filesystem and service-manager artifacts remain visible? |
| Windows self-removal helper | ⚠️ Known limitation | What artifacts remain during deferred executable deletion on a real Windows host? |
| macOS persistence | ❌ Not implemented | Requires a tested macOS-specific persistence path. |
| Interactive sessions | ❌ Not implemented | The current architecture is asynchronous request-response rather than TTY-oriented. |
| Agent chaining / relay | ❌ Not implemented | Agents currently require reachability to their configured Flask or Xray edge. |
| Live REALITY integration | 🧪 Measurement pending | Does the complete agent → Xray → Flask path behave as expected against a real deployment? |
| Live Windows behavior | 🧪 Partially verified | Windows code cross-compiles and has targeted tests, but still needs full execution on a Windows test host. |
The goal of this list is not to claim that every observable artifact can be eliminated. It is to keep the remaining tradeoffs explicit and measurable.
Technical Stack
- Team Server: Python 3.13+, Flask, Werkzeug, SQLite,
cryptography - Agent: Go 1.27, statically built for supported targets
- Windows Integration:
go-ole,x/sys - REALITY Transport: uTLS, X25519/HKDF-based REALITY client logic adapted from xray-core, VLESS TCP framing
- Operator Frontend: HTML5, CSS, vanilla JavaScript
- Build Pipeline: Server-side Go cross-compilation with generated source configuration
- Testing: Python
unittest, Go tests/race/vet, Node.js dashboard tests, Chromium UI checks
Source and Licensing
The project is primarily licensed under GPLv3.
The focused REALITY handshake implementation in agent/funcs/reality/reality.go is adapted from xray-core and remains subject to the Mozilla Public License 2.0. The repository includes the upstream source reference and attribution in THIRD_PARTY_NOTICES.md.