MonitorsTwo is an easy linux box that starts with exploiting a vulnerable instance of Cacti to gain a shell on the box. This drops you into a docker container that has SUID set on capsh
, which allows for easy privesc. You then move laterally to the main host by cracking a hash obtained from a local MySQL server, and then exploit CVE-2021-41091 to gain root on the box.
Info
Recon
NMAP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Nmap 7.70 scan initiated Wed Aug 2 06:22:06 2023 as: nmap -sC -sV -oN nmap.txt -v 10.10.11.211
Nmap scan report for 10.10.11.211
Host is up (0.60s latency).
Not shown: 998 closed ports
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-favicon: Unknown favicon MD5: 4F12CCCD3C42A4A478F067337FE92794
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: Login to Cacti
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Read data files from: /usr/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Wed Aug 2 06:23:17 2023 -- 1 IP address (1 host up) scanned in 70.81 seconds
Web
Site is running Cacti v1.2.22;
Quick search showed it’s vulnerable to CVE-2022-46169. PoC found in this repo. The exploit errored out after a while;
So I modified the script to go through my proxy to see what’s up. The exploit is bruteforcing the local_data_ids
parameter;
So I setup a numeric bruteforce on the field;
Running it, we got a few interesting results;
From the code, the output of finding_id()
is what’s passed to the rev_shell()
function, which appends the payload to the URL parameter poller_id
;
Testing this in the replay tab, I got code execution;
User
Python not installed locally, so used script /dev/null -qc /bin/bash
for TTY upgrade. Presence of /.dockerenv
indicates we are in a container. MySQL creds found in /var/www/html/include/config.php
;
Cacti uses user_auth
table to store user creds;
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
MySQL [cacti]> describe user_auth;
+------------------------+-----------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------------------+-----------------------+------+-----+---------+----------------+
| id | mediumint(8) unsigned | NO | PRI | NULL | auto_increment |
| username | varchar(50) | NO | MUL | 0 | |
| password | varchar(256) | NO | | | |
| realm | mediumint(8) | NO | MUL | 0 | |
| full_name | varchar(100) | YES | | 0 | |
| email_address | varchar(128) | YES | | NULL | |
| must_change_password | char(2) | YES | | NULL | |
| password_change | char(2) | YES | | on | |
| show_tree | char(2) | YES | | on | |
| show_list | char(2) | YES | | on | |
| show_preview | char(2) | NO | | on | |
| graph_settings | char(2) | YES | | NULL | |
| login_opts | tinyint(3) unsigned | NO | | 1 | |
| policy_graphs | tinyint(3) unsigned | NO | | 1 | |
| policy_trees | tinyint(3) unsigned | NO | | 1 | |
| policy_hosts | tinyint(3) unsigned | NO | | 1 | |
| policy_graph_templates | tinyint(3) unsigned | NO | | 1 | |
| enabled | char(2) | NO | MUL | on | |
| lastchange | int(11) | NO | | -1 | |
| lastlogin | int(11) | NO | | -1 | |
| password_history | varchar(4096) | NO | | -1 | |
| locked | varchar(3) | NO | | | |
| failed_attempts | int(5) | NO | | 0 | |
| lastfail | int(10) unsigned | NO | | 0 | |
| reset_perms | int(10) unsigned | NO | | 0 | |
+------------------------+-----------------------+------+-----+---------+----------------+
25 rows in set (0.001 sec)
Found 2 hashes;
1
2
3
4
5
6
7
8
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 |
+----------+--------------------------------------------------------------+
Cracked that of marcus
successfully;
This gave me access to the main host over SSH;
PrivEsc
marcus
does not have sudo perms, and is also not in any special group. File system enum showed we have execute permission on /var/lib/docker
, which means we can enter the directory;
Searching about how this could be exploited lead me to CVE-2021-41091;
CVE-2021-41091 is a flaw in Moby (Docker Engine) that allows unprivileged Linux users to traverse and execute programs within the data directory (usually located at /var/lib/docker) due to improperly restricted permissions. This vulnerability is present when containers contain executable programs with extended permissions, such as setuid. Unprivileged Linux users can then discover and execute those programs, as well as modify files if the UID of the user on the host matches the file owner or group inside the container.
For this exploit to work though, we need to be root
in one of the docker containers on the host. So I went back in as www-data
using the previous Cacti RCE. Searching for SUIDs gave an interesting result;
capsh
is a utility for managing capabilities/perms. Using capsh --gid=0 --uid=0 --
(from gtfobins), I was elevated to root
;
I then setup SUID on /bin/bash
, then ran the exploit again, which gave me root on main;
Summary
- NMAP showed port 22 and 80
- Web server running an instance of Cacti v1.2.22, which is vulnerable to CVE-2022-46169 (RCE)
- Inside as
www-data
;capsh
SUID allowed me to elevate toroot
- Obtained and crack the hash of
marcus
from local MySQL, which gave me a shell on the main box.
- Inside as
marcus
;- Global execute permission on
/var/lib/docker
(CVE-2021-41091) - Exploit it to gain code execution as
root
- Global execute permission on