Come Hackerare il protocollo di una lampadina WiFi

Ormai la domotica appartiene al nostro vivere quotidiano e facilmente avremo in casa una lampadina WiFi controllabile da qualche app del nostro cellulare o da un gateway hardware come Alexa, Google Assistant e tanti altri.
Ne esistono tantissime, ognuna di marche e modelli diversi, alcune controllabile solo in tonalità di bianco, altre sono a colori RGB, altre ancora in entrambe le modalità (RGBW). In questo articolo analizzeremo a fondo i messaggi che vengono scambiati tra l’app del nostro cellulare e una tra le lampade WiFi più usate, cercando di capire il protocollo usato e provando a riprodurre gli stessi messaggi per controllare la lampadina da PC e successivamente dall’ormai famoso chip ESP8266, con il quale saremo in grado di accendere la lampadina e cambiarne il colore a nostro piacimento, senza dover necessariamente usare l’app del cellulare o sfruttare server esterni centralizzati.
Il procedimento che andremo ad illustrare ci porterà all’interno dei pacchetti TCP che contengono i comandi di pilotaggio della lampadina, navigando tra i vari byte per cercare di capirne il significato ed intervenire per modificarli opportunamente e prendere il controllo della lampadina stessa senza dover dipendere dalla specifica app fornita in dotazione. Ovviamente ad un certo punto dovremo scendere in dettagli che sono specifici solo per quella particolare lampadina che abbiamo utilizzato, ma con questo articolo vogliamo illustrare un processo che potrà essere applicato anche su altri prodotti WiFi.
Stiamo parlando di lampadine a LED che possono essere regolate nelle varie tonalità di colore (RGB), o solo nel bianco (W) o in entrambe le modalità (RGBW), nel nostro caso abbiamo usato un tipo di lampadina non brandizzata (quindi esternamente non ha presenta alcun marchio visibile) disponibile da Futura Elettronica con il codice LEDWIFIBULB. Si tratta di una lampadina prodotta da “Tuya Smart” una grossa compagnia cinese specializzata nella produzione di hardware IoT, che quindi si occupa, non solo di illuminazione, ma di più svariati dispositivi per la casa come condizionatori, interruttori, prese intelligenti, ecc..
Generalmente, un po’ in tutte le lampadine, si può intervenire nella luminosità e nella saturazione per quanto riguarda il colore mentre nella modalità luce bianca si potrà intervenire nella luminosità e nella temperatura.
Ogni lampadina presenta un’app di riferimento (nel nostro caso SmartLife) con la quale viene, in una prima fase associata al nostro router, e successivamente controllata in ogni suo aspetto.
Con questa app possiamo anche creare scene ed effetti particolari ed impostare timer di accensione e spegnimento. In realtà possono esistere molte altre app per controllare queste lampade, come TuyaSmart, TuyaApp, FamilyCloud che, anche se apparentemente sembrano pressoché identiche, differiscono per la modalità con cui inviano comandi alla lampadina; alcune ad esempio usano server cinesi centrali con cui scambiano comandi tramite protocollo MQTT o Web API. Esistono poi anche diversi plugin in rete (quasi per ogni tipo di lampadina) per far in modo che esse possano essere associate a numerose piattaforme di assistenza domotica come Home Assistant, OpenHab, Domoticz e tante altre che sono sviluppate per Raspberry Pi, e che possono fornire spunto di analisi.

Primi passi

Il nostro obiettivo è quello di prendere il controllo della nostra lampadina inizialmente da PC (per comodità di intervento) e successivamente da un microcontrollore senza usare nessuna app, anche se la useremo per la nostra analisi. Prima di tutto installiamo la nostra lampadina, associandola al nostro router, secondo le istruzione del produttore, come da “normali” utilizzatori.
Solitamente si tratta di una particolare sequenza di accensione e spegnimento della lampadina in modo che quest’ultima entri in modalità configurazione. In questa fase il modulo WiFi interno alla lampadina entra in modalità Access Point, venendo a comportarsi come un router, con una proprio nome e password; il cellullare cercherà in automatico questa rete WiFi per connettersi ad essa. Ovviamente questa connessione è solo temporanea perché il nostro cellulare perderà la rete correntemente in uso e non potrebbe più connettersi in Internet, ma serve esclusivamente per trasferire alcuni dati alla nostra lampadina, come ad esempio il nome della rete del nostro router e la password. Una volta configurato, il modulo WiFi, torna in modalità Station, ma con le nuove informazioni acquisite, potrà connettersi al nostro router e quindi anche alla rete internet. Fin qua nulla di particolare, ma siamo già in grado di ottenere informazioni sul tipo di lampadina, perché nella fase di configurazioni, se eseguiamo una scansione delle reti WiFi, potremmo trovare il nome del modulo della lampadina; se ad esempio, dovesse iniziare con la stringa ESP seguito da qualche numero, capiremmo (come nel nostro caso) che all’interno della nostra lampadina si trova proprio un modulo ESP8266 o un ESP32 ed è un primo passo per capire con quale modulo abbiamo a che fare.

App TPacketCapture

A questo punto, dopo aver verificato che con l’app standard sul cellulare, riusciamo ad accendere e cambiare colore (o luminosità di bianco) della nostra lampadina, possiamo indagare sui pacchetti di rete che questa app invia alla lampadina.
Per fare questo ci vengono in aiuto alcune app per cellulare, che memorizzano su file, tutto il traffico di rete tra cellulare e mondo esterno, sia in entrata che in uscita. Hanno solitamente un pulsante di start, uno di stop e la possibilità di salvare il file nella memoria interna. Nel nostro caso abbiamo usato TpacketCapture, come mostrato in Fig. 1, ma ne esistono diverse.
Quindi come prima cosa, dopo aver fatto partire l’ acquisizione, apriamo l’ app specifica della lampadina e premiamo il comando per accendere la lampadina; stoppiamo acquisizione, recuperiamo dal cellulare il file appena generato (solitamente un file .pcap) e lo analizziamo su PC tramite il programma WireShark uno dei più conosciuti analizzatore del traffico di rete, scaricabile gratuitamente a questo indirizzo.

Fig. 1

Wireshark

Ovviamente nel nostro file sarà presente tutto il traffico di rete e non solo quello generato dalla nostra app, ma con Wireshark possiamo applicare alcuni filtri per visualizzare solo quello interessato.
Innanzitutto dovremmo conoscere l’indirizzo IP che il nostro router ha assegnato alla lampadina ed al nostro cellulare e questo si può facilmente ottenere dalle impostazioni del nostro router; quindi imposteremo un filtro del tipo: ip.dest == 192.168.1.5 (dove l’ indirizzo IP sarà quello della lampadina) e verranno visualizzati i pacchetti TCP, solitamente più di uno, inviati dal cellulare alla lampadina (Fig. 2) che possiamo analizzare singolarmente.

 

Fig. 2

Se siamo fortunati, questi dati potrebbero essere già in chiaro e quindi potremmo leggere alcune stringhe di testo, magari già esplicative, che rappresentano il comando inviato alla lampadina; in questo caso il lavoro è praticamente già finito anche perché alcune lampade WiFi in commercio forniscono la possibilità di controllare le proprie lampade e rendono pubblici i vari comandi nella sezione developer del proprio sito. Basterà incapsulare i vari comandi in un pacchetto TCP ed inviarlo alla lampadina nelle modalità che vedremo più avanti.
Se invece non siamo così fortunati ed i dati inviati sono in formato binario, occorrerà investigare ancora per cercare di capire il formato.
Potrebbe esserci anche il caso in cui non riusciamo a vedere nessun pacchetto TCP inviato alla lampadina, questo potrebbe essere dovuto al fatto che l’app si appoggia direttamente a server esterni ed invii messaggi alla lampadina attraverso essi usando alcuni protocolli come ad esempio MQTT. In questo caso si consiglia di scaricare altre app compatibili o versioni precedenti della stessa app in cui la comunicazione avviene ancora tramite traffico TCP.

Duplicazione comandi

Torniamo ora al caso in cui i pacchetti TCP che stiamo esaminando su Wireshark siano in formato binario; essi sono quelli che hanno fatto accendere la nostra lampadina e anche se non sappiamo ancora cosa vogliano significare i singoli byte che li compongono, possiamo comunque replicarlo dal nostro PC ed, in seguito, da un ESP8266.
Ogni linguaggio di programmazione (come C++, C#, python, java) ha le proprie funzioni primitive per invio e ricezione di pacchetti tcp e udp che possiamo utilizzare per il nostro scopo. Basterà conoscere l’ip e la porta (anch’essa visibile tramite Wireshark) della lampadina ed inviare lo stesso messaggio, o, per sicurezza, la stessa sequenza di messaggi contenuti nei pacchetti tcp che abbiamo ritrovato su Wireshark.
Per farlo ci viene in aiuto proprio l’interfaccia grafica di Wireshark che permette di copiare negli appunti, tramite previa selezione dei dati e poi “Copy Byte HexStream” (come mostrato in Fig. 2) solo la parte dati del pacchetto tcp verso la lampadina, quindi quello che chiameremo payload e che è privo di tutte gli header del protocollo tcp. Tale copia è in formato testo e rappresenta una stringa di byte consecutivi in formato esadecimale, quindi dal momento che solitamente queste primitive operano su array di byte, occorrerà effettuare una opportuna conversione.
Nel nostro caso useremo c# con l’IDE di Visual Studio, ed il caso specifico di invio di un messaggio TCP è visualizzato nel Listato 1.
In particolare il parametro che passiamo alla funzione è un array di stringhe perché gli passeremo tutti i messaggi TCP letti da Wireshark.
In seguito vedremo che in realtà ne può bastare solamente uno.

Listato 1 – Codice C# per invio di un pacchetto TCP

public int SendMessageTCP(string[] stream)
{
Thread t = new Thread(new ThreadStart(ListenData));
t.Start();

try
{
IPAddress ipAddress = IPAddress.Parse(_ipLamp);
IPEndPoint remoteEP = new IPEndPoint(ipAddress, _portLamp);

// Create a TCP/IP socket
if (senderTcp == null)
{
senderTcp = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
senderTcp.Connect(remoteEP);
Console.WriteLine(“Socket connected to {0}”, senderTcp.RemoteEndPoint.ToString());
}

for (int i = 0; i < stream.Length; i++)
{
string msg = stream[i];
byte[] msgbytes = convertStreamHex(msg);

senderTcp.BeginSend(msgbytes, 0, msgbytes.Length, SocketFlags.None, new AsyncCallback(SendCallBack), null);
}

}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
return -1;
}
return 0;
}

 

Associamo questo codice ad un pulsante che chiameremo ad esempio, “Turn On” e verifichiamo che premendolo si accenda la lampadina.
Ora si possono ripetere questi passaggi per lo spegnimento della lampadina, e successivamente per un determinato colore e per i vari comandi a cui siamo interessati, uno alla volta.
Questa non è di sicuro la soluzione ottimale e versatile per una serie di motivi; intanto si tratta di comandi cablati nel codice, potrebbe andare ancora bene se volessimo solo accendere e spegnare la lampadina con un colore fisso, ma se volessimo scegliere anche solo tra una decina di colori dovremmo inviare pacchetti TCP preconfezionati che comunque occuperebbero molto spazio in memoria, specialmente quando andremo a fare il porting su un microcontrollore in cui lo spazio diventa una variabile critica.
Inoltre non dimentichiamo che stiamo parlando di pacchetti binari di cui non conosciamo ancora nulla e che potrebbero non avere più lo stesso significato dal momento in cui svitiamo la nostra lampadina dalla sede e la riavvitiamo per esempio in un’ altra stanza; e dover rifare ogni volta questi procedimenti porta comunque via molto tempo.

Progetto C#

Prima abbiamo usato un programma in C# per inviare un pacchetto TCP alla lampadina, ma avremmo potuto anche usare alcuni programmi per PC che permettono invio (e anche ricezione) di messaggi personalizzati TCP/UDP verso qualsiasi altro dispostivo nella rete, come ad esempio PacketSender che può risultare sempre utile per prove veloci, tuttavia se optiamo per una soluzione su misura per la nostra lampadina avremo più vantaggi creando un nostro programma personalizzabile che in futuro potremmo usare e perfezionare anche per altri tipi di lampadine a seconda delle esigenze particolari.
Riprendiamo allora il nostro progetto in C# che ci è servito per i comandi base ed aggiungiamo una serie di controlli per facilitare la comprensione del formato dei byte nei pacchetti TCP sulla base di osservazione, esperimenti, tentativi ed un po’ di fortuna. Sappiamo già come accenderla e spegnerla, vogliamo capire come scegliere un colore a nostro piacimento modificando i byte giusti. Un metodo potrebbe essere quello di sniffare il traffico tra cellulare e lampadina (sempre usando l’app TPacketCapture) mentre cambiamo colore ripetutamente e poi analizzare su Wireshark le differenze tra i vari pacchetti generati, osservare le differenze e provare qualche cambiamento, rinviando il pacchetto modificato. Così, però, saremmo costretti a passare troppe volte tra il nostro programma e Wireshark e allora integreremo tutto nel programma, dandogli direttamente in pasto il file .pcap che verrà convertito internamente in un file di testo con la successione di tutti i pacchetti interessati. Per fare ciò useremo il programma tshark.exe che è contenuto all’ interno della cartella di Wireshark e che praticamente altro non è che la versione da linea di comando di Wireshark.
Il parametri che passeremo a tshark.exe sono:

-Y “ip.dst == 192.168.1.5 && tcp.len==151 && ip.proto== TCP && not tcp.analysis.retransmission” -r color.pcap -w out.pcap -T text -x -P -S *** > color.txt

Dopo aver scritto un po’ di codice saremo in grado di scorrere tra i pacchetti inviati alla lampadina e responsabili del cambio di colore, segnare di colore rosso i byte che cambiano di volta in volta ed osservare quelli che rimangono uguali, cercando di capire se i primi byte possono rappresentare un header fisso e contenere alcuni informazioni quali il tipo di comando, la lunghezza dell’ intero pacchetto e qualche checksum di controllo.
L’ interfaccia del programma, presente in Fig. 3 può sembra complessa, ma è il frutto di test e delle varie difficoltà incontrate e ha preso forma via via sviluppandosi da sinistra a destra. O meglio, inizialmente era presente solo la parte sinistra che e tutto ciò che ci serve per studiare il cuore del payload inviato alla lampadina ed i vari meccanismi per decodificarlo, mentre sulla parte destra ci sono i controlli che invieremo alla lampadina una volta che capiremo come codificare i comandi.

Fig. 3

Utilizzo del Programma C#

Segue una breve descrizione di alcuni controlli del programma C# utilizzato per effettuare vari test sulla lampadina WiFi, in riferimento ai pallini rossi nella Fig. 3.
1) Schermata di testo in cui vengono visualizzati i pacchetti TCP letti dal file pcap (precedemente acquisiti da wireshark o TpacketCapture su cellulare) dopo averli caricati dalla voce di menù “File”. Il pacchetto visualizzato può essere rinviato alla lampadina con pulsante “Send Original” o modificato testualmente per poi inviarlo con pulsante “Send Changed”
2) Casella di testo in cui viene trasferito solo il payload del pacchetto in seguito alla pressione del tasto “ToStream”. Questa casella di testo verrà inoltre popolata in automatico con la risposta della lampadina ai vari comandi.
3) Casella di testo in cui viene caricato il messaggio decodificato dal payload in seguito alla pressione del tasto “Decrypt”. Ovviamente se si volesse decodificare un altro payload è possibile copiarlo direttamente nella casella di testo 2.
4) Schermata di testo in cui viene mostrata la stringa di testo in formato json in modalità più facilmente leggibile, in seguito alla pressione del tasto “Parse”. Premendo il tasto “UpdateC” i valori contenuti verranno letti e gli slide del colore (RGB e HSV) sulla parte destra verranno aggiornati di conseguenza
5) Casella di testo che contiene la stringa di comando per regolare il colore della lampadina.
Può essere modficato a mano, ma si aggiorna in automatico appena vengono modificati gli slide del colore (RGB e HSV).
Premendo il tasto “Change color” a fianco, verrà aggiornato di conseguenza il comando nella casella 6, pronto per essere inviato.
6) Casella di testo che contiene il comando da inviare alla lampadina per cambiare colore. Può essere modificato manualmente o aggiornato in automatico con il testo fornito dalla casella 5, se vogliamo modificare il colore, oppure dai pulsanti “ChangeWhiteBR” e “ChangeWhiteTC”, se vogliamo variare i parametri del bianco (in base alla posizione degli slide BR e TC).
7) Casella di testo in cui viene caricato il payload del pacchetto finale in seguito alla pressione del tasto “Encrypt”. Può essere modificato manualmente inserendo un qualsiasi pacchetto valido.

Premendo il pulsante “Send Command” verrà confezionato un pacchetto TCP con questo pacchetto come payload ed inviato direttamente alla lampadina.
Premendo invece il pulsante “Send Query” verrà inviato un payload con il comando 0x0A che forzerà la lampadina a rispondere con un pacchetto contenente il suo stato, che sarà automaticamente mostrato nella casella 2 pronto per essere decodificato.
Altri pulsanti di controllo sono:
Pulsante “ON”: invia comando per accendere la lampadina.
Pulsante “OFF”: invia comando per spegnere la lampadina.
Pulsante “White-Mode”: invia comando per passare a modalità bianco.
Pulsante “Color-Mode”: invia comando per passare a modalità colore
Pulsante “REFRESH”: nel caso in cui lo stato fosse error, resetta la creazione del socket di rete
CheckBox Instant Mode: se spuntato invia direttamente un comando alla lampadina sul rilascio della slide H forzando il cambio colore.
Premendo poi i pulsanti “Analyze”, vicino alle caselle di testo 2 e 7, si aprirà una finestra che conterrà nella parte sinistra una suddivisione del pacchetto nei vari campi e nella parte destra una rappresentazione del pacchetto in forma di array da poter usare in un programma in C che useremo per i porting successivi. Premendo la voce di menù “Scan”, si aprirà una finestra con cui il programma si mette in ricezione dei pacchetti UDP inviati da una o più lampade ogni tre secondi e ci permetterà di selezionare quella che vorremo controllare. Sempre dalla voce di menù “File”, abbiamo la possibilità di usare la finestra “Settings” per impostare alcuni parametri essenziali come la directory in cui risiede la nostra installazione di Wireshark (per utilizzare il comando x all’ interno del programma), il DeviceId della lampadina e la Localkey entrambi usati all’ interno dei comandi. Da notare, a tal proposito, come mentre il DeviceID è univoco della lampadina e non cambia mai, la LocalKey cambia ogni volta che la lampadina viene associata al router.
Detto questo, possiamo modificare qualche byte nella textbox dell’interfaccia indicata con 1 ed inviare il nuovo pacchetto così formato alla lampadina tramite pulsante “Send changed”, tuttavia ancora non funziona perché probabilmente cambiando il valore di un byte cambierà anche la checksum o qualche CRC.
A questo punto siamo su PC quindi se avviamo Wireshark facendolo acquisire in tempo reale, vedremo anche la risposta della lampadina con un flag di RST indicante un pacchetto non valido. Dopo ulteriore analisi e tentativi si trova il gruppo di byte sul quale viene calcolato il CRC e confrontato con i quattro byte in fondo al pacchetto.
Si tratta di un CRC a 32 bit ed è facilmente riscontrabile sugli altri pacchetti utilizzando il tool online per il calcolo del CRC che fornisce tutti i tipi di CRC da uno stream di dati. Ora possiamo cambiare qualche byte, ricalcolare il CRC ed impostare quei quattro byte del CRC a quel valore, noteremo che non viene generato RST nella risposta della lampadina, quindi il comando viene accettato, ma ancora nessun cambiamento di colore. L’ulteriore complicazione è dovuta al fatto che i dati sono criptati e come ogni codice criptato occorre una chiave, ma sappiamo che si tratta di una lampadina Tuya e possiamo ottenere qualche informazione in più. Nel frattempo, però, dopo una serie di confronti tra i vari pacchetti, possiamo stabilire in linea di massima la struttura di un pacchetto base (per lampadine Tuya) che risulta essere come in Fig. 4 e come appare anche in Fig. 3 nella finestra “Analyze”.

Fig. 4

Recupero Localkey

Stiamo entrando in una analisi sempre più approfondita e di conseguenza queste procedure diventano sempre più dipendenti dal tipo di lampadina. Altri modelli avranno metodi più o meno differenti per il recupero di queste informazioni, ma una volta compresi questi passaggi, anche se solo per una determinata lampadina, potremmo essere facilitati qualora si presentassero difficoltà con altri modelli. Il modo più convenzionale per il recupero della chiave Tuya (chiamata Localkey) è quello consigliato dalla stessa casa e prevede l’accesso alla sezione developer del sito ufficiale TuyaSmart. Dopo essersi registrati, occorre accedere al menù “Cloud- Link Devices”, creare un progetto nuovo e nella tab “API Groups” abilitare tutte le voci per quel progetto, selezionare il tab “Link devices” by “App Account” come visualizzato in Fig. 5; dopodichè premere sul pulsante “AddAppAccount” e scansionare con l’ app della lampadina (SmartLife o similari) il codice QR che appare a schermo. A questo punto la lampadina viene associata al cloud Tuya, ma per ottenere la localkey occorre eseguire una Web Api verso i server Tuya passandogli alcuni dati che abbiamo a disposizione, come la coppia ClientId – ClientSecret del progetto creato precedentemente sul sito ed il DeviceId della lampadina che la identifica univocamente e che troviamo navigando all’ interno dell’app sotto la voce “Info Dispositivo”. La Web API che ci interessa è una GET come la seguente.
In cui è 3602383098f4abc8b73c è il DeviceId della lampadina e gli altri parametri (ClientId e ClientSecret) sono passati nell’header della richiesta. Per fare questo useremo Postman, un comodo tool gratuito nato proprio per lo sviluppo di api-web e che useremo per questo scopo. Tra i parametri che passeremo nell’ header, c’è anche il “token-access” che è obbligatorio e che ci viene fornito da una Web API di questo tipo.
Con tutti questi parametri otterremo una risposta in formato JSON che conterrà anche la nostra localkey. Insieme al progetto scaricabile dal nostro sito troverete comunque il file da importare in Postman ed avviare questa procedura, cambiando opportunamente i parametri secondo le vostre esigenze; anche perché l’access-token è temporaneo e dopo il periodo di scadenza occorre rieseguire l’API per ottenerne un altro valido.

Fig. 5

Cloud

Abbiamo appena associato la lampadina al cloud Tuya ed abbiamo la localkey che ci servirà per decriptare i pacchetti TCP ma con la stessa localkey e Postman potremmo usare anche le altre WEB API (sia GET che POST) sugli stessi server per prendere il controllo della lampadina esattamente come fa l’app SmartLife. Questo perché tramite il sito Tuya visto in precedenza c’ è anche una pagina di test (API Explorer) che permette di inviare comandi e leggere lo stato dei dispositivi collegati ed ottenere le risposte online. Questi stessi comandi possono poi essere inviati tramite Postman ed in futuro anche da un nostro sito o applicazione web. Noi però, come primo obiettivo, vogliamo decriptare i pacchetti WiFi per controllare la lampadina ed essere svincolati dall’ uso di server esterni che in futuro potrebbero smettere di funzionare, quindi riprenderemo i nostri tentativi per decriptare i nostri pacchetti TCP.

 

 

 

Il Formato del colore in elettronica

In elettronica ed informatica siamo più abituati a rappresentare un colore come composto dalle tre componenti di rosso, verde e blu.
Esistono però anche altri formati, come ad esempio HSV e HSL che non si basano su componenti distinte, ma sulla tonalità (Hue, da cui la lettera H) che varia da 0 a 360 e viene rappresentato proprio come un cerchio.
Partendo dall’angolo zero (colore rosso) e muovendosi lungo la circonferenza attraverseremo linearmente tutti i colori fino a tornare al rosso. Se poi per ogni tonalità mi allontano dalla circonferenza avvicinandomi al centro cambia il valore di saturazione(da 0 a 100) indicato con S) fino a diventare bianco nel centro del cerchio quando vale 0. Se poi a parità di posizione cambio il valore di intensità (varia anch’esso da 0 a 100 e viene indicato con V o con L) posso arrivare fino al colore 0. La differenza tra HSV e HSL sta solamente nel terzo valore che nel primo caso è chiamato appunto Value e quando vale 100 indica il colore pieno per quella tonalità, mentre nel caso di HSL è chiamato Luminosità ed al valore 100 assume colore nero, quindi al valore 50 diventa assimilabile al formato HSV.
Nel nostro caso la lampadina pùo essere controllata in entrambe le modalità, ma essendo il comando del colore una combinazione di entrambi formati (RGB e HSV) è preferibile inviare un comando coerente in cui, quindi, i primi sei caratteri per rappresentare componenti RGB siano equivalenti agli ultimi sette caratteri che rappresentano lo stesso colore in formato HSV.

Decodifica

Riprendiamo allora il programma C# ed aggiungiamo codice e controlli per provare a decriptare i pacchetti acquisiti in precedenza e cercare di capire quale algoritmo di criptazione viene usato dalla nostra lampadina. Ne esistono davvero tanti e con varianti diverse, quello più diffuso è AES (soprattuto da quando il DES si è rilevato debole rispetto a certi attacchi di forza bruta) ed utilizza un sistema di cifratura a blocchi. Ne esistono di diversi tipi, a seconda della dimensione di questi blocchi, ma noi ora abbiamo la localkey (nel nostro caso c7e961ddad19566f) e siccome è lunga 16 byte, quindi 128 bit, dovremmo orientarci tra gli algoritmi a 128 bit. Non sappiamo ancora quale parte del nostro pacchetto corrisponde al messaggio da decriptare, ma possiamo ipotizzare che i primi byte che abbiamo individuato come header (perché contengono alcune informazioni dei dati veri e propri) non ne facciano parte e nemmeno gli ultimi byte che (come illustrato in Fig. 4) sembrano essere il CRC e footer. Per effettuare tutta una serie di tentativi su diversi algoritmi di cifratura e su diversi sottoinsieme del pacchetto ci vengono in aiuto alcuni siti web che rilasciano l’algoritmo di criptazione e decriptazione online in cui si possono modificare al volo diverse variabili. Ad esempio questo sito.

Dopo un po’ di prove otteniamo come output della decodifica una stringa di testo in fomato json che ha tutta l’aria di un comando, scoprendo che l’algoritmo usato è AES-128 in modalità ECB.
La modalità ECB opera considerando ogni blocco come un’unità indipendente e risulta meno sicura di altre (come la CBC) in cui esiste anche una correlazione tra i vari blocchi, ma questo per fortuna, ci evita l’utilizzo di un vettore di inizializzazione che avrebbe portato altre difficoltà.
Alla fine otteniamo una stringa di questo tipo:

{“devId”:”3602383098f4abc8b73c”,”t”:”1613427708”,”dps”:{“1”:false,”2”:”colour”,”3”:79,”4”:0,”5”:”aa08ff00b5ffff”,”6”:”bd76000168ffff”,”7”:”ffff500100ff00”,”8”:”ffff8003ff000000ff000000ff000000000000000000”,”9”:”ffff5001ff0000”,”10”:”ffff0505ff000000ff00ffff00ff00ff0000ff000000”}}

In prima istanza potrebbe sembrare indecifrabile, ma ora possiamo fare diversi cicli di acquisizione con l’app TpacketCapture mentre da cellulare inviamo alla lampadina configurazioni di colore prestabilite e poi, osservando i vari messaggi decriptati, sarà tutto più chiaro. Scopriremo che il parametro “devId” è appunto il deviceId della lampadina, “t” è il timestamp e “dps” è la collezione dei comandi (nominati da 1 a 10) e separati per funzionalità come viene meglio dettagliato nell’apposito riquadro in queste pagine.

 

Codifica

A questo punto, dopo aver appreso il formato dei comandi ed il loro significato, possiamo rieseguire questi passi in maniera inversa e codificare una stringa personalizzata per poi inviare il pacchetto TCP così formato alla lampadina che si comporterà di conseguenza. Riprendiamo nuovamente il programma C#, che completeremo aggiungendo i controlli (visibili nella parte destra di Fig. 3) con i quali potremo inserire manualmente una stringa ed eseguire tutti i passaggi, dalla creazione del pacchetto al controllo CRC e infine alla codifica (utilizzeremo a tal proposito la libreria CryptoStream fornita da Microsoft e configurabile per AES-128 ECB). Per rendere più pratici i test aggiungeremo anche alcune slide con cui selezionare il colore desiderato (sia RGB che HSV) e che andranno a modificare la stringa nella casella 5. Aggiungeremo altre slide per cambiare la tonalità del bianco, due pulsanti per cambiare modalità (bianco o colore) ed infine i pulsanti per mostrare il pacchetto codificato prima di inviarlo sulla rete. In particolare sul rilascio della slide Hue che controlla la tonalità del colore il pacchetto TCP verrà inviato direttamente alla lampadina per provarla velocemente senza dover fare ogni volta tutti i passaggi.
Da notare inoltre come cambiando gli slide per controllare il colore tramite RGB devono cambiare di conseguenza anche gli slide HSV, in modo che la stringa per il comando “5” sia coerente; cambiando solo HSV o solo RGB potrebbero esserci problemi e la lampadina non cambierà colore.

 

Comandi di Controllo

Per la nostra esercitazione abbiamo impartito alcuni comandi esemplificativi alla lampada WiFI, che riportiamo nella tabella in questo riquadro. I restanti comandi sono utilizzati per gestire le scene, gli allarmi e i timer e non vengono ancora trattati in questa sede. Da notare che questi comandi per il colore o per il bianco, possono essere inviati anche a lampadina spenta; verranno normalmente acquisiti da essa e alla successiva accensione assumerà la tonalità di colore o di bianco impostata in precedenza. Allo stesso modo se cambiamo un colore mentre siamo in modalità bianco, non succederà nulla, ma se poi passiamo alla modalità colore troveremo la lampadina accesa col colore impostato precedentemente. Particolare attenzione per il comando “5” che rappresenta il colore sia  n modalità RGB che HSV ed espresso in una stringa in cui i valori vengono rappresentati in esadecimale. Da notare anche il valore minimo della luminosità del bianco e quello del valore V sia 25  0x19) anziché 0; questo non ha una particolare spiegazione, semplicemente è il risultato di test empirici.

 

 

Ricezione messaggi

Finora abbiamo parlato di invio di messaggi verso la lampadina e tutto funziona, ma avendo ormai la possibilità di inviare messaggi dal programma in C# (quindi dal nostro PC) e sniffare i pacchetti scambiati tramite Wireshark con più comodità, possiamo analizzare anche le possibili risposte della lampadina ai nostri comandi; basterà impostare i filtri su Wireshark ed osservare la comunicazione nelle due direzioni.
Noteremo che ad ogni pacchetto inviato, la lampadina risponde con un pacchetto TCP analogo, che potremo copiare e incollare nella casella di testo del nostro programma, eseguirne la decodifica e leggerne il risultato nella casella di testo sottostante. Vedremo che questa altro non è che una stringa json con lo stato della lampadina per gli stessi comandi che abbiamo impostato.
Per rendere tutto integrato nel programma C# abbiamo usato un thread di ricezione che viene attivato dopo l’ invio di un comando e che riceve i pacchetti trasmessi dalla lampadina copiandoli nella stessa casella di testo, pronti per essere decodificati.

Esiste anche un pacchetto particolare, che non ha bisogno di comandi (stringa vuota), ma nell’header, più precisamente nel campo Comando della Fig. 4, deve contenere il byte 0x0A (al posto del solito 0x07 usato per i controlli), tramite il quale la lampadina non esegue nessuna azione, ma risponde inviando un pacchetto in cui la stringa Json decodificata contiene lo stato di tutti i dieci comandi. In realtà, come si può verificare con Wireshark, la lampadina, mentre è spenta, invia sempre, ogni tre secondi un pacchetto UDP in broadcast, ovvero con indirizzo IP di destinazione settato a 255.255.255.255, pronto per essere ricevuto da chiunque, per segnalare la sua presenza nella rete. A quel punto i dispositivi vicini sanno l’ IP verso cui possono mandare i comandi e si potrebbe anche il codificare il pacchetto UDP che, a seconda dei modelli di lampadina, può contenere informazioni più generali come il tipo di prodotto, il modello del dispositivo o la versione.
Questo meccanismo è usato da diversi tipi di lampadine, anche se alcune rimangono silenti fino a che non ricevano esse stesse un particolare pacchetto broadcast che le attivi. È comunque pratica comune usare i pacchetti UDP, solitamente meno affidabili, per mandare informazioni di poco contenuto informativo e ad intervalli frequenti, mentre per i comandi in cui vogliamo essere più sicuri della loro trasmissione si ricorre a protocollo TCP che prevede meccanismi di ritrasmissione più affidabili.

Conclusioni

Abbiamo analizzato questo processo per apprendere qualche meccanismo in più che si cela dietro ai più comuni dispositivi WiFi; questo non vuole essere sicuramente una soluzione universale per tutti i casi perché, ovviamente lampadine di marche diverse avranno un loro protocollo proprietario e, a seconda dei casi, potrebbe essere più o meno complicato, ma imparare a districarsi anche solo con una, può essere un buon motivo per apprendere il funzionamento ed una ottima pratica per quando ci dovremo scontrare con un altro dispositivo.

Allo stesso modo, il programma in C# non ha la pretesa di sostituirsi ad un’app su cellulare sia a livello di utilizzo sia di estetica, ma è stato creato appositamente per analizzare la comunicazione con la lampadina e capire i vari passaggi di codifica per poi eseguire il tutto su un microprocessore dotato di interfaccia di rete in cui la memoria è limitata e le attese per il caricamento del firmware per le numerose prove che sono state richieste durante questo processo, avrebbero allungato di gran lunga i tempi di sviluppo.
Prossimamente eseguiremo il porting su microprocessore e nel prossimo articolo controlleremo una di queste lampadine tramite un ESP8266.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.

Menu