Kit de herramientas de detección y confirmación de RCE que prueba URLs o solicitudes HTTP capturadas en busca de inyección de comandos, SSTI, rutas ciegas y OOB, devolviendo veredictos por niveles con pruebas.
confirmed significa que el objetivo ejecutó la entrada. negative significa que las sondas lo alcanzaron.
Versión 2.40.0 · MIT · Python 3.8+ · cero dependencias de terceros
RCEKit es un kit de detección y confirmación de RCE para pruebas de penetración autorizadas, red teaming e investigación de seguridad. Apúntalo a un objetivo que tengas permitido probar — una URL o una solicitud HTTP capturada — y cada hallazgo regresa con el nivel que se ganó.
Cada confirmed se apoya en un valor que RCEKit generó aleatoriamente para esa
sonda y que la reflexión no puede producir: un resultado calculado presente en la
respuesta y ausente en un control sin payload, o un callback fuera de banda que
porta un token que solo el objetivo llegó a tener. Las señales más débiles
conservan sus propios niveles y nunca se promueven a este. Y una ejecución que no
pudo probar algo nunca lo reporta como limpio.
RCEKit confirma RCE mediante múltiples métodos bajo una sola CLI. A continuación se apunta a CVE reales y documentados públicamente en software de producción — cada veredicto diferenciado contra un control sin payload:
| Clase de RCE | --methods | Objetivo del mundo real | Veredicto |
|---|
| Inyección de comandos del SO (basada en resultados) | reflected | Webmin 1.910 — CVE-2019-15107 | confirmed |
| Inyección de expresiones (OGNL) | eval | Apache Struts2 — S2-001 | confirmed |
| Búsqueda de expresiones (Log4Shell/JNDI) | lookup | Apache Solr 8.11.0 (Log4j 2.14.1) — CVE-2021-44228 | lookup-sink |
| Inyección de comandos ciega (sin salida) | time | Webmin 1.910 — CVE-2019-15107 | needs-review |
Cada fila es reproducida por tests/bench/, que ejecuta RCEKit
contra estas compilaciones bajo Docker y verifica el veredicto y su control
negativo. Última ejecución en verde en la 2.36.0 (2026-09-20): 3/3 casos. Esa
es una afirmación puntual en el tiempo, no continua -- el benchmark se ejecuta con
una cadencia, no en cada cambio.
Cada control es la prueba real de la fila. Struts2 sondeado con reflected
regresa negative, porque S2-001 reevalúa OGNL y no hay un shell detrás de él.
La señal time de Webmin se mantiene en needs-review sobre un objetivo donde
resulta ser correcta. Y Solr sondeado con oob regresa negative aunque es
explotable -- oob construye comandos de shell y un sink ${jndi:...} no
ejecuta ninguno de ellos, que es la brecha que lookup existe para cerrar, medida
en lugar de afirmada.
La fila de Log4Shell dice lookup-sink, no confirmed: lo que el callback prueba
es que el sink resolvió una URI que RCEKit eligió. Alcanzar RCE requiere un
servidor que responda a la búsqueda con una clase cargable, y en el nivel de
riesgo predeterminado solo sale jndi:dns:// -- una búsqueda de nombre, sin
conexión más allá de ella para que tal servidor responda.
reflected — inyección de comandos del SO, Webmin CVE-2019-15107 → confirmed
eval — inyección de expresiones OGNL, Apache Struts2 S2-001 → confirmed
lookup-sink
time — inyección de comandos ciega, Webmin CVE-2019-15107 → needs-review
RCEKit tiene dos formas soportadas, y ninguna es un respaldo de la otra.
Instálalo — pipx mantiene la CLI en su propio entorno, que es lo que
quieres para una herramienta en lugar de una biblioteca:```bash
pipx install rcekit # or: pip install rcekit
rcekit --doctor # confirms the corpus it will run with
**O simplemente toma el único archivo.** El corpus de payloads está integrado en el módulo, por lo que
`rcekit.py` se ejecuta por sí solo sin nada más — sin paso de instalación, sin
site-packages, nada que dejar atrás. En un jump box de cliente, un host
air-gapped, o en cualquier lugar donde `pip install` no sea una opción:```bash
curl -O https://raw.githubusercontent.com/kabiri-labs/rcekit/main/rcekit.py
python rcekit.py --doctor # same corpus, same check, zero installation
Ambos ejecutan el mismo código y reportan los mismos veredictos. Trabajar desde un checkout es la tercera forma, y tampoco requiere instalación:```bash git clone https://github.com/kabiri-labs/rcekit.git cd rcekit # Python 3.8+, standard library only
Coloca un marcador `FUZZ` donde llegue tu entrada (o selecciona un parámetro con `-p` cuando
uses una solicitud capturada), y pídele a RCEKit que demuestre RCE:```bash
rcekit --acknowledge-consent \
--verify-url "https://target.example/lookup?host=FUZZ" \
--methods reflected,eval
| -t | --target | Target URL to scan |
| -l | --list | File containing a list of URLs to scan |
| -o | --output | Output file to save the results |
| -f | --format | Output format (json, html, csv) |
| -c | --config | Path to the configuration file |
| -v | --verbose | Enable verbose output |
| -s | --silent | Silent mode, only show results |
| -h | --help | Show help message and exit |
# Scan a single target
python3 vulnscan.py -t https://example.com
# Scan multiple targets from a file
python3 vulnscan.py -l targets.txt
# Save results in JSON format
python3 vulnscan.py -t https://example.com -o results.json -f json
# Use a custom configuration file
python3 vulnscan.py -t https://example.com -c config.yaml
# Enable verbose output
python3 vulnscan.py -t https://example.com -v
The tool uses a YAML configuration file to define scan parameters. Below is an example configuration:
# Scan settings
scan:
timeout: 30
threads: 10
user_agent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
# Modules to enable
modules:
- sqli
- xss
- lfi
- rfi
- ssrf
# Authentication settings
auth:
enabled: false
username: ""
password: ""
# Proxy settings
proxy:
enabled: false
http: "http://127.0.0.1:8080"
https: "https://127.0.0.1:8080"
Detects SQL injection vulnerabilities by injecting payloads into parameters and analyzing responses.
Identifies reflected and stored XSS vulnerabilities in web applications.
Tests for local file inclusion vulnerabilities that could allow attackers to read sensitive files.
Checks for remote file inclusion vulnerabilities that could lead to remote code execution.
Detects SSRF vulnerabilities that could allow attackers to access internal resources.
The tool supports multiple output formats:
This tool is intended for authorized security testing only. The authors are not responsible for any misuse or damage caused by this program. Always obtain proper authorization before testing any system.``` [detect] methods: reflected, eval [detect] sent 13 probes: confirmed=4, negative=9
[detect] CONFIRMED execution (4): [reflected/unix/raw] ; echo RKYZRIP$((540141+314681))RKFWVFS$(echo RKBWOOC)RKYZRIP (target computed 'RKYZRIP854822RKFWVFSRKBWOOCRKYZRIP' — random operands, absent from control)
### Desde una solicitud capturada — la forma que tienen la mayoría de los objetivos reales
Un `--verify-url` transporta una URL y nada más. La mayoría de los sinks que vale la pena probar se encuentran detrás de un POST con una cookie de sesión, un tipo de contenido y un cuerpo, y RCEKit toma esa solicitud completa: guárdala desde tu proxy o las devtools de tu navegador y nombra el campo en el que inyectar.```bash
rcekit --acknowledge-consent \
-r search.req -p q \
--methods reflected,eval
| -s | --server | SERVER | http://localhost:8080 | URL del servidor de escaneo |
| -t | --token | TOKEN | null | Token de autenticación de la API |
| -o | --output | OUTPUT | null | Ruta del archivo de salida |
| -f | --format | FORMAT | json | Formato de salida (json, csv, sarif) |
| -v | --verbose | | false | Habilitar registro detallado |
| -q | --quiet | | false | Modo silencioso (sin salida) |
| --timeout | | TIMEOUT | 30 | Tiempo de espera de la solicitud en segundos |
| --retries | | RETRIES | 3 | Número de reintentos de la solicitud |
| --insecure | | | false | Omitir la verificación del certificado TLS |
| --proxy | | PROXY | null | URL del proxy |
| --config | | CONFIG | null | Ruta del archivo de configuración |
| --no-color | | | false | Deshabilitar la salida en color |
| --debug | | | false | Habilitar la salida de depuración |
# Escanear un solo objetivo
scanner scan --target https://example.com
# Escanear múltiples objetivos desde un archivo
scanner scan --targets-file targets.txt
# Escanear con formato de salida específico
scanner scan --target https://example.com --format sarif --output results.sarif
# Escanear con autenticación
scanner scan --target https://example.com --token YOUR_API_TOKEN
# Escanear con proxy
scanner scan --target https://example.com --proxy http://proxy.example.com:8080
# Escanear con configuración personalizada
scanner scan --target https://example.com --config custom-config.yaml
El escáner admite un archivo de configuración en formato YAML:
# scanner-config.yaml
server: http://localhost:8080
token: YOUR_API_TOKEN
timeout: 30
retries: 3
insecure: false
proxy: null
output: results.json
format: json
verbose: false
quiet: false
no_color: false
debug: false
# Clonar el repositorio
git clone https://github.com/example/scanner.git
cd scanner
# Compilar el binario
make build
# O compilar directamente con Go
go build -o scanner ./cmd/scanner
# Ejecutar pruebas
make test
# Ejecutar linter
make lint
scanner/
├── cmd/
│ └── scanner/
│ └── main.go
├── internal/
│ ├── api/
│ ├── config/
│ ├── scanner/
│ └── utils/
├── pkg/
│ └── models/
├── docs/
├── examples/
├── scripts/
├── Makefile
├── go.mod
├── go.sum
└── README.md
# Ejecutar todas las pruebas
make test
# Ejecutar pruebas con cobertura
make test-coverage
# Ejecutar pruebas de un paquete específico
go test ./internal/scanner/...
# Ejecutar pruebas con salida detallada
go test -v ./...
git checkout -b feature/amazing-feature)git commit -m 'Add some amazing feature')git push origin feature/amazing-feature)make lint y make test antes de enviarEste proyecto está licenciado bajo la Licencia MIT - consulte el archivo LICENSE para más detalles.
Esta herramienta está destinada únicamente a fines de pruebas de seguridad autorizadas. Los usuarios son responsables de cumplir con todas las leyes y regulaciones aplicables. Los autores no se hacen responsables del uso indebido o daños causados por esta herramienta.``` [detect] sent 4 probes: confirmed=3, negative=1
[detect] CONFIRMED execution (3): [reflected/unix/raw] ; echo RKHWNHK$((114157+752773))RKXGFIH$(echo RKHSEIF)RKHWNHK (target computed 'RKHWNHK866930RKXGFIHRKHSEIFRKHWNHK' — random operands, absent from control)
El método, la ruta, las cabeceras, el cuerpo y las cookies se reutilizan tal como se capturaron, y cada valor se codifica para el contexto en el que termina — una hoja JSON, un campo de formulario y una cookie no se escapan de la misma manera. Elimina `-p` y marca el punto con `FUZZ` o `*` en su lugar, si lo prefieres.
### Todo lo que tiene la herramienta
Dos cosas solo son accesibles desde una solicitud capturada: la **enumeración de puntos de inyección** (`--auto-params`), y cualquier sink que necesite una sesión. Así que la ejecución más completa que RCEKit puede hacer comienza desde `-r`, no desde una URL — lo cual vale la pena saber antes de concluir que un objetivo está limpio.```bash
rcekit --acknowledge-consent \
-r search.req --auto-params all --point-order thorough \
--methods reflected,eval,time,lookup,deser \
--oob-host oob.yourdomain.example --listen-dns-port 53 \
--verify-active-risk stateful --probe-depth full \
--detect-json findings.json
| -s | --server | SERVER | http://localhost:8080 | URL del servidor de escaneo |
| -t | --token | TOKEN | null | Token de autenticación de la API |
| -o | --output | OUTPUT | null | Ruta del archivo de salida |
| -f | --format | FORMAT | json | Formato de salida (json, csv, html) |
| -v | --verbose | VERBOSE | false | Habilitar registro detallado |
| -q | --quiet | QUIET | false | Modo silencioso (sin salida en consola) |
| -c | --config | CONFIG | ~/.scanner/config.yaml | Ruta del archivo de configuración |
| -p | --parallel | PARALLEL | 4 | Número de escaneos paralelos |
| -r | --retry | RETRY | 3 | Número de reintentos en caso de fallo |
| -T | --timeout | TIMEOUT | 30 | Tiempo de espera de la solicitud en segundos |
| -k | --insecure | INSECURE | false | Omitir la verificación del certificado TLS |
| -H | --header | HEADER | null | Encabezado HTTP personalizado (se puede repetir) |
| -A | --user-agent | USER_AGENT | Mozilla/5.0 | Cadena de User-Agent |
| -P | --proxy | PROXY | null | URL del proxy (http://, socks5://) |
| -x | --exclude | EXCLUDE | null | Patrones de exclusión (separados por comas) |
| -i | --include | INCLUDE | null | Patrones de inclusión (separados por comas) |
| -l | --list | LIST | null | Ruta del archivo de lista de objetivos |
| -m | --mode | MODE | fast | Modo de escaneo (fast, normal, deep) |
| -d | --debug | DEBUG | false | Habilitar salida de depuración |
| -V | --version | | | Mostrar información de la versión |
| -h | --help | | | Mostrar mensaje de ayuda |
# Escaneo básico
scanner -u https://example.com
# Escaneo con salida a archivo
scanner -u https://example.com -o results.json
# Escaneo con formato de salida CSV
scanner -u https://example.com -f csv -o results.csv
# Escaneo con autenticación
scanner -u https://example.com -t YOUR_API_TOKEN
# Escaneo con proxy
scanner -u https://example.com -P socks5://127.0.0.1:1080
# Escaneo de múltiples objetivos desde archivo
scanner -l targets.txt -o results.json
# Escaneo en modo profundo con paralelismo
scanner -u https://example.com -m deep -p 8
# Escaneo con encabezados personalizados
scanner -u https://example.com -H "Authorization: Bearer TOKEN" -H "X-Custom: value"
# Escaneo silencioso con salida a archivo
scanner -u https://example.com -q -o results.json
# Escaneo con reintentos y tiempo de espera personalizados
scanner -u https://example.com -r 5 -T 60
# Escaneo omitiendo la verificación TLS
scanner -u https://example.com -k
# Escaneo con modo de depuración
scanner -u https://example.com -d
El archivo de configuración se encuentra en ~/.scanner/config.yaml por defecto. Ejemplo:
server: http://localhost:8080
token: YOUR_API_TOKEN
output: results.json
format: json
verbose: false
quiet: false
parallel: 4
retry: 3
timeout: 30
insecure: false
user_agent: "Mozilla/5.0"
proxy: null
exclude: []
include: []
mode: fast
debug: false
Las siguientes variables de entorno se pueden utilizar para configurar el escáner:
| Variable | Descripción | Valor predeterminado |
|---|---|---|
SCANNER_SERVER | URL del servidor de escaneo | http://localhost:8080 |
SCANNER_TOKEN | Token de autenticación de la API | null |
SCANNER_OUTPUT | Ruta del archivo de salida | null |
SCANNER_FORMAT | Formato de salida | json |
SCANNER_VERBOSE | Habilitar registro detallado | false |
SCANNER_QUIET | Modo silencioso | false |
SCANNER_PARALLEL | Número de escaneos paralelos | 4 |
SCANNER_RETRY | Número de reintentos | 3 |
SCANNER_TIMEOUT | Tiempo de espera de la solicitud | 30 |
SCANNER_INSECURE | Omitir la verificación TLS | false |
SCANNER_USER_AGENT | Cadena de User-Agent | Mozilla/5.0 |
SCANNER_PROXY | URL del proxy | null |
SCANNER_MODE | Modo de escaneo | fast |
SCANNER_DEBUG | Habilitar salida de depuración | false |
| Código | Descripción |
|---|---|
0 | Éxito |
1 | Error general |
2 | Error de uso de CLI |
3 | Error de autenticación |
4 | Error de conexión |
5 | Tiempo de espera agotado |
6 | Archivo no encontrado |
7 | Permiso denegado |
8 | Configuración no válida |
9 | Objetivo no válido |
10 | Error interno |
curl http://localhost:8080/health-s-T-p-P-k para omitir la verificación del certificado (solo para pruebas)-v para ver registros detalladosConsulte CHANGELOG.md para obtener una lista de cambios en cada versión.
Consulte CONTRIBUTING.md para obtener directrices sobre cómo contribuir al proyecto.
Este proyecto está licenciado bajo la Licencia MIT. Consulte el archivo LICENSE para obtener más detalles.
Esta herramienta está destinada únicamente a fines de pruebas de seguridad autorizadas y educación. Los usuarios son responsables de cumplir con todas las leyes y regulaciones aplicables. Los autores no se hacen responsables del uso indebido o daños causados por esta herramienta.
Lo que abre cada flag:
| | |
|---|---|
| `--auto-params all` | cada valor de consulta, hoja JSON, campo de formulario, parte multipart, cookie y cabecera, en lugar de un único campo nombrado |
| `--point-order thorough` | cada cabecera que no sea hop-by-hop, no solo las de alto rendimiento |
| `--methods ...,lookup,deser` | sumideros de expresión-lookup y deserialización, que los métodos con forma de shell no pueden alcanzar |
| `--oob-host` | un host de callback para los métodos ciegos. Necesita un dominio delegado a ti; el puerto 53 requiere root |
| `--verify-active-risk stateful` | el nivel superior — añade las formas de sonda que hacen que el objetivo obtenga desde una dirección que RCEKit no eligió |
| `--probe-depth full` | cada forma de escape por sumidero, no solo las baratas |
| `--detect-json` | los mismos veredictos en JSON legible por máquina |
**Esto son muchas peticiones.** La línea de coste se imprime antes de que se dispare nada, y
`--max-points` / `--max-payloads` la acotan. Ejecútalo contra una instancia que tengas
permitido romper: `--verify-active-risk stateful` es el nivel para un objetivo desechable, no para producción.
Sin infraestructura externa, sin archivo de configuración.
**No te fíes de los GIFs** — [reprodúcelos tú mismo](https://github.com/kabiri-labs/rcekit/blob/main/docs/verify-it-yourself.md)
contra objetivos Webmin y Struts2 dockerizados en unos cinco minutos.
**A continuación:** la [**guía de campo**](https://github.com/kabiri-labs/rcekit/blob/main/docs/guide.md) recorre las situaciones reales — peticiones
capturadas, WAFs, separadores filtrados, sumideros entrecomillados, objetivos ciegos y sin salida —
con un ejemplo práctico de cada una.
---
## Qué significa un veredicto
Encontrar un *candidato* a RCE es fácil. Reportar uno que sobreviva al retest de otra persona es la parte difícil, y falla en dos direcciones: un "posiblemente vulnerable" que resulta ser reflexión, y un "no vulnerable" de una ejecución que en realidad nunca probó nada.
RCEKit responde con **ocho veredictos que nunca se colapsan entre sí**:
| Veredicto | Qué afirma |
|---|---|
| **`confirmed`** | El objetivo ejecutó la entrada. Devolvió un valor que no podía producir de otro modo — calculado a partir de operandos aleatorios para esa sonda — y ese valor está ausente en un control sin payload. |
| **`deserialization-sink`** | El objetivo reconstruyó un grafo de objetos proporcionado por el atacante. Probado, pero sobre una *propiedad diferente*: llegar a RCE desde ahí depende de gadgets del classpath, por lo que nunca se denomina RCE. |
| **`lookup-sink`** | El objetivo resolvió una URI que RCEKit le entregó — una expresión `${jndi:…}` alcanzó un lookup, probado en un callback que llevaba un token que solo esa sonda poseía. Es un sumidero, no ejecución: llegar a RCE desde ahí necesita un servidor que responda con una clase cargable. |
| **`needs-review`** | Una señal real que no es prueba por sí sola — una regresión de temporización lineal, una huella de parser. Merece tu tiempo, nunca merece la palabra "confirmed". |
| **`inconclusive`** | La evidencia apareció, pero no pudo atribuirse a la ejecución — el control sin payload también la llevaba. |
| **`negative`** | Se construyeron sondas, alcanzaron el objetivo y no encontraron nada. |
| **`error`** | Nada alcanzó el objetivo. |
| **`nothing-tested`** | No se construyó ninguna sonda. |
En el momento en que `confirmed` y `maybe` se difuminan, `confirmed` deja de significar algo — por
lo que nada se promociona nunca hacia arriba. Una regresión de temporización se queda en `needs-review` por muy
limpia que sea la pendiente. Un callback de deserialización se queda en `deserialization-sink` por muy
seguro que estés de que el classpath es explotable.
### La otra mitad: una ejecución que no probó nada nunca está limpia
Las dos últimas filas son las que otras herramientas no tienen, y importan más de lo que
parecen. Un escáner que no pudo alcanzar el objetivo, o que no construyó ninguna sonda porque
tus flags excluyeron todas ellas, no ha aprendido **nada** sobre el objetivo —
e imprimir `negative` ahí es una mentira que se lee exactamente como seguridad.
Así que `error` y `nothing-tested` son veredictos de primera clase, la ejecución sale con código distinto de cero,
y RCEKit dice cuál de ellos ocurrió y por qué:```
[!] No probes were built, so NOTHING WAS TESTED — this is not a negative result.
[!] None of the selected methods (reflected, file) apply to environment(s): sql.
Se dispara dondequiera que una ejecución pueda quedar silenciosamente vacía: un método que no aplica a los entornos seleccionados, un peldaño de --sink-shape para el que el shell elegido no tiene sintaxis, una selección de --bridges retenida por completo por el techo de seguridad, un cuerpo de solicitud que rompió la entrega antes de llegar.
Una ejecución que solo quedó parcialmente ciega recibe el mismo tratamiento un nivel más abajo. Si pediste un oráculo de segundo orden y el endpoint observado nunca respondió, los veredictos de las sondas siguen en pie — pero la ejecución te dice que se decidieron sin haber leído nunca el canal al que apuntaste, en lugar de dejarlos pasar por un negativo de segundo orden.
Una CLI, una bandera --methods, cubriendo las rutas principales hacia RCE:
| Clase de RCE | --methods | Cómo lo demuestra RCEKit |
|---|---|---|
| Inyección de comandos del SO | reflected | Hace que el shell calcule $((a+b)) sobre operandos aleatorios y colapse $(echo TAG); confirma el resultado, nunca la expresión literal. Escrito en el propio dialecto del sink — POSIX, cmd.exe o PowerShell. |
Inyección de código / expresión — SSTI, SpEL, OGNL, Groovy, eval() (CWE-94) | eval | Inyecta a*b en cada sintaxis de plantilla común (${…} {{…}} #{…} %{…} <%=…%> @(…), sin envoltorio); confirma que aparece el producto mientras que el literal a*b no. |
| Inyección de comandos ciega (sin salida) | time | Dispara una serie de retardos controlada 0/N/2N y confirma que el tiempo de respuesta sigue el retardo de forma lineal; reportado como needs-review — el jitter no puede falsificarlo, pero el timing no es un valor calculado. |
| Objetivos internos / sin salida | file | Escribe un token aleatorio y lo recupera a través de cualquier ruta de lectura — una raíz web, un parámetro LFI, un manejador de descarga o exportación, una vista previa respaldada por /tmp. Demuestra ejecución más una primitiva de escritura, sin listener externo. |
| Primitiva de subida / escritura — PUT-a-JSP, subida sin verificar (CWE-434) | write | Escribe un one-liner que calcula un producto a través de tu propia solicitud de subida, luego recupera el archivo: el producto es RCE confirmed, el código fuente que vuelve textual es needs-review — escritura arbitraria de archivos, servida pero no interpretada. |
| Sinks de deserialización — fastjson, shiro, weblogic (CWE-502) | deser | Demuestra que el endpoint deserializa datos del atacante, mediante un gadget DNS no ejecutable o un diferencial de forma de error. Reportado como , como RCE. |
Tres cosas amplían hasta dónde pueden llegar esos métodos, sin cambiar lo que cualquiera de ellos llamará confirmed:
--observe-url) — cuando el payload aterriza en una solicitud y se ejecuta en otra: SSTI almacenado renderizado en una página de perfil, un payload escrito en un log que un motor de plantillas renderiza después, un trabajo en cola. El endpoint observado se diferencia contra una instantánea tomada antes de enviar cualquier sonda.--bridges) — COPY … FROM PROGRAM, xp_cmdshell, expect://. Un puente es un portador, no un oráculo: envuelve el comando que los métodos ya construyen, así que los mismos niveles aplican a través de él.-p all) — query, hojas JSON, campos de formulario, partes multipart, cookies, cabeceras y segmentos de ruta, cada uno codificado según dónde aterriza, con el coste de la sonda impreso antes de que se dispare nada. Un cuerpo GraphQL se ordena por lo que realmente puede confirmar: las variables que un resolver lee antes que el propio documento de operación.Combina métodos libremente: --methods reflected,eval,time ejecuta los tres y reporta cada nivel por separado.
Alcance honesto. RCEKit confirma RCE que es alcanzable inyectando en una solicitud e interpretada por un shell o un evaluador. No cubre bugs de corrupción de memoria (desbordamiento de búfer, UAF) ni inyección de argumentos en un array
argvsin shell — esos son problemas distintos. Las cadenas de gadgets de deserialización también quedan fuera de alcance:--methods deserdemuestra que un endpoint deserializa datos del atacante y lo dice en su propio nivel, pero qué gadget (si alguno) convierte eso en ejecución depende del classpath del objetivo, y RCEKit no pretende saberlo. Aspira a ser excelente en las clases de RCE impulsadas por inyección anteriores en lugar de mediocre en todo.
Las otras herramientas de este espacio están construidas para meterte dentro. RCEKit está construido para que el hallazgo sobreviva al escrutinio de otra persona — el retest del cliente, la cola de triaje, la revisión del informe. Esa diferencia se manifiesta tres veces.
Rara vez conoces la clase antes de probar. Cubrir un sink desconocido con herramientas de una sola clase significa ejecutar cada una por turno y reconstruir la solicitud para cada una:
| Puede confirmar | RCEKit | commix | SSTImap | Nuclei |
|---|---|---|---|---|
| Inyección de comandos del SO | ✅ | ✅ (todo su alcance) | — | por plantilla |
| Inyección de expresión / SSTI | ✅ | mediante su técnica basada en eval | ✅ (todo su alcance) | por plantilla |
| Ciego — timing | ✅ como nivel separado | ✅ | ✅ | — |
| Ciego — fuera de banda | ✅ listener integrado | — | — | mediante interactsh |
| Sin salida — escribir y recuperar | ✅ cualquier ruta de lectura | ✅ (raíz web) | — | — |
Sinks cmd.exe y PowerShell | ✅ sondas por dialecto | ✅ (cmd) | — | por plantilla |
| Subida → escribir-luego-ejecutar | ✅ escritura vs. ejecución, niveles separados | — | — | por plantilla |
| Segundo orden — aterriza aquí, se ejecuta allí | ✅ | — | — | — |
| Puente de lenguaje de consulta al SO | ✅ | — | — | por plantilla |
| Sink de deserialización | ✅ nivel propio, nunca llamado RCE | — | — | por plantilla |
| Todo lo anterior, una CLI, una ejecución | ✅ | — | — | — |
Cobertura según la lista de técnicas documentadas de cada proyecto. SSTImap es el sucesor mantenido de tplmap, que su autor marcó como no mantenido.```bash
python rcekit.py --acknowledge-consent -r request.txt -p host --methods reflected,eval,time
### 2. Discute con sus propios resultados
Una herramienta informa lo que encontró. RCEKit también informa **lo que se negó a creer** —
`inconclusive` es un veredicto propio, para evidencia que apareció pero que no pudo
atribuirse a la ejecución:```
[detect] methods: reflected, eval
[detect] sent 13 probes: confirmed=0, inconclusive=2, negative=11
Esos dos habrían sido el hallazgo de otra persona. Cinco mecanismos producen ese veredicto, y se ejecutan en cada confirmación:
inconclusive, no un hallazgo.$((a+b)); solo la ejecución devuelve el valor.confirmed.El mismo instinto funciona en sentido contrario. El timing nunca se autoconfirma, un callback de deserialización nunca se llama RCE, y una ejecución que no construyó sondas nunca se llama negativa.
Los controles sobre los que realmente pregunta el reglamento de un cliente, en la herramienta en lugar de en tus notas:
| Puerta de consentimiento | Nada explotador se genera ni se dispara sin --acknowledge-consent. |
| Plan de ejecución | Imprime el número exacto de sondas, las formas de sink, los niveles de seguridad y cualquier destino de callback saliente antes de que salga la primera solicitud. |
| Seguro por defecto | Las reverse shells, el acceso a credenciales, los metadatos de la nube, el movimiento lateral y el escape de contenedores se retienen hasta que eleves --verify-active-risk; la persistencia y las puertas traseras necesitan una segunda bandera adicional. Los puentes que crean un objeto en el objetivo están sujetos al mismo techo. |
| Comandos de limpieza | file, write y los puentes con estado cambian el estado del objetivo, por lo que cada hallazgo — incluido un needs-review — imprime qué ejecutar para deshacerlo. |
| Las credenciales se quedan donde están | La recuperación de lectura de file lleva las cabeceras Authorization/Cookie de la ejecución solo al mismo origen, y lo dice en voz alta cuando las retiene. La recuperación del canal observado no envía ninguna en absoluto a menos que le entregues una solicitud con --observe-request. |
| Rastro de auditoría redactado | Cada ejecución queda en exploit_audit.log, registrando que se envió una cabecera de credencial, nunca su valor. |
| Marca de agua | --watermark estampa un token rastreable en cada payload, de modo que un payload encontrado en los registros del cliente meses después sea atribuible a tu ejecución. |
| Sin callbacks de terceros | El listener OOB es tuyo. Nada se enruta a través de un servidor de interacción público, que algunos compromisos prohíben directamente. |
| Un solo archivo de la stdlib | rcekit.py se ejecuta solo — jump box, host con air-gap, donde sea que pip install no sea una opción. |
¿Quieres una shell en lugar de un veredicto? commix y SSTImap continúan hacia
la post-explotación; RCEKit se detiene en la prueba por diseño. ¿Barrer miles de hosts
en busca de CVE conocidos? Ese es el trabajo de Nuclei — y RCEKit escribe plantillas de
Nuclei (--output-format nuclei), así que alimenta tu escáner en lugar de competir con él.
¿Ya sabes que la inyección es SQL y quieres la base de datos en sí?
sqlmap domina ese terreno — los
puentes de RCEKit existen para probar que el SO es alcanzable desde un parámetro de texto, no para
explotar la base de datos.
Cada fila es un ejemplo práctico en la guía de campo — el comando, lo que envía, y cómo leer lo que devuelve.
| Situación | Ir a |
|---|---|
| Tengo una URL y un parámetro | Apuntar a una URL |
| Tengo una solicitud guardada de Burp | Apuntar a una solicitud capturada |
| La app es JSON / el payload sigue siendo destrozado | Aterrizar el payload intacto |
| No sé de qué clase es | Elegir métodos |
El sink elimina ; | Cuando el sink filtra separadores |
Mi entrada aterriza dentro de 'comillas' | Inyectar dentro de comillas |
| El sink ejecuta mi entrada como el comando completo | Sinks de comando completo |
| El objetivo es Windows o el sink es PowerShell | Sinks de Windows y PowerShell |
| Hay un WAF | Trabajar alrededor de un WAF |
| No vuelve ninguna salida en absoluto | Objetivos ciegos |
| Sin salida y sin egreso | Objetivos sin egreso |
| La solicitud almacena un archivo en lugar de ejecutar algo | Objetivos de subida y primitiva de escritura |
| Verifícalo tú mismo | Reproduce las confirmaciones anteriores en tu propia máquina, contra objetivos vulnerables dockerizados. Cinco minutos. |
| Guía de campo | Recorrido basado en ejemplos de cada situación real, desde una primera sonda hasta cadenas de múltiples pasos. Empieza aquí. |
| Generación de payloads y exportaciones | RCEKit como generador de payloads: perfiles de objetivo, y exportaciones de Burp / ffuf / Nuclei. |
| Referencia | Cada bandera, entorno, categoría, contexto, codificación y sink de ejecución de código. |
| CHANGELOG.md | Qué cambió en cada versión, y qué volver a comprobar al actualizar. |
| CONTRIBUTING.md | Cómo añadir sinks, categorías, codificaciones y métodos de detección. |
| SECURITY.md | Reportar una vulnerabilidad en RCEKit mismo. |
RCEKit explota, y ese es el punto. Una vulnerabilidad se confirma haciendo que el objetivo haga la cosa, porque esa es la única evidencia que una firma no puede falsificar y una compilación parcheada no puede producir por accidente. Lo que limita una ejecución no es la reticencia a explotar. Son dos hechos estructurales y un interruptor.
No toma ningún payload arbitrario de ti. Las sondas son construidas por el motor para servir a un oráculo — aritmética sobre operandos aleatorios para esa sonda, un nombre que solo esta ejecución podría haber elegido. No hay entrada que convierta la detección en algo más, porque no hay tal entrada que dar.
Cualquier cosa que vaya más allá de calcular un valor declara el nivel que necesita, así que una
bandera decide hasta dónde llega una ejecución: --verify-active-risk safe | intrusive | stateful. Un método o una forma de sonda individual por encima de ese nivel se retiene por
nombre, con la bandera que lo enviaría — una escalera que se encoge silenciosamente es
indistinguible de un objetivo sin nada que encontrar. Contra una instancia desechable, eleva el nivel y obtén todo lo que la herramienta tiene.
--acknowledge-consent; --detection-only es benigno y no lo requiere.--verify-active-risk. Los payloads destructivos (persistencia, puertas traseras) nunca se
disparan sin --verify-allow-destructive. Un plan de ejecución imprime exactamente
lo que se enviará antes de que algo se dispare.safe / intrusive / stateful. Los payloads del corpus se
filtran por --max-safety; los métodos de detección y sus formas de sonda declaran
los mismos peldaños y se filtran por --verify-active-risk, por lo que un método que
hace que el objetivo se comunique hacia fuera o deja algo atrás está sujeto al mismo
orden que cada payload del corpus. El pre-vuelo nombra el nivel que cada elemento retenido
realmente necesita. file y write están controlados por su propia configuración
en su lugar: ninguno hace nada hasta que nombres un directorio en el que escribir y una
URL desde la que leerlo de vuelta.exploit_audit.log; --watermark incrusta un token rastreable; los registros de ejecución van a
rcekit.log.--template-file explícito que falta, hace que RCEKit se niegue a ejecutarse y salga con un código distinto de cero
en lugar de generar silenciosamente nada (--doctor lo comprueba). Solo un archivo de corpus
predeterminado ausente recurre a la copia integrada, y lo dice cuando lo
hace.Este toolkit está destinado únicamente a pruebas de penetración autorizadas, investigación de seguridad, educación y entrenamiento defensivo. Nunca lo uses contra sistemas sin permiso explícito — las pruebas no autorizadas son ilegales.
python -m unittest discover -s tests # dependency-free test suite
Las contribuciones son bienvenidas — nuevos sinks/categorías, codificaciones, entornos, métodos de detección, correcciones de errores y documentación. Las bases de payloads residen en plantillas JSON editables
(`templates/payloads.json`), por lo que la mayor parte de la cobertura se amplía sin tocar el código
fuente de Python. Después de modificar el corpus, actualiza la copia integrada que se distribuye dentro de
`rcekit.py`:```bash
python tools/embed_corpus.py # --check verifies it is current
La suite de pruebas falla si los dos alguna vez divergen. Consulta CONTRIBUTING.md.
MIT — consulta LICENSE.
deserialization-sink| Ciego / fuera de banda — exfiltración, asíncrono | oob | El listener HTTP/DNS integrado recibe callbacks y correlaciona cada uno con el payload exacto; cada sonda lleva su propio token. |
| Sinks de búsqueda de expresiones — Log4Shell/JNDI | lookup | El sink resuelve una URI ${jndi:…} en lugar de ejecutar un comando, por lo que las sondas de shell de oob no alcanzan nada. Lo demuestra solo con el callback y reporta lookup-sink, nunca confirmed. Solo se envía jndi:dns:// — una búsqueda de nombre y nada más — así que lo que se demuestra es la búsqueda, no una cadena de gadgets. |
| El payload se ejecuta después, en una solicitud diferente | Cuando la ejecución ocurre en otra solicitud |
| El punto de inyección es SQL y el sink es el host de la base de datos | Puentes de lenguaje de consulta |
| El endpoint toma un objeto serializado | Sinks de deserialización |
| El sink está detrás de un login o una subida de archivos | Cadenas de múltiples pasos |
Obtuve needs-review / inconclusive / error | Leer los resultados |
| Dice que el corpus no es utilizable | Solución de problemas |