Les déploiements IoT ne cessent de croître et une partie de cette croissance significative est composée de millions de capteurs LPWAN (réseaux larges de la région à faible puissance) déployés dans des centaines de villes (villes intelligentes) dans le monde, également dans les industries et les maisons. L'une des technologies LPWAN les plus utilisées est LORA pour laquelle Lorawan est la norme réseau (Mac Layer). Lorawan est un protocole sécurisé avec un chiffrement intégré, mais les problèmes de mise en œuvre et les faiblesses affectent la sécurité des déploiements actuels.
Ce projet a l'intention de fournir une série d'outils pour fabriquer, analyser, envoyer, analyser et craquer un ensemble de paquets de Lorawan afin d'auditer ou de présélectionner la sécurité d'une infrastructure de Lorawan.
Ci-dessous, la structure de ce référentiel:
|-- 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
Nous offrons différentes options pour que votre cadre d'audit Lorawan soit opérationnel:
tools/ dir, afin d'éviter les problèmes de cartographie du port Docker.localhost . Voir les instructions ci-dessous pour configurer Docker.Ces instructions vous procureront une copie du projet et de ses dépendances dans votre machine locale. Les commandes ci-dessous sont pour un environnement basé sur Debian:
Clone Ce référentiel: git clone --recurse-submodules https://github.com/IOActive/laf.git
Installez Python3:
sudo apt-get updatesudo apt-get install python3.6Télécharger et installer les dépendances Python:
sudo pip3 install paho-mqtt && sudo pip3 install sqlalchemy && sudo pip3 install psycopg2-binary &&sudo pip3 install python-dateutilDéfinir PythonPath et environnement
cd laf && export PYTHONPATH=$(pwd) && export ENVIRONMENT='DEV'Installer et configurer Golang:
cd ~/Downloadssudo tar -C /usr/local -xvzf YOUR_GOLANG_FILEexport PATH=$PATH:/usr/local/go/binexport GOPATH="$HOME/go"Bibliothèque de compilation GO:
cd laf/lorawanwrapper/utilsgo build -o lorawanWrapper.so -buildmode=c-shared jsonUnmarshaler.go lorawanWrapper.go micGenerator.go sessionKeysGenerator.go hashGenerator.goSelon la base de données que vous souhaitez utiliser:
un. PosTresql: Suivez les instructions «Installez LAF à l'aide de Docker» jusqu'à la 3e étape.
né Sqlite:
cd laf/auditing/db__init__.py avec votre éditeur de texte préféré et commentez les lignes à utiliser avec Postgres (Variables de connexion et d'environnement DB) et non les comment à utiliser avec SQLite.Et c'est tout!
Cette approche évite de traiter l'installation de dépendances et de démarrer une base de données postgresql où les outils enregistrent les paquets et les données. Conteneurs:
Mesures:
git clone https://github.com/IOActive/laf.gitcd laf/docker-compose up --builddocker exec -ti laf_tools_1 /bin/bashVous pouvez vérifier les données en DB à l'aide de pgadmin:
Tout d'abord, l'accès à Pgadmin:
Ensuite, vous devez ajouter le serveur:
Voici la description des répertoires et des outils / fonction à l'intérieur.
L'objectif principal des outils fournis dans ce répertoire est de faciliter l'exécution d'un test de pénétration à une infrastructure de Lorawan.
Cet outil est destiné à envoyer des paquets de liaison montante (au serveur réseau ou à GatewayBridge, selon l'infrastructure) ou des paquets de liaison descendants (au paquet-collecteur). Facultativement, les paquets peuvent être flous et un micro valide peut être calculé.
Arguments facultatifs:
-h, --help show this help message and exit
--lcl-port LCL_PORT Source port, eg. --lcl-port=623.
--timeout TIMEOUT Time in seconds between every packet sent. Default is
1s. In this time, the sender will listen for replies.
--repeat Send message/s multiple times
--fuzz-out FUZZ_OUT [FUZZ_OUT ...]
Fuzz data sent to dest port (see fuzzing modes in
utils/fuzzer.py), eg. --fuzz-out 1 2.
--key KEY Enter the key (in hex format, a total of 32 characters
/ 16 bytes) to sign packets (calculate and add a new
MIC). Note that for JoinRequests it must be the
AppKey, and the NwkSKey for Data packets. This cannot
be validated beforehand by this program. eg.
00112233445566778899AABBCCDDEEFF
-a DEVADDR, --devaddr DEVADDR
DeviceAddress to impersonate, given in hex format (8
characters total), eg. AABB0011.
--fcnt FCNT The frame counter to be set in the given data packet.
This wouldn't work in a JoinRequest/JoinAccept since
this packets don't have a fCnt
Arguments requis:
--dst-ip DST_IP Destination ip, eg. --dst-ip 192.168.3.101.
--dst-port DST_PORT Destination port, eg. --dst-port 623.
--data DATA UDP packet. It can also be added more packets in
"data" array at the end of this script. The packet
must be a byte string (you will have to escape double
quotes). ***EXAMPLE*** with the packet_forwarder
format: --data "b'x02xe67x00xb8'xebxffxfezx80
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="}]}'" ***EXAMPLE*** using the gatevice
[GV] format sending in inmediate mode, in BW125 and
freq 902.3 is "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}'"
Exemple:
Pour envoyer un seul paquet toutes les 2 secondes à (LocalHost, 10001) à partir du port 10000 Fuzzing au hasard le micro et le FCounter:
python3 UdpSender.py --lcl-port 10000 --dst-ip 127.0.0.1 --dst-port 10001 --timeout 2 --fuzz-out 4 5 --data "b'x02xe67x00xb8'xebxffxfezx80xdb{"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="}]}'"
Ce proxy UDP est principalement destiné à être placé entre une passerelle série (Packet_Forwarders) et un serveur de réseau ou un pont de passerelle en fonction de l'infrastructure évaluée. Il offre également la possibilité des données de fuzz dans la direction souhaitée (liaison montante ou liaison descendante)
Arguments facultatifs:
-h, --help show this help message and exit
--collector-port COLLECTOR_PORT
Packet forwarder data collector port, eg. --collector-
port 1701. See
auditing/datacollectors/PacketForwarderCollector.py
--collector-ip COLLECTOR_IP
Packet forwarder data collector ip. Default is
localhost. eg. --collector-ip 192.168.1.1. See
auditing/datacollectors/PacketForwarderCollector.py
--fuzz-in FUZZ_IN [FUZZ_IN ...]
Fuzz data sent to dst-port in the given modes (see
fuzzing modes in utils/fuzzer.py), eg. --fuzz-in 1 2
...
--fuzz-out FUZZ_OUT [FUZZ_OUT ...]
Fuzz data sent to (source) port in the given modes
(see fuzzing modes in utils/fuzzer.py), eg. --fuzz-out
1 2 ...
-k KEY, --key KEY Enter a device AppSKey (in hex format, a total of 32
characters / 16 bytes) to decrypt its FRMPayload and
print it in plain text. You can also enter the AppKey
if you wish to decrypt a given Join Accept. eg.
00112233445566778899AABBCCDDEEFF
-p PATH, --path PATH Filepath where to save the data. If not given, data
will not be saved.
--no-log Do not print UDP packages into console
--no-parse Do not parse PHYPayload. If this option is selected,
Golang librarys from /lorawanwrapper/ won't be
imported (golang libs compiling is not required)
Arguments requis:
--port PORT The local port to listen, eg. --port 623.
--dst-ip DST_IP Destination host ip, eg. --dst-ip 192.168.3.101.
--dst-port DST_PORT Destination host port, eg. --dst-port 623.
Exemple:
Pour envoyer des paquets reçus dans le port 1234 à (LocalHost, 1235) et vicecersa. Les paquets reçus dans le port seront floues (le Devnonce sera modifié en randon) et transmis à (LocalHost, 1235).
python3 UdpProxy.py --port 1234 --dst-ip 127.0.0.1 --dst-port 1235 --fuzz-in 9
Ce proxy TCP est principalement destiné à être placé entre le serveur réseau et les courtiers MQTT. Il offre également la possibilité des données de fuzz.
Arguments facultatifs:
-h, --help show this help message and exit
--fuzz-in FUZZ_IN [FUZZ_IN ...]
Fuzz data sent to dst-port in the given modes (see
fuzzing modes in utils/fuzzer.py)
Arguments requis:
--lcl-port LCL_PORT The local port to listen, eg. --lcl-port=623.
--dst-ip DST_IP Destination host ip, eg. --dst-ip=192.168.3.101.
--dst-port DST_PORT Destination host port, eg. --dst-port=623.
Exemple:
Envoyer et recevoir des données de (LocalHost, 1884) et (LocalHost, 1883)
python3 TcpProxy.py --lcl-port 1884 --dst-ip 127.0.0.1 --dst-port 1883
Ce répertoire contient une série de scripts pour analyser, artisanat, bruteforcer, etc. lorawan a paquets.
Ce script reçoit un Joinaccept ou JoinRequest dans Base64 et essaie de décrypter son appkey avec un ensemble de clés possibles qui peuvent être fournies dans un fichier ou peuvent être générées à la volée.
Arguments facultatifs:
-h, --help show this help message and exit
-k KEYS, --keys KEYS File containing a list of keys, separated by n. Will
use /auditing/analyzers/bruteForcer/keys.txt by
default
--dont-generate Select this options if you don't want to generate keys
on the fly with the following combinations: 1- Combine
the first byte and the last fifteeen bytes. eg.
AABBBBBBBBBBBBBBBBBBBBBBBBBBBBBB 2- Combine even and
odd bytes position equally. eg.
AABBAABBAABBAABBAABBAABBAABBAABB 3- The first 14 bytes
in 00 and combine the last 2. eg.
0000000000000000000000000000BA01
Arguments requis:
-a ACCEPT, --accept ACCEPT
Join Accept in Base64 format to be bruteforced. eg. -a
IHvAP4MXo5Qo6tdV+Yfk08o=
-r REQUEST, --request REQUEST
Join Request in Base64 format to be bruteforced. eg.
-r AMQAAAAAhQAAAgAAAAAAAADcYldcgbc=
Exemple:
Crack a joinquest avec un ensemble de clés de my- keys.txt et générer également aprox. 200000 de plus dinamiquement.
python3 BruteForcer.py -a IHvAP4MXo5Qo6tdV+Yfk08o= -r AMQAAAAAhQAAAgAAAAAAAADcYldcgbc= -k ./my-keys.txt
Ces scripts reçoivent un paquet Phypayload dans Base64 et une clé qui peut être le NWKSK de l'Appkey en fonction du type de paquet et génère le nouveau micro.
Arguments facultatifs:
-h, --help show this help message and exit
--jakey JAKEY [JoinAccept ONLY]. Enter the key used to encrypt the
JoinAccept previously (in hex format, a total of 32
characters / 16 bytes). This cannot be validated
beforehand by this program. eg.
00112233445566778899AABBCCDDEEFF. A valid key sample
for the JoinAccept "IB1scNmwJRA32RfMbvwe3oI=" is
"f5a3b185dfe452c8edca3499abcd0341"
Arguments requis:
-d DATA, --data DATA Base64 data to be signed. eg. -d
AE0jb3GsOdJVAwD1HInrJ7i3yXAFxKU=
-k KEY, --key KEY Enter the new key (in hex format, a total of 32
characters / 16 bytes) to sign packets (calculate and
add a new MIC). Note that for JoinRequest/JoinAccept
it must be the AppKey, and the NwkSKey for Data
packets. This cannot be validated beforehand by this
program. eg. 00112233445566778899AABBCCDDEEFF
Exemple:
Signez le Phypayload donné avec l'Appkey 00112233445566778899AABBCCDDEEFF.
python3 MicGenerator.py -d AE0jb3GsOdJVAwD1HInrJ7i3yXAFxKU= -k 00112233445566778899AABBCCDDEEFF
Ce script reçoit un paquet Lorawan JSON et le transforme à Base64. Il fait l'inverse en tant que paquetParser.py, de sorte que la sortie de ce script peut être utilisée ici et vice-versa.
Arguments facultatifs:
-h, --help show this help message and exit
-k KEY, --key KEY Enter a device AppSKey or AppKey (in hex format, a
total of 32 characters / 16 bytes) to encrypt the
FRMPayload or a Join Accept. eg.
F5A3B185DFE452C8EDCA3499ABCD0341
--nwkskey NWKSKEY Enter the network session key if you'd like to
generate a data packet with a valid MIC.
Arguments requis:
-j JSON, --json JSON JSON object to parse. eg. -j '{"mhdr":
{"mType":"JoinRequest","major":"LoRaWANR1"},"macPayloa
d":{"joinEUI":"55d239ac716f234d","devEUI":"b827eb891cf
50003","devNonce":51639},"mic":"7005c4a5"}'
Exemple:
Obtenez un Phypayload JoinRequest dans Base64 avec donné dans le JSON avec les valeurs qui y sont passées.
python3 PacketCrafter.py -j '{"mhdr":{"mType":"JoinRequest","major":"LoRaWANR1"},"macPayload":{"joinEUI":"55d239ac716f234d","devEUI":"b827eb891cf50003","devNonce":51639},"mic":"7005c4a5"}'
Ce script analyse et imprime une seule données Lorawan Phypayload dans Base64. Il fait l'inverse comme packetcrafter.py, de sorte que la sortie de ce script peut être utilisée ici et vice-versa.
Arguments facultatifs:
-h, --help show this help message and exit
-k KEY, --key KEY Enter a device AppKey or AppSKey depending on the
packet to be decrypted (join accept or data packet).
Must be in hex format, a total of 32 characters / 16
bytes. eg. 00112233445566778899AABBCCDDEEFF
Arguments requis:
-d DATA, --data DATA Base64 data to be parsed. eg. -d
AE0jb3GsOdJVAwD1HInrJ7i3yXAFxKU=
Exemple:
Obtenez le format JoinRquest au format JSON à partir de l'exemple ci-dessus.
python3 PacketParser.py -d AE0jb3GsOdJVAwD1HInrJ7i3yXAFxKU=
Ce script reçoit un JoinACcept et un JoinRequest dans Base64, et un Appkey pour générer les touches de session. Un exemple de l'utilisation:
Arguments facultatifs:
-h, --help show this help message and exit
Arguments requis:
-a JACCEPT, --jaccept JACCEPT
JoinAccept payload in base64
-r JREQUEST, --jrequest JREQUEST
JoinRequest payload in base64
-k KEY, --key KEY Enter a device AppKey (in hex format, a total of 32
characters / 16 bytes). eg.
00112233445566778899AABBCCDDEEFF
Exemple:
Obtenez l'AppsKey et NwksKey avec les données de jointure suivantes.
python3 SessionKeysGenerator.py -r AE0jb3GsOdJVAwD1HInrJ7i3yXAFxKU= -a IB1scNmwJRA32RfMbvwe3oI= -k f5a3b185dfe452c8edca3499abcd0341
Ce sont des fonctions auxiliaires utilisées par UdpSender.py et UdpProxy.py . Dans Fuzzer.py vous pouvez voir les modes de fuzzing implémentés.
L'objectif général de ce répertoire est de collecter les paquets de Lorawan et d'analyser différents aspects du trafic, ainsi que d'essayer un ensemble de clés pour essayer de bruter l'Appkey.
Ce répertoire contient un ensemble de scripts qui reçoivent des paquets Lorawan de différentes sources (c.-à-d. Ces fichiers doivent être récupérés plus tard par le script /auditing/analyzers/LafProcessData.py lafprocessdata.py pour exécuter différents sous-outils.
Ce script se connecte au courtier MQQT, récupère tous les sujets et enregistre les messages dans un fichier dans le champ spécifié. Le nom de fichier est composé par la date à laquelle ce script a été démarré.
Arguments facultatifs:
-h, --help show this help message and exit
--collector-id COLLECTOR_ID
The ID of the dataCollector. This ID will be
associated to the packets saved into DB. eg. --id 1
--organization-id ORGANIZATION_ID
The ID of the dataCollector. This ID will be
associated to the packets saved into DB. eg. --id 1
--topics TOPICS [TOPICS ...]
List the topic(s) you want to suscribe separated by
spaces. If nothing given, default will be "#.
Arguments requis:
--ip IP MQTT broker ip, eg. --ip 192.168.3.101.
--port PORT MQTT broker port, eg. --port 623.
Exemple:
Connectez-vous à MQTT le courtier avec IP 200.200.200.200 dans le port par défaut (1883).
python3 GenericMqttCollector.py --ip 200.200.200.200 --port 1883
Ce script se connecte à un courtier Loraserver.io MQQT et enregistre des messages dans la base de données. Vous devez spécifier un CollectorId unique et vous pouvez spécifier les sujets auxquels vous souhaitez vous inscrire.
Arguments facultatifs:
-h, --help show this help message and exit
--port PORT MQTT broker port, eg. --port 623. Default 1883.
--collector-id COLLECTOR_ID
The ID of the dataCollector. This ID will be
associated to the packets saved into DB. eg. --id 1
--organization-id ORGANIZATION_ID
The ID of the dataCollector. This ID will be
associated to the packets saved into DB. eg. --id 1
--topics TOPICS [TOPICS ...]
List the topic(s) you want to suscribe separated by
spaces. If nothing given, default will be "#.
Arguments requis:
--ip IP MQTT broker ip, eg. --ip 192.168.3.101.
Ce script reçoit des paquets UDP du proxy UDP au format de paquet de passerelle_ pour les persiste.
Arguments facultatifs:
-h, --help show this help message and exit
--collector-id COLLECTOR_ID
The ID of the dataCollector. This ID will be
associated to the packets saved into DB. eg. --id 1
--organization-id ORGANIZATION_ID
The ID of the dataCollector. This ID will be
associated to the packets saved into DB. eg. --id 1
Arguments requis:
-n NAME, --name NAME Unique string identifier of the Data Collector. eg.
--name semtech_collector
-p PORT, --port PORT Port where to listen for UDP packets. --port 1702.
Exemple:
Enregistrez les données entre une passerelle envoyée au port local 1700 et un réseau XServer écoutant (LocalHost, 1701). Enregistrez les données ./ Répertoire.
python3 PacketForwarderCollector.py --name semtech_collector --port 1700
Ce script lit un fichier ou des fichiers ou STDIN et exécute différents sous-outils. Selon l'option sélectionnée, vous pouvez exécuter une analyse du trafic de Lorawan, essayer de brute for the Appkey ou analyser tous les paquets reçus. Ces options peuvent être combinées.
Arguments facultatifs:
This script reads retrieves packets from DB and executes different sub-tools.
Then, each sub-tool will save output data into the DB. See each option for
more information.
optional arguments:
-h, --help show this help message and exit
-a, --analyze Collect and analyze different aspects from traffic. If
Bruteforcer (-b) is activated, results will be
corelated
-b, --bforce Try to bruteforce the AppKeys with JoinRequests and
JoinAccepts payloads
-k KEYS, --keys KEYS [Bruteforcer] Filepath to keys file. If not provided,
"bruteForcer/keys.txt" will be used
--no-gen [Bruteforcer] Don't generate keys, only try keys from
files
-p, --parse Parse the PHYPayload into readable information
--from-id FROM_ID Packet ID from where to start processing.
--to-id TO_ID Last packet ID to be processed.
Exemple:
Les paquets de traitement dans la base de données à partir de l'ID de paquet 1000, exécutent une analyse du trafic et essayez de casser les appkeys donnés dans my-keys.txt, mais ne générez pas dinamiquement plus de clés.
python3 LafProcessData.py -a -b -k my-keys.txt --no-gen --from-id 1000
Ces scripts fournissent la fonctionnalité ornée par lafprocessdata.py. Ci-dessous, les alertes mises en œuvre par LafPacketAnalysis.py et LafBruteForcer.py :
| IDENTIFIANT | Titre | Analyseur | Niveau de risque | Description | Action recommandée |
|---|---|---|---|---|---|
| LAF-001 | Devnonce répété | Lafpacketanalysis.py | Faible | Les devnnes pour chaque appareil doivent être suffisamment aléatoires pour ne pas entrer en collision. Si le même Devnonce a été répété dans de nombreux messages, on peut en déduire qu'un appareil est sous une attaque de relecture. C'est un attaquant qui a capturé un JoinRequest et essaie de le renvoyer à la passerelle. | Vérifiez comment les DevNonces sont générés: la fonction qui les génère doit être implémentée à l'aide d'une bibliothèque aléatoire. De plus, vous devez vous assurer que le serveur vérifie les devnnes historiques (ils doivent être persistés en DB), afin de ne pas accepter une ancienne JoinRequest valide envoyée précédemment par l'appareil et ainsi générer une nouvelle session. |
| LAF-002 | Deveuis partageant le même Devaddr | Lafpacketanalysis.py | Informations | Deux appareils différents pourraient avoir été attribués le même Devaddr. Ce n'est pas une menace de sécurité. | Si l'appareil est sur l'air activé (OTAA): vérifiez la logique utilisée pour attribuer Devaddrs et assurez-vous que le serveur n'attribue pas le même Devaddr à différents appareils. Si le périphérique est activé par personnalisation (ABP): Vérifiez le Devaddr configuré dans le firmware d'un appareil est unique dans le réseau Lorawan. |
| LAF-003 | Rejoindre la relecture | FAIRE | Moyen | Un paquet de demande de jointure dupliqué a été détecté, ce qui peut impliquer que le serveur Lorawan est sous une attaque de relecture. Il s'agit d'un attaquant qui a peut-être capturé un paquet de demande de jointure précédent et l'envoie à nouveau au serveur Lorawan, afin d'essayer de générer une nouvelle session. | Vérifiez comment les DevNonces sont générés: la fonction qui les génère doit être implémentée à l'aide d'une bibliothèque aléatoire. De plus, vous devez vous assurer que le serveur vérifie les devnnes historiques (ils doivent être persistés en DB), afin de ne pas accepter une ancienne JoinRequest valide envoyée précédemment par l'appareil et ainsi générer une nouvelle session. |
| LAF-004 | Replay de paquets de données de liaison montante | FAIRE | Moyen | Un paquet de liaison montante dupliquée a été détecté, ce qui peut impliquer que le serveur Lorawan est sous une attaque de relecture. Il s'agit d'un attaquant qui a peut-être capturé un paquet de liaison montante (envoyée à partir de l'appareil) et l'envoie à nouveau au serveur Lorawan. | Dans les appareils activés par l'air (OTAA): assurez-vous que les clés de session sont re-générées après la réinitialisation ou le compteur de chaque appareil pour éviter tout effet de cette attaque. Avec des appareils activés par personnalisation (ABP) de Lorawan v1.0. *, Rien ne peut être fait pour empêcher une attaque de relecture, sauf de passer l'appareil à OTAA. |
| LAF-005 | Replays de paquets de données de liaison descendante | FAIRE | Haut | Un paquet de liaison descendante dupliquée a été détecté. Le serveur répond à une attaque de rediffusion ou génère un trafic atypique vers des appareils | Vérifiez les journaux des serveurs et vérifiez que l'action recommandée précédente est implémentée |
| LAF-006 | Appareil ABP possible (contre-réinitialisation et pas de jointure) | Lafpacketanalysis.py | Haut | Si le compteur était réinitialisé (revenu à 0), le Devaddr est maintenu le même et aucun processus de jointure précédent n'a été détecté, peut impliquer que le dispositif est activé par personnalisation (ABP). L'implémentation ABP Devices est découragée car aucun processus de jointure n'est effectué, ce qui signifie que les clés de session sont maintenues les mêmes pour toujours. Un appareil qui ne modifie pas ses clés de session est sujet à différentes attaques telles que Eveasdrop ou Replay. | Tous les appareils activés par la personnalisation (ABP) doivent être remplacés pour les appareils activés par l'air (OTAA) si possible. L'implémentation des dispositifs ABP est découragée. |
| LAF-007 | Reçu un compteur plus petit que prévu (distinct de 0) | Lafpacketanalysis.py | Moyen | Si un attaquant obtient une paire de clés de session (pour avoir volé l'Appkey dans les appareils OTAA ou le Appskey / Nwkskey dans les appareils ABP), il / elle pourrait envoyer de fausses données valides au serveur. Pour que le serveur accepte les messages usurpés, il est nécessaire que le FCNT (compteur de trame) du message soit supérieur au FCNT du dernier message envoyé. Dans un scénario où le périphérique usurpé d'origine continue d'envoyer des messages, le serveur commencerait à éliminer les messages (valides) car ils auraient un FCNT plus petit. Par conséquent, lorsque des messages avec une valeur FCNT plus petite que prévu par le serveur Lorawan sont reçus, il est possible de déduire qu'une session parallèle a été établie. | Si l'appareil est sur le dispositif activé par l'air (OTAA), modifiez son appkey car il a probablement été compromis. S'il est activé par la personnalisation, modifiez son appskey et NWKSKEY. De plus, assurez-vous que le serveur Lorawan est mis à jour et n'accepte pas les messages dupliqués. |
| LAF-008 | Mot de passe craqué avec JoinRequest | Lafbruteforcer.py | Haut | Il a été possible de décrypter un message JoinRquest à l'aide d'un appkey connu. | Utilisez différents appkeys que ceux fournis par les fournisseurs ou utilisez plus de clés aléatoires. |
| LAF-009 | Mot de passe fissuré | Lafbruteforcer.py | Haut | L'application de l'appareil a été retrouvée essayée avec une chaîne bien connue ou non aléatoire. Il a été déchiffré à l'aide d'une paire de messages de jointure (demande et accepter). | Utilisez un générateur de clés aléatoire pour l'Appkey au lieu d'utiliser ceux fournis par les fournisseurs. De plus, ne définissez pas le même appkey sur plus d'un appareil et ne générez pas Appkeys en utilisant une logique prévisible (par exemple, valeurs incrémentielles, retourner certains octets, etc.) |
| LAF-010 | Emplacement changé de passerelle | Lafpacketanalysis.py | Moyen | Si la passerelle n'est pas censée changer son emplacement. Il a peut-être été volé, déplacé ou une fausse passerelle peut essayer d'identiter la passerelle légitime. | Assurez-vous que la passerelle n'a pas été falsifiée, à la fois physiquement ou logiquement. |
Ce répertoire fournit un ensemble d'emballages pour la bibliothèque https://github.com/brocaar/lorawan/, qui est écrit en Golang. Ces fonctions sont implémentées par les outils.
Ici, vous trouverez une série de scripts destinés à automatiser différentes tâches. Assurez-vous de leur donner une autorisation d'exécution si nécessaire ( chmod +x your_script pour Linux / MacOS).
Configurez facilement votre passerelle et changez ses canaux à des fins de reniflement. Pour plus d'informations sur la façon de les utiliser, vous pouvez voir le ReadMe dans ce répertoire.
Ce script est utilisé pour installer tous les packages logiciels nécessaires sur un Raspberry Pi pour construire une passerelle Lorawan en conjonction avec un concentrateur LORA connecté (IC980-SPI, RHF0M301-SPI, RAK831-SPI ou tout autre par configuration manuelle).
Puisqu'il n'est pas possible de savoir dans quelles fréquences les appareils LORA fonctionnent, nous avons créé un script qui peut changer de canaux de passerelle des bandes de fréquence US915 et EU868 à des fins de reniflement. Bien qu'il existe des passerelles professionnelles et coûteuses qui prennent en charge 32 ou 64 canaux, la plupart des passerelles prennent en charge jusqu'à 8 canaux. Ce script est destiné à fonctionner dans ce type de passerelles.
Au moins dans la bande de fréquences US915, les 8 premiers canaux sont les plus utilisés. Mais il existe des implémentations bien connues qui utilisent un autre groupe de canaux, comme par exemple les réseaux de choses, qui utilisent le deuxième groupe (8-15) des canaux pour la communication de liaison montante.
Actuellement, nous ne prenons pas en charge d'autres bandes de fréquences, mais, avec peu de modifications à ces scripts, vous pourriez le faire par vous-même :).
Nous avons téléchargé une vidéo de ce cadre en action (même scénario présenté à Blackhat 2019): https://youtu.be/mm6a2rvnocs. Les étapes détaillées de la démo sont dans la description de la vidéo YouTube.
FAIRE
Ce projet est sous licence sous licence de clause BSD-3.