Introduzione all'analisi del firmware di una telecamera IP Reolink

I dispositivi di tipo embedded sono sempre più diffusi e in modo particolare una categoria di dispositivi va ultimamente per la maggiore: IoT (Internet Of Things). Negli ultimi decenni, mai come d’ora si è assistito ad una evoluzione della domotica, partendo da semplici lampadine e arrivando a stampanti connesse con il cloud.

L’evoluzione però ha portato con sé anche alcuni svantaggi, tra cui la perenne necessità di essere connessi ad internet ed un aumento della potenziale superficie di attacco. Temi come la sicurezza informatica e la privacy sono molto importanti per evitare di rendere la tua vita pubblica, anche se molti costruttori di dispositivi IoT sembrano ignorarli.

In questa serie di articoli che pubblicherò a cadenza settimanale, vorrei analizzare in profondità il funzionamento tecnico di una videocamera IP dell’azienda ReoLink per comprendere meglio i potenziali rischi di un dispositivo IoT. Partendo dai dettagli di livello più basso e arrivando fino all’interfaccia utente, andremo a spiegare come è stata creata e sviluppata tale telecamera. Iniziamo allora ad esplorare la telecamera IP.

I Dispositivi Embedded

Per incominciare ad analizzare un firmware, è necessario introdurre un paio di nozionistica riguardo i dispositivi embedded. Che cosa sono e perché sono stati chiamati così?

Possiamo identificare due grandi categorie nei dispositivi di tutti i giorni (elettrodomestici, il tuo cellulare, computer, server): quelli che sono progettati per uno scopo specifico e quelli denominati general-purpose (ovvero ad uso generale). I dispositivi che sono progettati per un specifico obiettivo sono ad esempio elettrodomestici, domotica, fotocamere, stampanti, impianti di riscaldamento. In questi casi, è possibile identificare un solo scopo: nel caso del forno a microonde, il dispositivo dovrà solo scaldare alimenti, non sicuramente mostrare un film.

Invece i dispositivi general purpose, come computer, cellulari, smartwatch, sono macchine che possono soddisfare qualsiasi tipo di compito: dallo scrivere un’email a guardare un film. Il loro scopo dipende dall’uso che l’utente vuole farne. Si può programmare, guardare un film, comporre musica e molto altro.

Generalmente i dispositivi specifici hanno risorse poco performanti, di unità molto minore rispetto a ciò che ci aspettiamo dai dispositivi general-purpose. La ragione principale per cui hanno poche risorse disponibili è data dal fatto che sono concepiti per un solo scopo, quindi hanno un solo task da svolgere. La loro progettazione è molto critica e richiede molta precisione per evitare inutili dispendi di tempo e denaro.

Tali dispositivi sono spesso chiamati dispositivi embedded (dall’inglese immerso, ma in Italiano si chiamano anche dispositivi integrati) perché sono “immersi” nella realtà: svolgono attività e lavori ben specifici in contesti fisici. Pensiamo per esempio quanti chip potremo trovare in una casa: impianto di aria condizionata, domotica per accendere/spegnere una lampadina, sistema di antifurto, elettrodomestici. Figuriamoci in ambienti più complessi come un automobile (centraline, autoradio) e industrie (catena di montaggio, sensori).

Tutti i dispositivi sono sempre basati sull’architettura di Von Neumann; quello che in realtà varia e fa la differenza è il tipo di architettura (16 bit/32 bit/64 bit e ARM/MISP/Coldfire) e le risorse hardware disponibili. Inoltre, i dispositivi embedded non lavorano mai in isolamento: di solito sono configurati per lavorare e portare a termine un compito che dipendono da informazioni di altri sistemi (esempio: controllore del riscaldamento che controlla la pompa di calore).

Le risorse limitate e il fatto di dover comunicare con altri sistemi in modo standard sono due delle sfide più complesse che un progettista di dispositivi embedded deve affrontare. In aggiunta, c’è un altro sottile problema trascurato ma venuto alla luce recentemente.

Alla fine del millennio, diverse persone teorizzarono l’applicazione della connessione Internet a dispositivi embedded, chiamando il concetto “Internet Of Things”. Anche se, volendo essere precisi, in pratica erano già stati sviluppati dei dispositivi connessi ad internet già nei primi anni 80. Uno dei primi dispositivi embedded era una macchina per la distribuzione di bevande (The “Only” Coke Machine on the Internet), situata presso la Carnegie Mellon University che era collegata ad Internet. I programmatori si connettevano alla macchina attraverso la rete internet per verificare se ci fosse stata una bevanda disponibile.

Dalla creazione del concetto - nei primi anni del 2000 - i dispositivi IoT cominciarono a diffondersi, prima nelle industrie, e poi nelle abitazioni di tutti noi. Grazie a vaste campagne di marketing, diversi dispositivi embedded entrarono nelle nostre case: allarmi, stampanti, televisori, serrature intelligenti. Non è però tutto rosa e fiori come gli esperti del marketing vogliono far credere.

Con l’introduzione della rete ai dispositivi embedded, diverse sfide emersero e alcune sono ancora oggetto di discussione tutt’oggi. La mancanza di protezione, il ciclo di vita breve del software (con 1 aggiornamento in 5 anni), protocolli di sicurezza proprietari e il mantra “security by obscurity” fanno i dispositivi IoT una ghiotto obiettivo per gli attaccanti che cercano di entrare in una infrastruttura. Inoltre, la dipendenza dal costruttore costituisce un punto di centralizzazione che potrebbe essere un problema quando il costruttore cessa di esistere (cessione della società/dissolvimento). Anche problemi tecnici a datacenter, server proprietari e infrastrutture possono impattare negativamente l’esperienza dell’IoT. È fantastico non riuscire ad entrare in casa solo perché AWS nella tua zona è momentaneamente giù, giusto?

Puntualizziamo che la categoria Internet of Things è una sotto categoria dei dispositivi embedded: non tutti i dispositivi che vediamo in giro per casa sono collegati ad internet (per fortuna). Non è però il caso della telecamera IP di Reolink.

Serie di post

Ecco la tempistica dei prossimi articoli riguardanti questa serie, ho cercato di dividere in diverse sezioni le tematiche che vorrei affrontare. Il mercoledì di ogni settimana rilascerò un nuovo articolo, per circa 12 settimane.

Questo indice verrà aggiornato appena nuovi articoli verranno rilasciati.

Per evidenziare tutti i problemi riguardanti l’IoT, ho deciso di prendere un firmware da un costruttore ben conosciuto ed analizzarlo passo dopo passo manualmente per comprendere meglio come funzionano i dispositivi embedded e quanto effettivamente possano essere sicuri.

La mia indagine incomincia durante un sabato piovoso approfondendo la telecamera ReoLink RLC-810 A, un “gioiello” - o così dicono - di telecamera IP PoE (Power over Ethernet). Una telecamera IP è una telecamera connessa ad Internet, raggiungibile attraverso un qualsiasi browser ed un indirizzo IP (prende il nome dal protocollo del livello Rete, ovvero IP, Internet Protocol).

Prima di ottenere il firmware, cerchiamo di analizzare l’architettura hardware per avere una panoramica generale sulle funzionalità. Proviamo quindi a leggere le specifiche rilasciate dal produttore che ci saranno sicuramente utili in futuro.

La telecamera supporta video 4K (registrati su scheda microSD con dimensione fino a 256GB), rinosce persone o veicoli che si muovono tramite l’intelligenza artificiale e può registrare anche l’audio tramite un microfono posto all’interno del dispositivo. È alimentata da PoE, un opzione che permette di alimentare un dispositivo via cavo ethernet: permette quindi di avere un unico cavo dalla telecamera alla sorgente di corrente elettrica/rete internet. Inoltre è equipaggiata con un sensore CMOS 1/2.49’’ che permette di registrare video con risoluzione 3840x2160 (8 MegaPixel).

Oltre a questo, Reolink millanta di avere 18 led IR e una visione fino a 130 piedi dal punto in cui la telecamera sta riprendendo. Si collega in modo intelligente sia a Google Assistant e Alexa e può essere comandata da applicazione Android o iOS. Come riusciamo ad ottenere questo tipo di funzionalità? Che tipo di protocolli la telecamera sta usando? Considerando che una sola telecamera costa attorno ai 100 euro, avranno considerato la sicurezza oppure è rimasta in secondo piano?

Dai documenti presentati al cliente, non è stata data alcuna informazione aggiuntiva sul tipo di architettura hardware (CPU, RAM) o sulla sicurezza del dispositivo. Solo il software può rivelare indizi su cosa effettivamente ci sia all’interno dell’hardware. Non resta che iniziare a studiare il firmware dentro la telecamera.

La parte software

In questa sezione, cercheremo di approfondire la prima parte della nostra analisi introducendo lo strumento Binwalk e iniziando ad ottenere i file di configurazione del dispositivo.

I dispositivi embedded di fascia customer, siano essi collegati ad internet o meno, possono essere confrontati come funzionalità ed architettura ad un computer general-purpose. Hanno una CPU che serve al sistema operativo per elaborare informazioni e una RAM in cui posizionare tali dati. In aggiunta, spesso hanno uno spazio di archiviazione esterno (abitualmente una microsd) che è montata come memoria secondaria e al cui interno è situato il sistema operativo.

Ricordiamo che l’avere pensato ad un dispositivo embedded come un computer non è sempre vero (pensiamo per esempio ad un System on a Chip modificato), ma è generalmente dato per scontato in quanto i dispositivi devono avere un costo di progettazione relativamente basso. Tale vantaggio consente al costruttore di produrre tali dispositivi su ampia scala e in serie per avere un ampio margine di quadagno. Per questo motivo, i produttori cercano di riutilizzare architetture e schemi hardware già esistenti (con strumenti già pronti) in modo da risparmiare risorse e tempo.

Nella maggior parte dei casi, la parte software è costituita da un’immagine di dimensione minima (da qualche MB a centinaia di MB) di un sistema operativo basato su Unix o Linux. Tale distribuzioni sono equipaggiate con alcuni binari custom dell’azienda che costituiscono il controllore vero e proprio del IoT, come nel caso della videocamera Reolink.

Concentriamoci quindi sulla parte software. Per iniziare la nostra indagine, abbiamo due principali opzioni: cercare di ottenere il firmware dalla casa produttrice, oppure recuperare l’immagine del firmware da una telecamera “manualmente”. In realtà, abbiamo preferito la prima opzione perché risulta molto più semplice rispetto ad aprire la telecamera IP. All’interno della pagina “Download center”, oltre ai manuali e le istruzioni per l’uso, sono presenti anche gli aggiornamenti firmware scaricabili come file zip.

Ho scaricato quindi la versione v3.1.0.956_22041503, versione rilasciata il 18 Aprile 2022. Guardando la changelog e le diverse versioni disponibili, 6 versioni sono state rilasciate nell’ultimo anno e tutte sono state accompagnate da numerosi cambiamenti. Sulla carta, ReoLink sembra promettere bene.

Scarichiamo il file zip del firmware tramite il comando wget o curl:

wget https://url-of-firmware-reolink/firmware-rlc-810a-v3.1.0.956_22041503.zip

e procediamo alla scompattazione:

unzip firmware-rlc-810a-v3.1.0.956_22041503.zip

Il comando ls che serve per vedere i file all’interno della cartella mostra due file: il primo è un file .pdf che illustra il procedimento per fare l’aggiornamento del firmware, il secondo invece è il file .pak che contiene effettivamente il firmware.

Disclaimer: un’analisi estesa di un qualsiasi firmware richiede un investimento abbastanza ampio di risorse e tempo. Ho dedicato settimane a questa serie da articoli ma sono conscio che questa indagine sia lontana dall’essere perfetta. Se trovare errori di battitura, sviste tecniche, scrivetemi un’email.

Analisi attraverso BinWalk

Un veloce file sul firmware non evidenzia chissà che tipo di file, restituendoci un semplice “data” (l’utility file non è riuscita quindi ad identificare il tipo preciso di file). Sappiamo che l’estensione .pak, inoltre, viene utilizzata abitualmente per firmware, backup e molto altro, ma non identifica un preciso tipo di file.

La nostra indagine potrebbe concludersi qui oppure andare avanti con una noiosa scrittura di codice volta ad analizzare ogni singolo byte per capire che tipo di file è. Per nostra fortuna, una utility chiamata BinWalk permette di agevolare gran parte del lavoro, analizzando ed estraendo il firmware.

Binwalk è uno strumento scritto in Python da ReFirmsLabs (acquistata di recente da Microsoft) e riesce ad identificare le parti di un file che corrispondono ad una data estensione, tentando un’estrazione. Ricordiamo infatti che pur essendo Binwalk un prodotto completo, talvolta potrebbe fallire (se il firmware è particolarmente offuscato, crittografato oppure costruito in modo da non permetterne l’estrazione).

Ogni file ha comunemente all’inizio una serie di byte scelti a tavolino dagli sviluppatori dell’estensione file per associare un file apparentemente sconosciuto ad un tipo preciso di file. Questa serie di byte viene chiamata file signature oppure magic bytes (esempio 45 50 per i binari PE). La principale caratteristica di Binwalk sta nella cosiddetta signature scanning, ovvero Binwalk confronta per ogni coppia di byte la lista di signature già conosciute. Se effettivamente BinWalk conosce la signature associata al file, è possibile provare l’estrazione del tipo del file riconosciuto (un file zip per esempio).

Per chi fosse interessato ai dettagli, Binwalk utilizza il formato libmagic per descrivere i magic già conosciuti. Questo permette di creare, aggiornare e modificare la lista dei magic bytes con molta facilità. Lo stesso formato viene anche utilizzato per l’utility file.

Binwalk diventa molto utile anche nel caso di un firmware o un file pesantemente offuscato. Quando le informazioni sono pesantemente offuscate non seguendo una certa logica, l’entropia di alcune sezioni risulta essere molto elevata. Specificando l’opzione --entropy, Binwalk permette di visualizzare l’entropia di un file sottoforma di un grafico. Un insieme di comandi completi con cui utilizzare questo potente strumento è disponibile su Github.

Poco spesso viene ricordato: lo strumento è stato creato in modo specifico per i firmware, non come strumento di analisi per file. Perfetto per il nostro caso! Per identificare le varie parti del file e procedere con l’estrazione, Binwalk utilizza un approccio sottile ma intelligente. Per primo, analizza il file con tutte le signature. Successivamente, invece di dividere in modo arbitrario il file in parti più piccole, cerca di fare il parsing dei tipi di file. Con molta probabilità, all’interno degli header di ciascun file è indicata anche la dimensione del segmento o del blocco interessato (in modo specifico questo è vero specialmente per i file system!). Binwalk quindi divide il file in blocchi di dimensioni ben specifiche, ottenute dal precedente passaggio di scanning delle signature e parsing dei file header. Procede quindi con l’estrazione di ogni “blocco” utilizzando altri particolari strumenti scelti in base al tipo di file da estrarre.

Ritorniamo quindi al firmware scaricato, avviamo binwalk specificando il nome del file.

binwalk firmware-rlc-810a-v3.1.0.956_22041503.pak

Il risultato è il seguente:

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
34600         0x8728          Flattened device tree, size: 17375 bytes, version: 17
468491        0x7260B         eCos RTOS string reference: "ecos pat%d, res check sum fail."
469218        0x728E2         eCos RTOS string reference: "ecos %s"
469688        0x72AB8         eCos RTOS string reference: "ecos %s"
477499        0x7493B         CRC32 polynomial table, little endian
479095        0x74F77         CRC32 polynomial table, little endian
480119        0x75377         CRC32 polynomial table, little endian
509401        0x7C5D9         LZO compressed data
624319        0x986BF         uImage header, header size: 64 bytes, header CRC: 0x7B9F6E31, created: 2021-06-19 06:29:15, image size: 3153472 bytes, Data Address: 0x8000, Entry Point: 0x8000, data CRC: 0xD7FC213, OS: Linux, CPU: ARM, image type: OS Kernel Image, compression type: none, image name: "Linux-4.19.91"
624383        0x986FF         Linux kernel ARM boot executable zImage (little-endian)
637815        0x9BB77         LZ4 compressed data, legacy
649910        0x9EAB6         LZ4 compressed data, legacy
722627        0xB06C3         SHA256 hash constants, little endian
1151908       0x1193A4        Certificate in DER format (x509 v3), header length: 4, sequence length: 774
2580562       0x276052        Certificate in DER format (x509 v3), header length: 4, sequence length: 536
3049852       0x2E897C        AES Inverse S-Box
3486531       0x353343        Base64 standard index table
3711491       0x38A203        LZ4 compressed data, legacy
3777855       0x39A53F        UBI erase count header, version: 1, EC: 0x0, VID header offset: 0x800, data offset: 0x1000

Molto interessante! L’analisi del file si è rivelata efficace. In modo particolare, possiamo osservare come Binwalk cerchi la signature ed addirittura cerca di interpretare il file header. Per ora non ci preoccupiamo di esaminare in modo specifico tutti i dati, anche se alcuni destano subito all’occhio. Per chi non ha esperienza con i tipi di file e in particolare i file system, può incollare ogni tipo di file in un motore di ricerca e ricavare più informazioni.

Binwalk ha elencato per ogni tipo di file anche l’offset, ovvero la posizione in byte che ricopre il tipo di file. Questo ci sarà utile successivamente per poter estrarre in modo manuale i file (e come cartina tornasole per Binwalk). Attraverso la signature scanning, siamo riusciti ad estrapolare le prime informazioni dal firmware. Per ora non ci preoccuperemo di esaminare in profondità il formato file .pak.

In modo particolare siamo interessati ai seguenti tipi di file:

  • Flattened device tree: struttura dati che contiene la configurazione virtuale della macchina.
  • uImage header: un immagine che ha un wrapper U-Boot che include il tipo di sistema operativo e le informazioni sul loader. Ci sono le prime informazioni sull’architettura, ARM, Little Endian, che monta un OS basato sul kernel Linux versione 4.19.91.
  • Linux kernel ARM boot executable zImage: loader del sistema operativo.
  • UBI erase count header: un tipo di header specifico per l’UBI File system.

Se alcuni di questi termini sembrano abbastanza sconosciuti, non disperate. Nel prossimo post, approfondiremo la fase di boot e le varie componentistiche del sistema operativo (u-boot), Linux, in modo da estrarre il firmware ed iniziare l’analisi. A presto con un nuovo articolo!