Ghost AcademyGhostOffensive · Ghost Academy
GhostOffensiveMódulo 10Con laboratorio

Adaptar y corregir exploits

Encontrar el exploit correcto (módulo anterior) es solo la mitad del trabajo. La inmensa mayoría de los exploits públicos, tal como se descargan, no funcionan a la primera. Y eso no significa que estén mal elegidos: casi siempre necesitan un ajuste pequeño para encajar con tu objetivo exacto.

Objetivos de la unidad

1. Por qué un exploit público casi nunca funciona sin tocarlo

Un exploit se escribe contra un entorno concreto —una versión, un sistema operativo, una configuración, una dirección IP— y se publica tal cual. El tuyo casi nunca es idéntico. Adaptarlo no es un fallo del exploit ni tuyo: es el trabajo. Los motivos habituales, de más trivial a más delicado:

MotivoSíntoma habitual
Dirección o puerto de ejemplo del autor, sin cambiarLa conexión no llega a ningún sitio: cuelgue o "connection refused".
Escrito para Python 2SyntaxError al ejecutarlo con Python 3 (print sin paréntesis, xrange...).
Mezcla de bytes y strTypeError: can't concat str to bytes (o similar).
Llamada a una función con los argumentos mal puestosTypeError señalando cuántos argumentos esperaba la función.
El protocolo del objetivo cambió ligeramente respecto a cuando se escribió el exploitEl objetivo responde, pero con un error o un rechazo, no con un fallo de Python.
Terminador de línea o de comando distinto al esperadoEl objetivo no responde nunca: se queda esperando el resto de una petición que nunca llega completa.
Un valor numérico (longitud, offset, dirección) calculado para otra versiónEl objetivo responde con un error explícito, o el exploit "casi" funciona pero el objetivo se cae en vez de darte control.
MotivoSíntoma habitual
Dirección o puerto de ejemplo del autor, sin cambiarLa conexión no llega a ningún sitio: cuelgue o "connection refused".
Escrito para Python 2SyntaxError al ejecutarlo con Python 3 (print sin paréntesis, xrange...).
Mezcla de bytes y strTypeError: can't concat str to bytes (o similar).
Llamada a una función con los argumentos mal puestosTypeError señalando cuántos argumentos esperaba la función.
El protocolo del objetivo cambió ligeramente respecto a cuando se escribió el exploitEl objetivo responde, pero con un error o un rechazo, no con un fallo de Python.
Terminador de línea o de comando distinto al esperadoEl objetivo no responde nunca: se queda esperando el resto de una petición que nunca llega completa.
Un valor numérico (longitud, offset, repetición) calculado para otra versiónEl objetivo responde con un error explícito sobre el valor recibido, si tiene la cortesía de decirlo.

2. Leer el error antes que nada

Un traceback de Python no es ruido: es la localización exacta del problema.

kali@lab
$ python3 exploit.py
Traceback (most recent call last):
  File "exploit.py", line 14, in <module>
    payload = b"DIAG5 " + version_cliente + b"\r\n"
TypeError: can't concat str to bytes

La última línea dice el tipo de error; la penúltima, la línea de código exacta. Aquí, version_cliente es una cadena de texto (str) y se está intentando concatenar con datos binarios (bytes); la solución es convertirla con .encode() o escribirla directamente como bytes (b"...").

3. Cuando el objetivo responde, pero no como se esperaba

No todos los fallos son excepciones de Python. Si el exploit se ejecuta sin errores pero el objetivo responde con un mensaje de rechazo, la información está en esa respuesta:

4. Los parámetros frágiles: shellcode, direcciones y offsets

Los exploits de corrupción de memoria (desbordamientos de búfer y similares) llevan piezas especialmente sensibles al entorno que conviene reconocer aunque este curso no construya uno desde cero:

La lección para este curso: cuando un exploit de memoria falla sin dar un error de Python claro, sospecha del shellcode o de una dirección calculada para otra versión, no de tu forma de ejecutarlo.

5. Adaptar, no reescribir

El objetivo casi nunca es escribir el exploit desde cero: es cambiar lo mínimo necesario para que funcione contra tu objetivo concreto. El método:

  1. Ejecuta el exploit tal cual viene, para ver el fallo real (no el que imaginas).
  2. Localiza la línea exacta señalada por el error, o el punto donde deja de avanzar.
  3. Cambia solo eso: una dirección, un separador, un tipo de dato, un nombre de comando.
  4. Vuelve a ejecutar. Si aparece un fallo distinto, ya has resuelto el anterior: repite el proceso con el nuevo.
Un exploit se corrige de fallo en fallo, no todo de golpe. Es normal necesitar varias vueltas; cada error nuevo es una señal de progreso, no de retroceso.

6. Prueba en un entorno controlado primero

Un exploit adaptado sigue siendo código que puede tumbar el servicio objetivo (sobre todo los de memoria: si el offset no es exacto, el proceso se cae). Lanzarlo directamente contra el sistema de producción de un cliente sin haberlo probado es una forma rápida de provocar una caída no autorizada. La práctica correcta, cuando es posible, es montar una réplica del objetivo (misma versión del software, mismo SO) y afinar ahí el exploit —offset, shellcode, parámetros— hasta que sea fiable, antes de usarlo contra el objetivo real. Es, literalmente, lo que hace el laboratorio de este módulo: un entorno seguro donde equivocarse sale gratis.

Para profundizar
🧰 Herramientas relacionadas (Ghost Academy)

Guías y laboratorios ya publicados en Ghost Academy sobre las herramientas de este módulo:

RevShell · Tratamiento de TTY

Laboratorio: Nexus Robotics

⬇ Descargar laboratorio (ZIP)

Descomprime, lee el LEEME.md y lanza startlab.sh. En la carpeta exploits/ hay 8 scripts rotos, cada uno con un fallo distinto de los descritos en esta unidad, contra el servicio de diagnóstico NexusDiag (localhost:9000). Arréglalos uno a uno; cada uno, al funcionar, imprime su flag GO{...}. Verifícalas en http://localhost:8787/verificador.

¿Atascado o ya terminado? La solución paso a paso muestra el error de cada script y su corrección exacta. Úsala cuando lo hayas intentado.

Autoevaluación

  1. Un exploit falla con ConnectionRefusedError. ¿Qué es lo primero que revisas?
  2. ¿Qué diferencia hay entre un SyntaxError y un TypeError a la hora de saber qué corregir?
  3. El objetivo responde "comando no reconocido" en vez de fallar el script. ¿Qué te dice eso sobre dónde está el problema?
  4. ¿Por qué un exploit de memoria puede tumbar el servicio en vez de darte control, y qué parámetro suele ser la causa?
  5. ¿Qué es un shellcode y por qué uno de ejemplo casi nunca sirve tal cual?
  6. ¿Por qué conviene corregir un fallo cada vez, en vez de reescribir el script entero de golpe?
  7. ¿Por qué se prueba un exploit adaptado en una réplica antes de lanzarlo contra el objetivo real?