Why Camera Security Matters
Security cameras remain exposed online in 2025. Simple exploits work across firmware versions, making them botnet targets. Military reports link camera hacks to logistics tracking. Ransomware groups use cameras to pivot inside networks. Lazar analyzed three Dahua cameras and one XVR. Firmware was needed to assess security.
Extracting Firmware: Online and Offline
Firmware can be downloaded from the vendor website, obtained via UART, or intercepted from an update. For two cameras and the XVR, Dahua provided firmware online. For the third camera, the flash chip had to be desoldered and read with a Bus Pirate. FlashROM utility failed. Lazar wrote a Python script using datasheet commands. The chip yielded the firmware.
Reversing the Bootloader to Find Encryption Keys
Extracted archives contained files like web.squashfs, but binwalk only found U-Boot headers and high entropy. Files appeared encrypted. The bootloader (U-Boot variant) was unencrypted. Lazar loaded it in Ghidra and searched for AES S-box references. Functions found: firmware_get_key, set_key_factors, set_flags, uboot_encrypt_file. Key derivation uses hardcoded bytes concatenated with the processor name. Three hashing functions were SHA-256, deduced via constant matching and ChatGPT elimination. The 32-byte hash was XOR-folded to 16 bytes for the firmware key.
Decrypting the Filesystem with AES-256 CBC
The key factors step uses hardcoded buffers and AES tables to derive a 32-byte AES key. Mode is AES-256 CBC. IV comes from two loops: bytes 0x20-0x30 and 0x23-0x33. Plaintext derived from two hardcoded buffers. Resulting ciphertext’s last 16 bytes combine with the firmware key. Decryption processes 32 blocks at a time; some blocks are skipped and left as plaintext. This explains why partially encrypted data contained strings and code. The filesystem image had a 64-byte header with a size field. Lazar carved the bytes and decrypted. Binwalk extracted the full filesystem.
Exploit 1: HTTP Heap Overflow to Root
The main binary (sonia or challenge) handles 10-16 protocols on the same port. HTTP handler RPC2_UploadFile had no authentication. It misused strncpy: used string length instead of buffer size. A 0x34-byte overflow overwrites a session structure’s function pointer. Token cleanup called that pointer. Lazar replaced it with system(). Crashes printed registers via the TX pin. After 15 crashes, control was achieved. TFTP downloaded a shared library; LD_PRELOAD granted root.
Exploit 2: Stack Buffer Overflow via Host Header
VIF endpoints getCapabilities and getServiceCapabilities copied the Host header without size checking if a square bracket was present. Stack buffer overflow. Lazar controlled seven registers (R4-R11). Code was not position-independent; only one gadget allowed due to null bytes. A gadget with matching epilogue was found: stores R7 into R5. Over 10-15 requests, payload was written into BSS. Then system() gadget with payload address in R6. TFTP and LD_PRELOAD gave root.
Notable Quotes
Those blocks were never encrypted, just partially. Alexandru Lazar · ▶ 12:46
The first six bytes will be replaced with a processor name. Alexandru Lazar · ▶ 05:57
If you only check the open ports with LMAP, for example, you will only find three open ports. Alexandru Lazar · ▶ 13:55
We had a 20 megabytes binary, so we had plenty to choose from. Alexandru Lazar · ▶ 23:53
Kudos to them. Alexandru Lazar · ▶ 25:34
Key Takeaways
- Reversed Dahua U-Boot to extract AES-256 CBC encryption keys for firmware.
- Found two unauthenticated code-execution vulnerabilities: heap and stack overflows.
- Used TFTP and LD_PRELOAD to bypass kernel signature checks and gain root.