A Python-based implementation of a secure client-server (C2) architecture using Transport Layer Security (TLS).
For educational purposes only. Use only on systems you own or have explicit permission to test.
- End-to-end TLS 1.2+ encryption using Python's
sslmodule - Protobuf binary protocol with zlib compression on the wire
- Mutual TLS (mTLS) support — optional client certificate auth
- Auth token validation on every connection
- Async server built on
asyncio— handles many clients concurrently - Auto-heartbeat — server pings clients every 30s, drops unresponsive ones
- Exponential backoff reconnect on the client side
- File transfer — upload and download files over the TLS tunnel
- Screenshot capture — grab the client screen as PNG
- Remote shell — run any command on the connected client
- Client groups — tag clients and send commands to a whole group
- Message routing — broadcast to all, or target a specific group
- Web dashboard — live client list at
http://localhost:8080 - Config files —
config.yamlfor server,client_config.yamlfor client - Portmap.io tunnel — expose server globally without port forwarding
- PyInstaller packaging — build a standalone
tls_client.exe - Docker deploy —
docker-compose upto run server in the cloud
├── server.py # Async TLS C2 server
├── client.py # TLS agent / client
├── protocol.py # Protobuf + zlib framing layer
├── tunnel.py # Portmap.io SSH reverse tunnel
├── config_loader.py # YAML config loader
├── config.yaml # Server configuration
├── client_config.yaml # Client configuration
├── gen_certs.py # Generate CA + server + client certs
├── messages.proto # Protobuf schema
├── messages_pb2.py # Compiled protobuf (auto-generated)
├── build_client.spec # PyInstaller spec for client exe
├── Dockerfile # Docker image for server
├── docker-compose.yml # Docker Compose for cloud deploy
├── setup.bat # Windows quick-install script
└── requirements.txt # Python dependencies
# Windows
setup.bat
# Linux / macOS
pip install -r requirements.txtpython -m grpc_tools.protoc -I. --python_out=. messages.protopython gen_certs.pyThis creates ca.crt, server.crt/key, client.crt/key in the current directory.
Never commit .key or .pem files.
python server.pypython client.pyOnce running, the server exposes an interactive CLI:
| Command | Description |
|---|---|
clients |
List all connected clients |
groups |
List clients grouped by tag |
use <id> |
Select a client by ID or UUID prefix |
ping |
Ping the selected client |
info |
Get OS, TLS version, cipher, PID |
exec <cmd> |
Run a shell command on the client |
file_get <remote> [local] |
Download a file from the client |
file_put <local> <remote> |
Upload a file to the client |
screenshot [out.png] |
Capture a screenshot |
echo <text> |
Echo text back |
queue |
Show pending command queue |
broadcast <msg> |
Send to all connected clients |
groupsend <group> <msg> |
Send to a specific group |
drop |
Disconnect the selected client |
exit |
Shut down the server |
Visit http://127.0.0.1:8080 while the server is running.
Auto-refreshes every 5 seconds showing all connected clients, their groups, hostnames, and TLS info.
Key settings:
server:
host: "127.0.0.1"
port: 6767
auth:
token: "changeme-token-1234" # clients must match this
heartbeat:
interval: 30 # seconds between pings
timeout: 10 # drop client if no pong within this
tunnel:
enabled: false # set true to expose via Portmap.ioserver:
host: "127.0.0.1"
port: 6767
client:
group: "default" # tag this client for group commands# Server
python server.py --require-client-cert
# Client
python client.py --use-client-certExpose the server to the internet without touching your router:
- Sign up at portmap.io → create a configuration → Type: SSH
- Download the
.pemkey file → save to~/.ssh/ - On Linux/macOS:
chmod 600 ~/.ssh/<n>.first - Update
config.yaml:
tunnel:
enabled: true
key_file: "~/.ssh/<n>.first"
username: "<n>.first"
remote_host: "<n>-<port>.portmap.host"
remote_port: <assigned-port>
local_port: 6767- Update
client_config.yamlon the remote machine:
server:
host: "<n>-<port>.portmap.host"
port: <assigned-port>
server_name: "localhost"pip install pyinstaller
pyinstaller build_client.spec
# Output: dist/tls_client.exeThe exe is fully standalone — no Python needed on the target machine.
# Docker
docker build -t tls-server .
docker run -p 6767:6767 -p 8080:8080 tls-server
# Docker Compose
AUTH_TOKEN=mysecrettoken docker-compose up -d- Certificates are self-signed and intended for lab/demo use
- Change
auth.tokenin both config files before any real use - Never commit
.key,.pem, or.crtfiles —.gitignorealready handles this
MIT