Titanic

Foothold

Intanto mappiamo l’IP della macchina con l’hostname titanic.htb nel file /etc/hosts.

Dopo aver lanciato una scansione si ottiene

$ sudo nmap -sV -vv -oN tcp.txt titanic.htb
# Nmap 7.94SVN scan initiated Sat Mar  1 15:17:19 2025 as: /usr/lib/nmap/nmap -sV -vv -oN tcp.txt titanic.htb
Nmap scan report for titanic.htb (10.10.11.55)
Host is up, received reset ttl 128 (0.011s latency).
Scanned at 2025-03-01 15:17:19 CET for 16s
Not shown: 998 filtered tcp ports (no-response)
PORT   STATE SERVICE REASON          VERSION
22/tcp open  ssh     syn-ack ttl 128 OpenSSH 8.9p1 Ubuntu 3ubuntu0.10 (Ubuntu Linux; protocol 2.0)
80/tcp open  http    syn-ack ttl 128 Apache httpd 2.4.52
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Read data files from: /usr/share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Sat Mar  1 15:17:35 2025 -- 1 IP address (1 host up) scanned in 16.57 seconds

È quindi presente un servizio in ascolto sulla porta 80.

Navigando sul sito è presente una funzione di booking e proviamo a vedere se esiste qualche vulnerabilità su di essa.

Titanic

Dopo aver inviato la prenotazione viene scaricato un file .json e guardando le richieste su Burp Suite, si nota questa GET

Titanic

Vedendo la struttura della GET, si verifica se è presente un LFI, essendo presente un parametro, ed in effetti, con le seguenti payload si ottengono dei risultati

Payload 1:
/download?ticket=../../../etc/passwd
Payload 2:
/download?ticket=../../../etc/hosts

Con la prima payload si legge il nome di un utente developer, con cui si ottiene difatti la user flag in ../../../home/developer/user.txt.

Con la seconda si nota un nuovo host dev.titanic.htb.

Andando sul nuovo hostname ci si trova su un applicativo gitea, in questo applicativo andando nella sezione explore, poi in developer/docker-config abbiamo due cartelle, gitea e mysql.

Nella cartella gitea abbiamo un file docker-compose.yml con del contenuto interessante

Titanic

Attraverso quel path e LFI si potrebbero cercare dei file di configurazione di gitea, come app.ini, come dice la documentazione qui https://docs.gitea.com/next/administration/config-cheat-sheet.

Guardando meglio la documentazione dell’installazione di gitea con docker (qui https://docs.gitea.com/installation/install-with-docker#customization) si fa riferimento al fatto che “Customization files described here should be placed in /data/gitea directory”.

A questo punto combinando il path di sopra con questa cosa, si prova a fare un LFI su

/home/developer/gitea/data/gitea/conf/app.ini

Il file viene trovato e contiene qualcosa di interessante

Titanic

Scaricando gitea.db e facendo le query con sqlite3 si trova una tabella user con il seguente contenuto (ci sono anche altri campi nella tabella)

sqlite> select name,email,passwd,salt,passwd_hash_algo from user;
name|email|passwd|salt|passwd_hash_algo
administrator|root@titanic.htb|cba20ccf927d3ad0567b68161732d3fbca098ce886bbc923b4062a3960d459c08d2dfc063b2406ac9207c980c47c5d017136|2d149e5fbd1b20cf31db3e3c6a28fc9b|pbkdf2$50000$50
developer|developer@titanic.htb|e531d398946137baea70ed6a680a54385ecff131309c0bd8f225f284406b7cbc8efc5dbef30bf1682619263444ea594cfb56|8bf3e3452b78544f8bee9400d6936d34|pbkdf2$50000$50

A questo punto si può usare hashcat per craccare le password e quindi creiamo un file hashes.txt con il corretto formato.

Intanto sapendo anche gli username, inseriamoli nel file, poi le iterazioni, il formato sha256 per pbkdf2, il salt e l’hash in base64.

administrator:sha256:50000:MmQxNDllNWZiZDFiMjBjZjMxZGIzZTNjNmEyOGZjOWI=:Y2JhMjBjY2Y5MjdkM2FkMDU2N2I2ODE2MTczMmQzZmJjYTA5OGNlODg2YmJjOTIzYjQwNjJhMzk2MGQ0NTljMDhkMmRmYzA2M2IyNDA2YWM5MjA3Yzk4MGM0N2M1ZDAxNzEzNg==
developer:sha256:50000:OGJmM2UzNDUyYjc4NTQ0ZjhiZWU5NDAwZDY5MzZkMzQ=:ZTUzMWQzOTg5NDYxMzdiYWVhNzBlZDZhNjgwYTU0Mzg1ZWNmZjEzMTMwOWMwYmQ4ZjIyNWYyODQ0MDZiN2NiYzhlZmM1ZGJlZjMwYmYxNjgyNjE5MjYzNDQ0ZWE1OTRjZmI1Ng==

Ora lanciamo il comando

hashcat hashes.txt --wordlist /usr/share/wordlists/rockyou.txt --user

Dopo un po’ hashcat ci fornisce la password per developer “25282528”, con questa accediamo alla macchina in SSH e otteniamo il foothold.

Privilege Escalation

Facendo una ricerca tra le connessioni in ascolto, i processi attivi, si nota che è presente un app.py avviata dalla cartella /opt/app

Andando a controllare nella cartella /opt è presente un’altra cartella scripts contenente uno script identify_images.sh.

Titanic

Il contenuto dello script sembra richiamare tutti i file .jpg in un path e va a prendere i metadati attraverso magick e li inserisce nel file metadata.log.

Titanic

Provando ad eseguire lo script, ci dice che non è possibile scrivere sul file metadata.log, difatti, controllando i permessi è di proprietà di root.

Questo ci fa dedurre che potrebbe esserci un cron job che esegue lo script come utente root.

Titanic

Avendo visto che nello script è presente magick, si verifica la versione per vedere se esistono delle CVE associate.

Version: ImageMagick 7.1.1-35

In questa versione è presente una CVE-2024-41817 che consente l’esecuzione di codice arbitrario tramite il caricamento di librerie condivise dannose nella directory di lavoro corrente quando si esegue ImageMagick: https://github.com/ImageMagick/ImageMagick/security/advisories/GHSA-8rxc-922v-phg8

Quindi siccome la working directory per lo script è /opt/app/static/assets/images e guardando bene i permessi è possibile creare file in quella directory, proviamo quindi questa PoC per la creazione di una libreria condivisa e vediamo se viene eseguita.

Titanic

Ora attendiamo e vediamo se esiste veramente un cron job che esegue lo script e scrive su metadata.log.

Effettivamente dopo poco leggendo il contenuto di metadata.log, si può evincere il seguente output

Titanic

A questo punto lanciamo la seguente payload

Titanic

E mettendomi in ascolto con netcat

Titanic

Ora prendiamo e inviamo la flag root.txt.

Foothold

First, let’s map the machine’s IP to the hostname titanic.htb in the /etc/hosts file.

After running a scan we get

$ sudo nmap -sV -vv -oN tcp.txt titanic.htb
# Nmap 7.94SVN scan initiated Sat Mar  1 15:17:19 2025 as: /usr/lib/nmap/nmap -sV -vv -oN tcp.txt titanic.htb
Nmap scan report for titanic.htb (10.10.11.55)
Host is up, received reset ttl 128 (0.011s latency).
Scanned at 2025-03-01 15:17:19 CET for 16s
Not shown: 998 filtered tcp ports (no-response)
PORT   STATE SERVICE REASON          VERSION
22/tcp open  ssh     syn-ack ttl 128 OpenSSH 8.9p1 Ubuntu 3ubuntu0.10 (Ubuntu Linux; protocol 2.0)
80/tcp open  http    syn-ack ttl 128 Apache httpd 2.4.52
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Read data files from: /usr/share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Sat Mar  1 15:17:35 2025 -- 1 IP address (1 host up) scanned in 16.57 seconds

So there is a service listening on port 80.

Browsing the site, there is a booking feature, and we try to see whether it has any vulnerabilities.

Titanic

After submitting the booking, a .json file is downloaded, and looking at the requests in Burp Suite we notice this GET

Titanic

Looking at the structure of the GET, we check whether an LFI is present, since there is a parameter, and indeed, with the following payloads we get some results

Payload 1:
/download?ticket=../../../etc/passwd
Payload 2:
/download?ticket=../../../etc/hosts

With the first payload we read the name of a developer user, with which we actually obtain the user flag in ../../../home/developer/user.txt.

With the second one we notice a new host dev.titanic.htb.

Going to the new hostname we land on a gitea application; in this application, going to the explore section, then to developer/docker-config, we have two folders, gitea and mysql.

In the gitea folder we have a docker-compose.yml file with some interesting content

Titanic

Through that path and the LFI we could look for gitea configuration files, such as app.ini, as the documentation states here https://docs.gitea.com/next/administration/config-cheat-sheet.

Looking more closely at the documentation for installing gitea with docker (here https://docs.gitea.com/installation/install-with-docker#customization) it mentions that “Customization files described here should be placed in /data/gitea directory”.

At this point, combining the path above with this, we try an LFI on

/home/developer/gitea/data/gitea/conf/app.ini

The file is found and contains something interesting

Titanic

Downloading gitea.db and running queries with sqlite3, we find a user table with the following content (there are also other fields in the table)

sqlite> select name,email,passwd,salt,passwd_hash_algo from user;
name|email|passwd|salt|passwd_hash_algo
administrator|root@titanic.htb|cba20ccf927d3ad0567b68161732d3fbca098ce886bbc923b4062a3960d459c08d2dfc063b2406ac9207c980c47c5d017136|2d149e5fbd1b20cf31db3e3c6a28fc9b|pbkdf2$50000$50
developer|developer@titanic.htb|e531d398946137baea70ed6a680a54385ecff131309c0bd8f225f284406b7cbc8efc5dbef30bf1682619263444ea594cfb56|8bf3e3452b78544f8bee9400d6936d34|pbkdf2$50000$50

At this point we can use hashcat to crack the passwords, so we create a hashes.txt file with the correct format.

In the meantime, knowing the usernames as well, let’s add them to the file, then the iterations, the sha256 format for pbkdf2, the salt and the hash in base64.

administrator:sha256:50000:MmQxNDllNWZiZDFiMjBjZjMxZGIzZTNjNmEyOGZjOWI=:Y2JhMjBjY2Y5MjdkM2FkMDU2N2I2ODE2MTczMmQzZmJjYTA5OGNlODg2YmJjOTIzYjQwNjJhMzk2MGQ0NTljMDhkMmRmYzA2M2IyNDA2YWM5MjA3Yzk4MGM0N2M1ZDAxNzEzNg==
developer:sha256:50000:OGJmM2UzNDUyYjc4NTQ0ZjhiZWU5NDAwZDY5MzZkMzQ=:ZTUzMWQzOTg5NDYxMzdiYWVhNzBlZDZhNjgwYTU0Mzg1ZWNmZjEzMTMwOWMwYmQ4ZjIyNWYyODQ0MDZiN2NiYzhlZmM1ZGJlZjMwYmYxNjgyNjE5MjYzNDQ0ZWE1OTRjZmI1Ng==

Now let’s run the command

hashcat hashes.txt --wordlist /usr/share/wordlists/rockyou.txt --user

After a while, hashcat gives us the password for developer “25282528”, with which we log into the machine over SSH and obtain the foothold.

Privilege Escalation

Searching through the listening connections and the active processes, we notice that there is an app.py started from the /opt/app folder

Going to check in the /opt folder, there is another folder scripts containing an identify_images.sh script.

Titanic

The content of the script seems to call all the .jpg files in a path and grab their metadata through magick, inserting them into the metadata.log file.

Titanic

Trying to run the script, it tells us that it is not possible to write to the metadata.log file; indeed, checking the permissions, it is owned by root.

This leads us to deduce that there might be a cron job running the script as the root user.

Titanic

Having seen that magick is used in the script, we check the version to see whether there are any associated CVEs.

Version: ImageMagick 7.1.1-35

In this version there is a CVE-2024-41817 that allows arbitrary code execution through loading malicious shared libraries in the current working directory when running ImageMagick: https://github.com/ImageMagick/ImageMagick/security/advisories/GHSA-8rxc-922v-phg8

So, since the working directory for the script is /opt/app/static/assets/images and looking carefully at the permissions it is possible to create files in that directory, let’s try this PoC for creating a shared library and see whether it gets executed.

Titanic

Now we wait and see whether there really is a cron job running the script and writing to metadata.log.

Indeed, after a short while, reading the content of metadata.log, we can deduce the following output

Titanic

At this point we launch the following payload

Titanic

And setting up a listener with netcat

Titanic

Now we go ahead and submit the root.txt flag.