En este writeup documentamos la resolución completa de la máquina virtual Pinguinazo (autor: El Pingüino de Mario), catalogada como fácil en la plataforma DockerLabs.
El objetivo es entregar una guía reproducible, didáctica y orientada a mitigación: explicar qué se hizo, por qué funcionó cada paso y cómo evitar patrones similares en entornos reales.
El flujo de trabajo se estructura en tres fases:
Reconocimiento – identificar servicios expuestos, rutas relevantes y vectores de entrada.
Escalada de privilegios – abusar de configuraciones inseguras (sudo) para obtener root.
⚠️ Aviso: Todas las pruebas se realizaron dentro de un laboratorio controlado (DockerLabs). No realices pruebas intrusivas en sistemas sin autorización explícita.
/index — página principal con un formulario de entrada.
/greet — formulario que muestra el nombre introducido (punto de interés).
/console — interfaz que pide un PIN; sugiere un panel administrativo.
Observación: el comportamiento de /greet (mostrar input en la página) sugiere la posibilidad de Server-Side Template Injection (SSTI) si la aplicación usa plantillas sin correcto escape.
En el formulario (/greet), enviamos una prueba básica de expresión:
{{ 7 * 7 }}
La página devuelve 49, lo que confirmaría que la entrada se evalúa dentro de una plantilla (comportamiento típico de motores tipo Jinja2 u otros motores Python).
Por qué importa: si la plantilla evalúa expresiones, es posible acceder a objetos globales y, desde ahí, intentar ejecutar comandos del sistema.
Probamos explorar objetos disponibles para encontrar os y funciones que permitan ejecutar procesos. Un ejemplo que funcionó en esta máquina:
{{ lipsum.__globals__["os"].popen('id').read() }}
Resultado: la salida del comando id aparece en la página → ejecución remota de comandos confirmada.
Explicación técnica breve:lipsum (u otro objeto expuesto en el contexto) tiene un diccionario __globals__ que contiene el módulo os. Llamando a os.popen() se pueden ejecutar comandos y leer su salida.
Tras enviar el payload, la conexión inversa se establece y obtenemos shell interactiva en el listener.
Nota práctica: muchas shells obtenidas por RCE son muy básicas. Para estabilizarlas, tras conseguir la shell puedes ejecutar en tu terminal atacante lo siguiente (si la shell está en background) para obtener una TTY más usable:
Ventana de terminal
# Ejemplo de estabilización (en atacante)
script/dev/null-cbash
# Luego en la shell remota: Ctrl+Z, y en local:
sttyraw-echo; fg
reset
exportTERM=xterm
🧑💻 Paso 3 — Escalada de privilegios (sudo → root)
Como el usuario recuperado (pinguinazo), listamos los privilegios sudo:
Ventana de terminal
sudo-l
Salida relevante: el usuario puede ejecutar java como root sin contraseña.
Impacto: poder ejecutar java como root permite ejecutar código arbitrario con privilegios elevados si java puede cargar y ejecutar clases/controladores proporcionados por el atacante.
Al ejecutar el jar con sudo, la reverse shell que conecte de vuelta al atacante tendrá permisos root. Resultado final: acceso root conseguido.
Alternativas: en vez de usar un jar, se puede usar sudo java -cp . Exploit, o encontrar otra clase con funcionalidad de ejecución. La idea clave es que sudo permite ejecutar java con el entorno de root.
Evitar evaluar directamente entradas de usuario en plantillas. Usa motores con escapado por defecto y no expongas objetos internos.
Si usas Jinja2 (u otro motor Python), emplea Environment(..., autoescape=True) y restringe el contexto que se pasa a las plantillas (no incluir módulos o funciones peligrosas).
Valida y sanea entradas del usuario — aplicar listas blancas de valores cuando sea posible.
Emplear Content Security Policy (CSP) y protección CSRF donde aplique.
A nivel de sistema
Revisa la configuración de sudoers y elimina privilegios innecesarios (no permitir ejecutar binarios generales como java sin restricciones).
Minimizar servicios expuestos y usar firewalls para limitar acceso por IP cuando corresponda.
No dejar archivos sensibles en /tmp o directorios accesibles públicamente; usar permisos mínimos y ubicaciones seguras.
Registrar y monitorizar ejecuciones de sudo y actividades inusuales en el sistema.
Defensa en profundidad
Aplicar principios de menor privilegio para cuentas y procesos.
Usar herramientas de detección de RCE y escaneo de dependencias para detectar patrones vulnerables.
Hacer revisiones de código (code review) enfocadas en manejo de plantillas y entrada de usuario.