C2 Command & Control Framework
Overview
This is a pet project designed for learning and experimentation with Command & Control (C2) frameworks. But I'm not excluding the possibility of truning it into a full-scale usabe C2 for my future Penetration Testing experience. It features a secure C2 server written in Go and a Windows-based agent written in C. The project focuses on encrypted communication, implant management, task execution, data exfiltration and overall stealthy operations.
⚠️ Disclaimer: This project is for educational purposes only. Unauthorized deployment or usage is strictly prohibited.
Current Features
🔹 Server & Client (Go)
- Secure communication using mTLS
- Authentication
- Agent management
- Task management
- Tab-completion
- Dynamic implant generation
- Modules loading
- HTTPS listener and traffic shaping
🔹 Agent (C) Stage 1
- Small footprint because implant is written in C
- Covert HTTPS communication channel with round robin logic and traffic shaping
- Task execution:
- CMD and Powershell execution
- Adjustable connection interval, jitter, start-up delay
- Download files/directories from target, upload files to target
- File system navigation
- System information collection
- Process list retrieval
- Injection techniques:
- Self injection with in-memory shellcode decryption
- Inject into remote process
- Spawn a new process with custom ppid (aka process hollowing)
- Keylogger
- Auto persistence
- SOCKS5 proxy to tunnel traffic through target
- Cleanup and self deletion
Setup
🔹 Server & Client (Tested on Kali, Debian and Ubuntu)
Quickstart for testing. These will start server and client on localhost in developer mode. To see all options use -h flag.
- Install dependencies:
sudo apt install golang mingw-w64 make xxd openssl - Generate TLS certificates using provided script:
bash generate_certs.sh - Start server on localhost
bash start_server.sh - Start operator console:
bash start_client.sh
🔹 Payload Generation
-
Create a listener:
listen -t https -h domain1.com,domain2.com -p 8443 -n test_listener1 -
Generate the agent payload:
generate agent <listener_name> [flags]- Replace
<listener_name>with the desired listener (tab completed). - Some optional flags:
--intervalSet interval between connections in seconds (default 10)--jitterSet jitter for reconnection interval--delaySet startup delay--persistence- Enable persistence capability.--keylogger- Enable keylogger capability.--proxy- Enable socks5 proxy capability.
- Replace
-
The implant will be saved to the "./agent/bin" folder.
To-Do List
🛠 Planned Improvements
- Canceled
Beacon with VM detection Basic tasks execution (cmd, powershell, sleep, load dll/shellcode, cleanup)Context switching in terminalFile download/uploadShellcode in-memory decryption and delay before executionSOCK5 proxy on infected machinesBeacon: rewrite to CHTTPS listener with profilesFile system navigationHTTP communication channel for agentHTTP profiles loadingPE and .NET loader- Implement staging logic for agent
- Encrypted local storage (agent's DB, etc.)
- Sleep obfuscation and memory encryption during sleep
- One line web-delivery
- VBS macro stager
- Agent: buffering, shutdown detection and manual reporting for keylogger
- Canceled
Covert DNS communication channel - Installation script
- Detailed documentation with nice screenshots
- Docker image
- GUI
License
📜 All Rights Reserved
This project is proprietary and confidential. Unauthorized copying, distribution, modification, or public sharing of this codebase is strictly prohibited.
⚠️ Usage is permitted only for personal learning and experimentation. Redistribution or commercial use is forbidden.
Changelog
📌 Latest Version: v0.6.0 — 18-08-2025
v0.6.0
This update is pretty big and contains some radical changes in project.
- SSL, TCP and DNS communication channels have been striped and only HTTPS is left. The reason is simple - the communication architecture was not thought out from the start, and was adjusted on the fly every time any new communication-related feature was added with long and painful debugging sessions. I decided to stick with HTTPS as it may cover 99% of all engagements needs' and allows to maintain cover during operations.
- HTTPS traffic shaping is introduced via YAML config file. it allows to specify domains hosted, their respective certificate paths, content paths and headers/cookies for identifying agent and exchanging messages with server. Client that are not identified as C2 agents - are served usual web content.
- C2 communication inside of HTTPS is encrypted (not by encapsulating HTTPS protocol, but by itself and look like bening cookie strings). Currently encryption is done with hardcoded key. In next updates I will implement dynamic session key generation.
- Three injection techniques have been tested and seem to work well. Output capturing has been implemented with named piped, so currently it only captures output from specifically crafted modules.
- For every injection command you can now specify --donut flag with following after it donut arguments. This way you can directly inject .EXE .DDL and .NET stuff :)
- Beacon, beacon, beacon... was removed as I was fully rethinking it's purpose and understood it brings nothing to operations. It will replaced with stager or some kind of very stealthy long-haul implant or fall-back option for maintaining foothold on the target system.
- Talking about stagers - stager prototype is already in repository. It works but is not yet fully integrated into server. Plans are to add sandbox detection to it and maybe even persistence. Again I'm still building the concept of this C2 server in my head and many things can change in future.
- A lot of source files restructuring and code cleanup has been done. PS. An interesting idea for using named pipes is hatching in my head... but I will share it later.
v0.5.1
- HTTPS communication channel was implemented for agent. Uploading files to server is not yet supported, but will be in nearest future.
- Agent and server files have been restrucutred for convenience. Agent source files have also been split for convenience and readability.
- Operator's terminal was enchanced to better display output. Also, some comands were renamed to be more intuitive and some errors have been fixed, which led to terminal's panic. Command parses has also been enchanced to not mismatch commands and handle them strictly. Command 'tasks' now work in both general and agent contexts.
- Filepath handling was fixed in 'download', 'upload' and 'spawn' commands. Now filepaths with spaces are handled correctly.
- WolfSSL was ditched, as it is not really necessary anymore.
Next areas of my focus are:
- Rewrite command sending logic to use TLV approach or some custom protocol, because sending just plain strings is not opsec (even inside of SSL) and not very extensible.
- Implement HTTPS profiles to mimic legitimate traffic.
- After that I will start adding more post-exploitation modules.
- Also, I'm rethinking the purpose of beacon. Maybe I will rewrite it into more of a stager or reconn implant.
v0.5.0
The moment You all've been waiting for I was delaying for two monthes already!
- Beacon in GO got fully replaced with Beacon written in C. Old beacon files removed.
- Added HTTP listener to server and HTTP communication channel to beacon. This was actually pretty hard for me to implement. I learned more about interfaces and abstractions in C - that's basically how I was able to add a request-response HTTP protocol to my transport abstraction, which was initially created for stream-based protocols.
- Changed project folder structure a bit. And will continue doing so, untill my internal perfectionist is satisfied.
- Small fixes like: task result parsing and reporting, cosmetic adjustments, taskID fixes, pid and ppid fixes in injection logic,
- A lot of new ideas have came to my mind since last version. I have a working prototype of DLL unhooking and API hashing, so there is a possibility of adding those soon. But, of course, first I need to polish HTTP listener's profiles logic.
v0.4.3
- Added size optimization flags to payload generator
- Fixed preprocessor macros for transport selection
- Https implants now send all messages via GET and big messages via POST
- Move target cookies and headers inside of domain profiles
- Added task ID reporting by client, which helps identify operator who issued command. In next version task result will be reported selectively to operator who sent command
v0.4.2
- Added https listener prototype to server
v0.4.1
- New beacon now supports Win Schannel TLS only (no wolfssl)
- Flag --devel now skip mTLS
v0.4.0
- Added Windows Schannel TLS transport, no more overhead caused by Wolfss. However, you can still use Wolfssl.
- Fixed flags and macros from testing build
- Prototyped https listener. Currently working on it.
v0.3.2
- Fixed injection logic for new beacon
- Added new beacon to repo
v0.3.1
- Sysinfo command now follows new task result sending logic.
- Fixed keylogger and persistence commands by passing a dummy buffer.
v0.3.0
- Refactored task result sending logic. Now it's cleaner and more flexible.
- Fixed proxy bug which prevented it from stopping after stop command received.
v0.2.2
- No hardcoded keys - one-time ecnryption key generation and transfer to agents. Key are cleared after use. Makes it harder to catch shellcode.
v0.2.1
- Added missing header files to get rid of compiler warnings
- Added compile flags to Makefile
v0.2.0
- Removed unnecessary WSACleanUp, which prevented agent from reconnection after server went offline and back online.
- Rewrote some blocks to use sync.Map instead of mutex.
- Added PID and process name retrieving for "ps" command.
- Added nice output for "ps" command and it is now handled separately, like sysinfo and keylogger.
- Devel mode: if message is bigger than 512 chars, console will print only 512 chars. Laying the foundation for new task-result logic in future:
- Task handler: now generates task id for every task.
- Task handler: does not delete task after sending to agent, but just marks it as dispatched.
- Task handler: operator conn and ID retrieval by task id.
v0.1.0
- Decided to keep track of changes
- Added "inject" command to write shellcode into process by PID
- Added "spawn" command to start new suspended process and write shellcode into it. Optional: specify PPID.
- Modulesa are now not hardcoded, but loaded dynamically from folder.
- Shellcode is encrypted before task handler, decrypted right before writing to memory and cleared right after it. TODO:
- Persistence and staging mechanism for new beacon.
- Self injection for new beacon