
Questo progetto intende fornire una serie di strumenti per creare, analizzare, inviare, esaminare e decifrare un insieme di pacchetti LoRaWAN al fine di effettuare audit o test di penetrazione sulla sicurezza di un'infrastruttura LoraWAN.
Le implementazioni IoT continuano a crescere e una parte di questa significativa crescita è composta da milioni di sensori LPWAN (low-power wide-area network) distribuiti in centinaia di città (Smart Cities) in tutto il mondo, oltre che in industrie e case. Una delle tecnologie LPWAN più utilizzate è LoRa, per la quale LoRaWAN è lo standard di rete (livello MAC). LoRaWAN è un protocollo sicuro con crittografia integrata, ma problemi di implementazione e debolezze influenzano la sicurezza della maggior parte delle implementazioni attuali.
Questo progetto intende fornire una serie di strumenti per creare, analizzare, inviare, analizzare e decifrare un insieme di pacchetti LoRaWAN al fine di verificare la sicurezza di un'infrastruttura LoRaWAN.
Di seguito, la struttura di questo repository:
|-- tools
|-- UdpSender.py
|-- UdpProxy.py
|-- TcpProxy.py
|-- lorawan
|-- BruteForcer.py
|-- MicGenerator.py
|-- PacketCrafter.py
|-- PacketParser.py
|-- SessionKeysGenerator.py
|-- Loracrack (https://github.com/matiassequeira/Loracrack/tree/master)
|-- utils
|-- DevAddrChanger.py
|-- Fuzzer.py
|-- FileLogger.py
|-- auditing
|-- datacollectors
|-- MqttCollector.py
|-- UdpForwarderProxy.py
|-- analyzers
|-- LafProcessData.py
|-- bruteForcer
|-- LafBruteforcer.py
|-- keys
|-- dataanalysis
|-- LafPacketAnalysis.py
|-- printer
|-- LafPrinter.py
|-- db
|-- __init__.py
|-- Models.py
|-- Service.py
|-- lorawanwrapper
|-- LorawanWrapper.py
|-- utils
|-- jsonUnmarshaler.go
|-- lorawanWrapper.go
|-- micGenerator.go
|-- sessionKeysGenerator.go
|-- scripts
|-- gateway_channel_changer
|-- LoRa-GW-Installer.sh
|-- Continuous-Channel-Switch.sh
|-- LoRa-GW-Channel-Setup.sh
Forniamo diverse opzioni per avere il tuo LoraWAN Auditing Framework funzionante:
tools/, per evitare problemi con il mapping delle porte di Docker.localhost. Vedi le istruzioni sotto per configurare Docker.Queste istruzioni ti permetteranno di ottenere una copia del progetto e delle sue dipendenze sulla tua macchina locale. I comandi seguenti sono per un ambiente basato su Debian:
Clona questo repository: git clone --recurse-submodules https://github.com/IOActive/laf.git
Installa python3:
sudo apt-get updatesudo apt-get install python3.6Scarica e installa le dipendenze python:
sudo pip3 install paho-mqtt && sudo pip3 install sqlalchemy && sudo pip3 install psycopg2-binary &&sudo pip3 install python-dateutilImposta PYTHONPATH e ENVIRONMENT
cd laf && export PYTHONPATH=$(pwd) && export ENVIRONMENT='DEV'Installa e configura golang:
cd ~/Downloadssudo tar -C /usr/local -xvzf YOUR_GOLANG_FILEexport PATH=$PATH:/usr/local/go/binEd è tutto!
Questo approccio evita di gestire l'installazione delle dipendenze e avvia un database PostgreSQL dove gli strumenti salvano pacchetti e dati. Contenitori:
Passaggi:
git clone https://github.com/IOActive/laf.gitcd laf/docker-compose up --builddocker exec -ti laf_tools_1 /bin/bashPuoi controllare i dati nel DB usando pgAdmin:
Prima, accedi a pgAdmin:
Poi, devi aggiungere il server:
Ecco la descrizione delle directory e degli strumenti/funzioni al loro interno.
Lo scopo principale degli strumenti forniti in questa directory è facilitare l'esecuzione di un penetration test su un'infrastruttura LoRaWAN.
Questo strumento è progettato per inviare pacchetti uplink (al server di rete o al gatewayBridge, a seconda dell'infrastruttura) o pacchetti downlink (al packet-forwarder). Opzionalmente, i pacchetti possono essere fuzzati e può essere calcolato un MIC valido.
Argomenti opzionali:
-h, --help mostra questo messaggio di aiuto ed esce
--lcl-port LCL_PORT Porta di origine, es. --lcl-port=623.
--timeout TIMEOUT Tempo in secondi tra ogni pacchetto inviato. Default è
1s. In questo tempo, il mittente ascolterà le risposte.
--repeat Invia il/i messaggio/i più volte
--fuzz-out FUZZ_OUT [FUZZ_OUT ...]
Fuzza i dati inviati alla porta di destinazione (vedi
modalità di fuzzing in utils/fuzzer.py), es. --fuzz-out 1 2.
--key KEY Inserisci la chiave (in formato esadecimale, un totale di 32 caratteri
/ 16 byte) per firmare i pacchetti (calcola e aggiungi un nuovo
MIC). Nota che per JoinRequest deve essere AppKey,
e NwkSKey per i pacchetti Data. Questo non può
essere validato a priori da questo programma. es.
00112233445566778899AABBCCDDEEFF
-a DEVADDR, --devaddr DEVADDR
DeviceAddress da impersonare, fornita in formato esadecimale (8
caratteri totali), es. AABB0011.
--fcnt FCNT Il contatore di frame da impostare nel pacchetto dati dato.
Questo non funzionerebbe in un JoinRequest/JoinAccept poiché
questi pacchetti non hanno un fCnt
Argomenti obbligatori:
--dst-ip DST_IP IP di destinazione, es. --dst-ip 192.168.3.101.
--dst-port DST_PORT Porta di destinazione, es. --dst-port 623.
--data DATA Pacchetto UDP. Si possono anche aggiungere più pacchetti
nell'array "data" alla fine di questo script. Il pacchetto
deve essere una stringa di byte (dovrai fare l'escape dei
doppi apici). ***ESEMPIO*** con il formato packet_forwarder:
--data "b'\x02\xe67\x00\xb8\'\xeb\xff\xfez\x80
\xdb{\"rxpk\":[{\"tmst\":2749728315,\"chan\":0,\"rfch\
":0,\"freq\":902.300000,\"stat\":1,\"modu\":\"LORA\",\
"datr\":\"SF7BW125\",\"codr\":\"4/5\",\"lsnr\":9.5,\"r
ssi\":-76,\"size\":23,\"data\":\"AMQAAAAAhQAAAgAAAAAAA
ACH9PRMJi4=\"}]}'" ***ESEMPIO*** utilizzando il formato
gatevice [GV] inviando in modalità immediata, in BW125 e
freq 902.3 è "b'{\"tx_mode\": 0, \"freq\": 902.3,
\"rfch\": 0, \"modu\": 16, \"datarate\": 16,
\"bandwidth\":3, \"codr\": 1, \"ipol\":false,
\"size\": 24, \"data\":
\"QOOL8AGA6AMCnudJqz3syCkeooCvqbSn\", \"class\": 2}'"
Esempio:
Per inviare un singolo pacchetto ogni 2 secondi a (localhost, 10001) dalla porta 10000, fuzzando casualmente il MIC e il FCounter:
python3 UdpSender.py --lcl-port 10000 --dst-ip 127.0.0.1 --dst-port 10001 --timeout 2 --fuzz-out 4 5 --data "b'\x02\xe67\x00\xb8\'\xeb\xff\xfez\x80\xdb{\"rxpk\":[{\"tmst\":2749728315,\"chan\":0,\"rfch\":0,\"freq\":902.300000,\"stat\":1\"modu\":\"LORA\",\"datr\":\"SF7BW125\",\"codr\":\"4/5\",\"lsnr\":9.5,\"rssi\":-76,\"size\":23,\"data\":\"AMQAAAAAhQAAAgAAAAAAAACH9PRMJi4=\"}]}'"
Questo proxy UDP è principalmente progettato per essere posizionato tra una serie di gateway (packet_forwarders) e un server di rete o bridge di gateway, a seconda dell'infrastruttura in valutazione. Offre anche la possibilità di fuzzare i dati nella direzione desiderata (uplink o downlink)
Argomenti opzionali:
-h, --help mostra questo messaggio di aiuto ed esce
--collector-port COLLECTOR_PORT
Porta del collettore dati del packet forwarder, es. --collector-
port 1701. Vedi
auditing/datacollectors/PacketForwarderCollector.py
--collector-ip COLLECTOR_IP
IP del collettore dati del packet forwarder. Default è
localhost. es. --collector-ip 192.168.1.1. Vedi
auditing/datacollectors/PacketForwarderCollector.py
--fuzz-in FUZZ_IN [FUZZ_IN ...]
Fuzza i dati inviati alla porta dst-port nelle modalità indicate
(vedi modalità di fuzzing in utils/fuzzer.py), es. --fuzz-in 1 2
...
--fuzz-out FUZZ_OUT [FUZZ_OUT ...]
Fuzza i dati inviati alla porta (sorgente) nelle modalità indicate
(vedi modalità di fuzzing in utils/fuzzer.py), es. --fuzz-out
1 2 ...
-k KEY, --key KEY Inserisci una AppSKey del dispositivo (in formato esadecimale, un totale di 32
caratteri / 16 byte) per decriptare il suo FRMPayload e
stamparlo in testo chiaro. Puoi anche inserire la AppKey
se desideri decriptare un dato Join Accept. es.
00112233445566778899AABBCCDDEEFF
-p PATH, --path PATH Percorso del file dove salvare i dati. Se non fornito, i dati
non verranno salvati.
--no-log Non stampare i pacchetti UDP nella console
--no-parse Non analizzare il PHYPayload. Se questa opzione è selezionata,
le librerie Golang di /lorawanwrapper/ non verranno
importate (non è richiesta la compilazione delle librerie golang)
Argomenti obbligatori:
--port PORT La porta locale su cui ascoltare, es. --port 623.
--dst-ip DST_IP IP host di destinazione, es. --dst-ip 192.168.3.101.
--dst-port DST_PORT Porta host di destinazione, es. --dst-port 623.
Esempio:
Per inviare i pacchetti ricevuti sulla porta 1234 a (localhost, 1235) e viceversa. I pacchetti ricevuti sulla porta verranno fuzzati (il devNonce verrà cambiato casualmente) e inoltrati a (localhost, 1235).
python3 UdpProxy.py --port 1234 --dst-ip 127.0.0.1 --dst-port 1235 --fuzz-in 9
Questo proxy TCP è principalmente progettato per essere posizionato tra il server di rete e un broker MQTT. Offre anche la possibilità di fuzzare i dati.
Argomenti opzionali:
-h, --help mostra questo messaggio di aiuto ed esce
--fuzz-in FUZZ_IN [FUZZ_IN ...]
Fuzza i dati inviati alla porta dst-port nelle modalità indicate
(vedi modalità di fuzzing in utils/fuzzer.py)
Argomenti obbligatori:
--lcl-port LCL_PORT La porta locale su cui ascoltare, es. --lcl-port=623.
--dst-ip DST_IP IP host di destinazione, es. --dst-ip=192.168.3.101.
--dst-port DST_PORT Porta host di destinazione, es. --dst-port=623.
Esempio:
Invia e ricevi dati da (localhost, 1884) a (localhost, 1883)
python3 TcpProxy.py --lcl-port 1884 --dst-ip 127.0.0.1 --dst-port 1883
Questa directory contiene una serie di script per analizzare, creare, forzare brute force, ecc. pacchetti LoRaWAN.
Questo script riceve un JoinAccept o JoinRequest in Base64 e prova a decriptare la sua AppKey con un insieme di chiavi possibili che possono essere fornite in un file o generate al volo.
Argomenti opzionali:
-h, --help mostra questo messaggio di aiuto ed esce
-k KEYS, --keys KEYS File contenente un elenco di chiavi, separate da \n. Verrà
utilizzato /auditing/analyzers/bruteForcer/keys.txt di default
--dont-generate Seleziona questa opzione se non vuoi generare chiavi
al volo con le seguenti combinazioni: 1- Combina
il primo byte e gli ultimi quindici byte. es.
AABBBBBBBBBBBBBBBBBBBBBBBBBBBBBB 2- Combina le
posizioni dei byte pari e dispari equamente. es.
AABBAABBAABBAABBAABBAABBAABBAABB 3- I primi 14 byte
in 00 e combina gli ultimi 2. es.
0000000000000000000000000000BA01
Argomenti obbligatori:
-a ACCEPT, --accept ACCEPT
Join Accept in formato Base64 da forzare brute force. es. -a
IHvAP4MXo5Qo6tdV+Yfk08o=
-r REQUEST, --request REQUEST
Join Request in formato Base64 da forzare brute force. es.
-r AMQAAAAAhQAAAgAAAAAAAADcYldcgbc=
Esempio:
Decifra un JoinRequest con un insieme di chiavi da my-keys.txt e genera anche circa 200000 in più dinamicamente.
python3 BruteForcer.py -a IHvAP4MXo5Qo6tdV+Yfk08o= -r AMQAAAAAhQAAAgAAAAAAAADcYldcgbc= -k ./my-keys.txt
Questo script riceve un pacchetto PHYPayload in Base64 e una chiave che può essere la NwkSKey o la AppKey a seconda del tipo di pacchetto e genera il nuovo MIC.
Argomenti opzionali:
-h, --help mostra questo messaggio di aiuto ed esce
--jakey JAKEY [SOLO JoinAccept]. Inserisci la chiave usata per criptare il
JoinAccept precedentemente (in formato esadecimale, un totale di 32
caratteri / 16 byte). Questo non può essere validato
a priori da questo programma. es.
00112233445566778899AABBCCDDEEFF. Un esempio di chiave valida
per il JoinAccept "IB1scNmwJRA32RfMbvwe3oI=" è
"f5a3b185dfe452c8edca3499abcd0341"
Argomenti obbligatori:
-d DATA, --data DATA Dati in Base64 da firmare. es. -d
AE0jb3GsOdJVAwD1HInrJ7i3yXAFxKU=
-k KEY, --key KEY Inserisci la nuova chiave (in formato esadecimale, un totale di 32
caratteri / 16 byte) per firmare i pacchetti (calcola e
aggiungi un nuovo MIC). Nota che per JoinRequest/JoinAccept
deve essere la AppKey, e la NwkSKey per i pacchetti
Data. Questo non può essere validato a priori da questo
programma. es. 00112233445566778899AABBCCDDEEFF
Esempio:
Firma il PHYPayload fornito con la AppKey 00112233445566778899AABBCCDDEEFF.
python3 MicGenerator.py -d AE0jb3GsOdJVAwD1HInrJ7i3yXAFxKU= -k 00112233445566778899AABBCCDDEEFF
Questo script riceve un pacchetto LoRaWAN in formato JSON e lo trasforma in Base64. Fa l'inverso di packetParser.py, quindi l'output di quello script può essere utilizzato qui e viceversa.
Argomenti opzionali:
-h, --help mostra questo messaggio di aiuto ed esce
-k KEY, --key KEY Inserisci una AppSKey o AppKey del dispositivo (in formato
esadecimale, un totale di 32 caratteri / 16 byte) per criptare
il FRMPayload o un Join Accept. es.
F5A3B185DFE452C8EDCA3499ABCD0341
--nwkskey NWKSKEY Inserisci la chiave di sessione di rete se desideri
generare un pacchetto dati con un MIC valido.
Argomenti obbligatori:
-j JSON, --json JSON Oggetto JSON da analizzare. es. -j '{"mhdr":
{"mType":"JoinRequest","major":"LoRaWANR1"},"macPayloa
d":{"joinEUI":"55d239ac716f234d","devEUI":"b827eb891cf
50003","devNonce":51639},"mic":"7005c4a5"}'
Esempio:
Ottieni un PHYPayload JoinRequest in Base64 dal JSON fornito con i valori passati al suo interno.
python3 PacketCrafter.py -j '{"mhdr":{"mType":"JoinRequest","major":"LoRaWANR1"},"macPayload":{"joinEUI":"55d239ac716f234d","devEUI":"b827eb891cf50003","devNonce":51639},"mic":"7005c4a5"}'
Questo script analizza e stampa un singolo dato PHYPayload LoRaWAN in Base64. Fa l'inverso di packetCrafter.py, quindi l'output di quello script può essere utilizzato qui e viceversa.
Argomenti opzionali:
-h, --help mostra questo messaggio di aiuto ed esce
-k KEY, --key KEY Inserisci una AppKey o AppSKey del dispositivo a seconda del
pacchetto da decriptare (join accept o pacchetto dati).
Deve essere in formato esadecimale, un totale di 32 caratteri / 16
byte. es. 00112233445566778899AABBCCDDEEFF
Argomenti obbligatori:
-d DATA, --data DATA Dati in Base64 da analizzare. es. -d
AE0jb3GsOdJVAwD1HInrJ7i3yXAFxKU=
Esempio:
Ottieni il JoinRequest in formato JSON dall'esempio precedente.
python3 PacketParser.py -d AE0jb3GsOdJVAwD1HInrJ7i3yXAFxKU=
Questo script riceve un JoinAccept e un JoinRequest in Base64, e una AppKey per generare le chiavi di sessione. Un esempio di utilizzo:
Argomenti opzionali:
-h, --help mostra questo messaggio di aiuto ed esce
Argomenti obbligatori:
-a JACCEPT, --jaccept JACCEPT
Payload JoinAccept in base64
-r JREQUEST, --jrequest JREQUEST
Payload JoinRequest in base64
-k KEY, --key KEY Inserisci una AppKey del dispositivo (in formato esadecimale, un totale di 32
caratteri / 16 byte). es.
00112233445566778899AABBCCDDEEFF
Esempio:
Ottieni AppSKey e NwkSKey con i seguenti dati di join.
python3 SessionKeysGenerator.py -r AE0jb3GsOdJVAwD1HInrJ7i3yXAFxKU= -a IB1scNmwJRA32RfMbvwe3oI= -k f5a3b185dfe452c8edca3499abcd0341
Queste sono funzioni ausiliarie utilizzate da UdpSender.py e UdpProxy.py. In Fuzzer.py puoi vedere le modalità di fuzzing implementate.
Lo scopo generale di questa directory è raccogliere pacchetti LoRaWAN e analizzare diversi aspetti del traffico, oltre a provare un insieme di chiavi per tentare di forzare brute force la AppKey.
Questa directory contiene una serie di script che ricevono pacchetti LoRaWAN da diverse fonti (ad esempio packet_forwarder del gateway, The Things Network, ecc.) e li salvano in file, con un formato standard. Questi file dovrebbero essere successivamente recuperati dallo script /auditing/analyzers/LafProcessData.py per eseguire diversi sotto-strumenti.
Questo script si connette al broker mqqt, recupera tutti i topic e salva i messaggi in un file nel campo specificato. Il nome del file è composto dalla data in cui questo script è stato avviato.
Argomenti opzionali:-h, --help mostra questo messaggio di aiuto ed esci --collector-id COLLECTOR_ID L'ID del dataCollector. Questo ID sarà associato ai pacchetti salvati nel DB. es. --id 1 --organization-id ORGANIZATION_ID L'ID del dataCollector. Questo ID sarà associato ai pacchetti salvati nel DB. es. --id 1 --topics TOPICS [TOPICS ...] Elenca i topic a cui vuoi sottoscriverti separati da spazi. Se non viene fornito nulla, il default sarà "#.
Argomenti obbligatori:
--ip IP IP del broker MQTT, es. --ip 192.168.3.101.
--port PORT Porta del broker MQTT, es. --port 623.
Esempio:
Connettersi al broker MQTT con ip 200.200.200.200 sulla porta predefinita (1883).
python3 GenericMqttCollector.py --ip 200.200.200.200 --port 1883
Questo script si connette a un broker mqqt loraserver.io e salva i messaggi nel DB. Devi specificare un collectorID univoco e puoi specificare i topic a cui vuoi sottoscriverti.
Argomenti opzionali:
-h, --help mostra questo messaggio di aiuto ed esci
--port PORT Porta del broker MQTT, es. --port 623. Default 1883.
--collector-id COLLECTOR_ID
L'ID del dataCollector. Questo ID sarà
associato ai pacchetti salvati nel DB. es. --id 1
--organization-id ORGANIZATION_ID
L'ID del dataCollector. Questo ID sarà
associato ai pacchetti salvati nel DB. es. --id 1
--topics TOPICS [TOPICS ...]
Elenca i topic a cui vuoi sottoscriverti separati da
spazi. Se non viene fornito nulla, il default sarà "#.
Argomenti obbligatori:
--ip IP IP del broker MQTT, es. --ip 192.168.3.101.
Questo script riceve pacchetti UDP dal proxy UDP nel formato packet_forwarder del gateway e li persiste.
Argomenti opzionali:
-h, --help mostra questo messaggio di aiuto ed esci
--collector-id COLLECTOR_ID
L'ID del dataCollector. Questo ID sarà
associato ai pacchetti salvati nel DB. es. --id 1
--organization-id ORGANIZATION_ID
L'ID del dataCollector. Questo ID sarà
associato ai pacchetti salvati nel DB. es. --id 1
Argomenti obbligatori:
-n NAME, --name NAME Identificatore univoco stringa del Data Collector. es.
--name semtech_collector
-p PORT, --port PORT Porta su cui ascoltare i pacchetti UDP. --port 1702.
Esempio:
Registrare i dati tra un gateway che invia sulla porta locale 1700 e un network xserver in ascolto su (localhost, 1701). Salvare i dati nella directory ./.
python3 PacketForwarderCollector.py --name semtech_collector --port 1700
Questo script legge da un file o da file o da stdin ed esegue diversi sottostrumenti. A seconda dell'opzione selezionata, puoi eseguire un'analisi del traffico LoRaWAN, provare a forzare l'AppKey, o analizzare tutti i pacchetti ricevuti. Queste opzioni possono essere combinate.
Argomenti opzionali:
Questo script recupera i pacchetti dal DB ed esegue diversi sottostrumenti.
Poi, ogni sottostrumento salverà i dati di output nel DB. Vedi ogni opzione per
maggiori informazioni.
argomenti opzionali:
-h, --help mostra questo messaggio di aiuto ed esci
-a, --analyze Raccogli e analizza diversi aspetti del traffico. Se
Bruteforcer (-b) è attivato, i risultati saranno
correlati
-b, --bforce Prova a forzare gli AppKey con payload JoinRequests e
JoinAccepts
-k KEYS, --keys KEYS [Bruteforcer] Percorso del file delle chiavi. Se non fornito,
verrà usato "bruteForcer/keys.txt"
--no-gen [Bruteforcer] Non generare chiavi, prova solo chiavi da
file
-p, --parse Analizza il PHYPayload in informazioni leggibili
--from-id FROM_ID ID del pacchetto da cui iniziare l'elaborazione.
--to-id TO_ID Ultimo ID del pacchetto da elaborare.
Esempio:
Elaborare i pacchetti nel DB a partire dall'ID pacchetto 1000, eseguire un'analisi del traffico e provare a decifrare gli AppKey forniti in my-keys.txt, ma non generare dinamicamente più chiavi.
python3 LafProcessData.py -a -b -k my-keys.txt --no-gen --from-id 1000
Questi script forniscono la funzionalità orchestrata da LafProcessData.py. Di seguito, gli alert implementati da LafPacketAnalysis.py e LafBruteForcer.py:
Questa directory fornisce un insieme di wrapper per la libreria https://github.com/brocaar/lorawan/, scritta in Golang. Queste funzioni sono implementate dagli strumenti.
Qui troverai una serie di script pensati per automatizzare diverse attività. Assicurati di dare loro i permessi di esecuzione se necessario (chmod +x your_script per Linux/MacOS).
Configura facilmente il tuo gateway e cambia i suoi canali per scopi di sniffing. Per maggiori informazioni su come usarli, puoi vedere il readme in questa directory.
Questo script viene usato per installare tutti i pacchetti software necessari su un Raspberry PI per costruire un Gateway LoRaWAN in combinazione con un Concentratore LoRa collegato (iC980-SPI, RHF0M301-SPI, RAK831-SPI o qualsiasi altro mediante configurazione manuale).
Poiché non è possibile sapere in quali frequenze operano i dispositivi LoRa, abbiamo creato uno script in grado di cambiare i canali dei gateway dalle bande di frequenza US915 e EU868 per scopi di sniffing. Sebbene esistano gateway professionali e costosi che supportano 32 o 64 canali, la maggior parte dei gateway supporta fino a 8 canali. Questo script è pensato per funzionare su questo tipo di gateway.
Almeno nella banda di frequenza US915, i primi 8 canali sono i più usati. Ma ci sono implementazioni ben note che usano un altro gruppo di canali, come ad esempio The Things Networks, che usa il secondo gruppo (8-15) di canali per la comunicazione uplink.
Attualmente non supportiamo altre bande di frequenza, ma con poche modifiche a questi script saresti in grado di farlo da solo :).
TODO
Questo progetto è concesso in licenza sotto BSD-3-Clause.
export GOPATH="$HOME/go"Compila la libreria go:
cd laf/lorawanwrapper/utilsgo build -o lorawanWrapper.so -buildmode=c-shared jsonUnmarshaler.go lorawanWrapper.go micGenerator.go sessionKeysGenerator.go hashGenerator.goA seconda del DB che desideri utilizzare:
a. PostgreSQL: Segui le istruzioni 'Installare LAF usando Docker' fino al 3° passaggio.
b. SQLite:
cd laf/auditing/db__init__.py con il tuo editor di testo preferito e commenta le righe da utilizzare con Postgres (connessione DB e variabili d'ambiente) e decommenta la riga da utilizzare con sqlite.| ID | Titolo | Analyzer | Livello di rischio | Descrizione | Azione consigliata |
|---|
| LAF-001 | DevNonce ripetuto | LafPacketAnalysis.py | Basso | I DevNonce per ogni dispositivo dovrebbero essere sufficientemente casuali da non collidere. Se lo stesso DevNonce viene ripetuto in molti messaggi, si può dedurre che un dispositivo è sotto un attacco di replay. Cioè, un attaccante che ha catturato una JoinRequest e sta cercando di inviarla di nuovo al gateway. | Controlla come vengono generati i DevNonce: la funzione che li genera dovrebbe essere implementata usando una libreria casuale. Inoltre, devi assicurarti che il server controlli i DevNonce storici (dovrebbero essere persistiti nel DB), per non accettare una vecchia JoinRequest valida inviata in precedenza dal dispositivo e quindi generare una nuova sessione. |
| LAF-002 | DevEUI che condividono lo stesso DevAddr | LafPacketAnalysis.py | Info | Due dispositivi diversi potrebbero aver ricevuto lo stesso DevAddr. Questo non è una minaccia alla sicurezza. | Se il dispositivo è attivato via etere (OTAA): Controlla la logica usata per assegnare i DevAddr e assicurati che il server non assegni lo stesso DevAddr a dispositivi diversi. Se il dispositivo è attivato per personalizzazione (ABP): Controlla che il DevAddr configurato nel firmware del dispositivo sia unico nella rete lorawan. |
| LAF-003 | Replay Join | TODO | Medio | È stato rilevato un pacchetto di join request duplicato, il che potrebbe implicare che il server lorawan è sotto un attacco di replay. Cioè, un attaccante potrebbe aver catturato un precedente pacchetto di join request e lo sta inviando di nuovo al server lorawan, per cercare di generare una nuova sessione. | Controlla come vengono generati i DevNonce: la funzione che li genera dovrebbe essere implementata usando una libreria casuale. Inoltre, devi assicurarti che il server controlli i DevNonce storici (dovrebbero essere persistiti nel DB), per non accettare una vecchia JoinRequest valida inviata in precedenza dal dispositivo e quindi generare una nuova sessione. |
| LAF-004 | Replay pacchetti dati uplink | TODO | Medio | È stato rilevato un pacchetto uplink duplicato, il che potrebbe implicare che il server lorawan è sotto un attacco di replay. Cioè, un attaccante potrebbe aver catturato un pacchetto uplink (inviato dal dispositivo) e lo sta inviando di nuovo al server lorawan. | Nei dispositivi attivati via etere (OTAA): Assicurati che le chiavi di sessione vengano rigenerate dopo ogni reset del dispositivo o overflow del contatore per evitare qualsiasi effetto da questo attacco. Con dispositivi attivati per personalizzazione (ABP) da lorawan v1.0.*, non si può fare nulla per prevenire un attacco di replay se non passare il dispositivo a OTAA. |
| LAF-005 | Replay pacchetti dati downlink | TODO | Alto | È stato rilevato un pacchetto downlink duplicato. Il server sta rispondendo a un attacco di replay o sta generando un traffico atipico verso i dispositivi. | Controlla i log del server e verifica che le azioni consigliate precedenti siano state implementate. |
| LAF-006 | Possibile dispositivo ABP (contatore resettato e nessun join) | LafPacketAnalysis.py | Alto | Se il contatore è stato resettato (tornato a 0), il DevAddr rimane lo stesso e non è stato rilevato alcun precedente processo di Join, potrebbe implicare che il dispositivo è attivato per personalizzazione (ABP). L'implementazione di dispositivi ABP è sconsigliata perché non viene eseguito alcun processo di join, il che significa che le chiavi di sessione rimangono le stesse per sempre. Un dispositivo che non cambia le sue chiavi di sessione è soggetto a diversi attacchi come intercettazione o replay. | Tutti i dispositivi attivati per personalizzazione (ABP) dovrebbero essere sostituiti con dispositivi attivati via etere (OTAA) se possibile. L'implementazione di dispositivi ABP è sconsigliata. |
| LAF-007 | Ricevuto contatore più piccolo del previsto (diverso da 0) | LafPacketAnalysis.py | Medio | Se un attaccante ottiene una coppia di chiavi di sessione (per aver rubato l'AppKey nei dispositivi OTAA o l'AppSKey/NwkSKey nei dispositivi ABP), potrebbe inviare dati falsi validi al server. Perché il server accetti messaggi spoofati, è necessario che il FCnt (Frame Counter) del messaggio sia superiore al FCnt dell'ultimo messaggio inviato. In uno scenario in cui il dispositivo spoofato originale continua a inviare messaggi, il server inizierebbe a scartare messaggi (validi) poiché avrebbero un FCnt più piccolo. Quindi, quando vengono ricevuti messaggi con un valore FCnt inferiore a quanto previsto dal server lorawan, è possibile dedurre che è stata stabilita una sessione parallela. | Se il dispositivo è attivato via etere (OTAA), cambia il suo AppKey perché probabilmente è stato compromesso. Se è attivato per personalizzazione, cambia il suo AppSKey e NwkSKey. Inoltre, assicurati che il server lorawan sia aggiornato e non accetti messaggi duplicati. |
| LAF-008 | Password decifrata con JoinRequest | LafBruteforcer.py | Alto | È stato possibile decifrare un messaggio JoinRequest usando un AppKey noto. | Usa AppKey diversi da quelli forniti dai vendor o usa chiavi più casuali. |
| LAF-009 | Password decifrata | LafBruteforcer.py | Alto | L'AppKey del dispositivo è stato trovato provando con una stringa ben nota o non casuale. È stato decifrato usando una coppia di messaggi di join (Request e Accept). | Usa un generatore di chiavi casuali per l'AppKey invece di usare quelli forniti dai vendor. Inoltre, non impostare lo stesso AppKey per più di un dispositivo e non generare AppKey usando una logica prevedibile (es. valori incrementali, invertire certi byte, ecc.) |
| LAF-010 | Posizione del gateway cambiata | LafPacketAnalysis.py | Medio | Se il gateway non dovrebbe cambiare posizione. Potrebbe essere stato rubato, spostato, o un gateway falso potrebbe cercare di impersonare il gateway legittimo. | Assicurati che il gateway non sia stato manomesso, né fisicamente né logicamente. |