
Tenda Technology Co., Ltd NVR_4H: CH3 v2.1.V27.5.58.6 è stato rilevato contenere una chiave crittografica hardcoded.
ID CNVD: CNVD-2026-25884
Fornitore: Tenda Technology Co., Ltd.
Prodotto: NVR_4H network video recorder (versione hardware CH3V2.1)
Firmware: V27.5.58.6
Classe: CWE-321 — Use of Hard-coded Cryptographic Key
Il firmware NVR_4H memorizza una coppia di chiavi ECDSA nella sua partizione in sola lettura user-x.squashfs (montata in /opt/app/): la chiave privata in /etc/privkey.pem e il certificato self-signed corrispondente in /etc/cacert.pem. Entrambi sono stati generati una sola volta in fase di build e inseriti nell'immagine, quindi ogni dispositivo che esegue la V27.5.58.6 viene distribuito con la stessa chiave privata.
L'immagine del firmware è scaricabile gratuitamente dal sito di Tenda. Chiunque la estragga possiede una chiave privata funzionante per l'interfaccia HTTPS di ogni NVR_4H su questa versione. Un attaccante sulla stessa rete (LAN, Wi-Fi o un dispositivo esposto a Internet) può inserire un proxy tra il browser dell'amministratore e l'NVR tramite ARP spoofing o DNS poisoning, presentare il certificato Tenda autentico con la chiave estratta, e il browser non mostrerà alcun avviso. L'intera sessione è quindi leggibile e modificabile in tempo reale: login admin, token di sessione, credenziali RTSP delle telecamere, configurazione del dispositivo.
| File | Descrizione |
|---|---|
/etc/privkey.pem | Chiave privata EC da 302 byte (P-256) |
/etc/cacert.pem | Certificato self-signed da 802 byte, O=Tenda, OU=Video Surveillance, CN=www.tenda.com.cn |
Il container del firmware è un archivio ZIP all'offset 0xBBB:
# 1. unpack the firmware
binwalk -e ted.bin
cd ted.bin.extracted/BBB
# 2. strip the 64-byte proprietary header
dd if=user-x.squash.img of=pure_system.squashfs bs=1 skip=64
# 3. unpack the filesystem
unsquashfs pure_system.squashfs
# 4. locate the key material
find squashfs-root -name "*.pem"
# squashfs-root/etc/cacert.pem
# squashfs-root/etc/privkey.pem
Per confermare che la chiave privata appartiene al certificato distribuito, esportare la chiave pubblica da entrambi e confrontare:
openssl ec -in squashfs-root/etc/privkey.pem -pubout > pub_from_priv.pem
openssl x509 -in squashfs-root/etc/cacert.pem -pubkey -noout > pub_from_cert.pem
diff pub_from_priv.pem pub_from_cert.pem
# no output
sha256sum pub_from_priv.pem pub_from_cert.pem
# 80b6aa4b9e8f4cd30e857ff5b9bfcf7e0227e268f4d397efdaffe37d4b0e9bcc (both files)
La chiave funziona anche direttamente dall'immagine:
openssl s_server \
-key squashfs-root/etc/privkey.pem \
-cert squashfs-root/etc/cacert.pem \
-accept 4433 -www
# ACCEPT — TLS server starts with no errors
user-x.squashfs è un filesystem compresso in sola lettura, quindi il suo contenuto è identico byte per byte su ogni unità distribuita.
Non esiste alcun provisioning per dispositivo nell'immagine: nessuno script di init, nessun binario openssl, nessuna generazione di chiavi al primo avvio. Le uniche stringhe correlate alla generazione di chiavi nell'intero filesystem provengono da hostapd e wpa_supplicant, che non hanno nulla a che fare con il server HTTPS.
/etc/ all'interno del squashfs contiene solo quattro file, due dei quali sono questo materiale chiave. Entrambi riportano il timestamp di build del squashfs anziché uno di runtime.
Il certificato è X.509 v1, self-signed (issuer = subject = C=CN, ST=ZJ, L=HZ, O=Tenda, OU=Video Surveillance, CN=www.tenda.com.cn), valido dal 1999-12-31 al 2049-12-18, senza SAN e senza estensioni key usage. Il seriale 1c:f2:13:a0:7b:e2:7c:91:63:f3:e0:0c:be:0f:0d:42:2e:6b:e8:69 è fisso e identico su tutti i dispositivi.
La chiave privata estratta, utilizzabile così com'è:
-----BEGIN EC PARAMETERS-----
BggqhkjOPQMBBw==
-----END EC PARAMETERS-----
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIHQLiI/KUzk/hXX4BZVuujlQMit341WWi3sTpLlGQVcaoAoGCCqGSM49
AwEHoUQDQgAEqFt550/3k/nGoYr4CFeRtvDf9HuZpHbb5FecKweJtFH7a5hBNFqq
qckxILVt8KefGENelZgPdEGNU6VcXyTORA==
-----END EC PRIVATE KEY-----
La riservatezza e l'integrità dell'intera interfaccia di gestione HTTPS sono compromesse per ogni dispositivo su questa versione del firmware, nei confronti di chiunque abbia scaricato l'immagine pubblica. Non sono necessari privilegi né interazione dell'utente sul lato target — è sufficiente un MITM passivo. Le credenziali admin rubate danno il pieno controllo del registratore e delle sue telecamere.
Generare una coppia di chiavi univoca per dispositivo al primo avvio e memorizzarla su una partizione scrivibile (ad esempio l'area JFFS2 sotto /opt/sav/), e rimuovere completamente privkey.pem e cacert.pem dall'immagine in sola lettura. A lungo termine, emettere certificati per dispositivo firmati in fase di produzione.