
Este projeto pretende fornecer um conjunto de ferramentas para criar, interpretar, enviar, analisar e quebrar um conjunto de pacotes LoRaWAN, a fim de auditar ou realizar pentest na segurança de uma infraestrutura LoRaWAN.
As implementações de IoT continuam crescendo e uma parte desse crescimento significativo é composta por milhões de sensores LPWAN (rede de longa distância de baixa potência) implantados em centenas de cidades (Cidades Inteligentes) ao redor do mundo, também em indústrias e residências. Uma das tecnologias LPWAN mais utilizadas é LoRa, para a qual LoRaWAN é o padrão de rede (camada MAC). LoRaWAN é um protocolo seguro com criptografia embutida, mas problemas de implementação e fraquezas afetam a segurança da maioria das implementações atuais.
Este projeto pretende fornecer uma série de ferramentas para criar, analisar, enviar, analisar e quebrar um conjunto de pacotes LoRaWAN, a fim de auditar ou testar a segurança de uma infraestrutura LoRaWAN.
Abaixo, a estrutura deste repositório:
|-- 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
Fornecemos diferentes opções para ter seu LoraWAN Auditing Framework em funcionamento:
tools/, para evitar problemas com mapeamento de portas do Docker.localhost. Veja as instruções abaixo para configurar o Docker.Estas instruções fornecerão uma cópia do projeto e suas dependências em sua máquina local. Os comandos abaixo são para um ambiente baseado em Debian:
Clone este repositório: git clone --recurse-submodules https://github.com/IOActive/laf.git
Instale python3:
sudo apt-get updatesudo apt-get install python3.6Baixe e instale as dependências python:
sudo pip3 install paho-mqtt && sudo pip3 install sqlalchemy && sudo pip3 install psycopg2-binary &&sudo pip3 install python-dateutilDefina PYTHONPATH e ENVIRONMENT
cd laf && export PYTHONPATH=$(pwd) && export ENVIRONMENT='DEV'Instale e configure golang:
cd ~/Downloadssudo tar -C /usr/local -xvzf YOUR_GOLANG_FILEexport PATH=$PATH:/usr/local/go/binE pronto!
Esta abordagem evita lidar com a instalação de dependências e inicia um banco de dados PostgreSQL onde as ferramentas salvam pacotes e dados. Contêineres:
Passos:
git clone https://github.com/IOActive/laf.gitcd laf/docker-compose up --builddocker exec -ti laf_tools_1 /bin/bashVocê pode verificar os dados no banco usando pgAdmin:
Primeiro, acesse pgAdmin:
Em seguida, você precisa adicionar o servidor:
Aqui está a descrição dos diretórios e das ferramentas/funções dentro deles.
O principal objetivo das ferramentas fornecidas neste diretório é facilitar a execução de um teste de penetração em uma infraestrutura LoRaWAN.
Esta ferramenta destina-se a enviar pacotes uplink (para o servidor de rede ou gatewayBridge, dependendo da infraestrutura) ou pacotes downlink (para o packet-forwarder). Opcionalmente, os pacotes podem ser "fuzzeados" e um MIC válido pode ser calculado.
Argumentos opcionais:
-h, --help show this help message and exit
--lcl-port LCL_PORT Porta de origem, ex. --lcl-port=623.
--timeout TIMEOUT Tempo em segundos entre cada pacote enviado. Padrão é
1s. Neste tempo, o remetente escutará por respostas.
--repeat Envia a mensagem/s várias vezes
--fuzz-out FUZZ_OUT [FUZZ_OUT ...]
Fuzzeia os dados enviados para a porta de destino
(veja modos de fuzzing em utils/fuzzer.py),
ex. --fuzz-out 1 2.
--key KEY Insira a chave (em formato hex, total de 32 caracteres
/ 16 bytes) para assinar pacotes (calcular e adicionar
um novo MIC). Observe que para JoinRequests deve ser o
AppKey, e para pacotes de dados o NwkSKey. Isso não
pode ser validado antecipadamente por este programa.
ex. 00112233445566778899AABBCCDDEEFF
-a DEVADDR, --devaddr DEVADDR
DeviceAddress para personificar, fornecido em formato
hex (8 caracteres no total), ex. AABB0011.
--fcnt FCNT O contador de quadro a ser definido no pacote de dados
fornecido. Isso não funcionaria em um
JoinRequest/JoinAccept, pois esses pacotes não
possuem fCnt
Argumentos obrigatórios:
--dst-ip DST_IP IP de destino, ex. --dst-ip 192.168.3.101.
--dst-port DST_PORT Porta de destino, ex. --dst-port 623.
--data DATA Pacote UDP. Também é possível adicionar mais pacotes no
array "data" ao final deste script. O pacote deve ser
uma string de bytes (você precisará escapar aspas
duplas). ***EXEMPLO*** com o 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,\"rssi\":-76,\"size\":23,\"data\":\"AMQAAAAAhQAAAgAAAAAAAACH9PRMJi4=\"}]}'" ***EXEMPLO*** usando o formato gatevice [GV] em modo imediato, em 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}'"
Exemplo:
Para enviar um único pacote a cada 2 segundos para (localhost, 10001) da porta 10000, fuzzeando aleatoriamente o MIC e o 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=\"}]}'"
Este proxy UDP destina-se principalmente a ser colocado entre uma série de gateways (packet_forwarders) e um servidor de rede ou gateway bridge, dependendo da infraestrutura sendo avaliada. Também oferece a possibilidade de fuzzear dados na direção desejada (uplink ou downlink)
Argumentos opcionais:
-h, --help show this help message and exit
--collector-port COLLECTOR_PORT
Porta do coletor de dados do packet forwarder,
ex. --collector-port 1701. Veja
auditing/datacollectors/PacketForwarderCollector.py
--collector-ip COLLECTOR_IP
IP do coletor de dados do packet forwarder. Padrão é
localhost. ex. --collector-ip 192.168.1.1. Veja
auditing/datacollectors/PacketForwarderCollector.py
--fuzz-in FUZZ_IN [FUZZ_IN ...]
Fuzzeia dados enviados para a porta de destino nos
modos fornecidos (veja modos de fuzzing em
utils/fuzzer.py), ex. --fuzz-in 1 2 ...
--fuzz-out FUZZ_OUT [FUZZ_OUT ...]
Fuzzeia dados enviados para a porta (origem) nos
modos fornecidos (veja modos de fuzzing em
utils/fuzzer.py), ex. --fuzz-out 1 2 ...
-k KEY, --key KEY Insira um AppSKey de dispositivo (em formato hex,
total de 32 caracteres / 16 bytes) para decifrar seu
FRMPayload e imprimi-lo em texto plano. Você também
pode inserir o AppKey se desejar decifrar um
determinado Join Accept. ex.
00112233445566778899AABBCCDDEEFF
-p PATH, --path PATH Caminho do arquivo onde salvar os dados. Se não
for fornecido, os dados não serão salvos.
--no-log Não imprime pacotes UDP no console
--no-parse Não analisa PHYPayload. Se esta opção for selecionada,
as bibliotecas Golang de /lorawanwrapper/ não serão
importadas (compilação das libs golang não é
necessária)
Argumentos obrigatórios:
--port PORT Porta local para escutar, ex. --port 623.
--dst-ip DST_IP IP do host de destino, ex. --dst-ip 192.168.3.101.
--dst-port DST_PORT Porta do host de destino, ex. --dst-port 623.
Exemplo:
Para enviar pacotes recebidos na porta 1234 para (localhost, 1235) e vice-versa. Os pacotes recebidos na porta serão fuzzeados (o devNonce será alterado aleatoriamente) e encaminhados para (localhost, 1235).
python3 UdpProxy.py --port 1234 --dst-ip 127.0.0.1 --dst-port 1235 --fuzz-in 9
Este proxy TCP destina-se principalmente a ser colocado entre o servidor de rede e um broker MQTT. Também oferece a possibilidade de fuzzear dados.
Argumentos opcionais:
-h, --help show this help message and exit
--fuzz-in FUZZ_IN [FUZZ_IN ...]
Fuzzeia dados enviados para a porta de destino nos
modos fornecidos (veja modos de fuzzing em
utils/fuzzer.py)
Argumentos obrigatórios:
--lcl-port LCL_PORT Porta local para escutar, ex. --lcl-port=623.
--dst-ip DST_IP IP do host de destino, ex. --dst-ip=192.168.3.101.
--dst-port DST_PORT Porta do host de destino, ex. --dst-port=623.
Exemplo:
Enviar e receber dados de (localhost, 1884) para (localhost, 1883)
python3 TcpProxy.py --lcl-port 1884 --dst-ip 127.0.0.1 --dst-port 1883
Este diretório contém uma série de scripts para analisar, criar, forçar brute force, etc., pacotes LoRaWAN.
Este script recebe um JoinAccept ou JoinRequest em Base64 e tenta decifrar seu AppKey com um conjunto de chaves possíveis que podem ser fornecidas em um arquivo ou geradas em tempo real.
Argumentos opcionais:
-h, --help show this help message and exit
-k KEYS, --keys KEYS Arquivo contendo uma lista de chaves, separadas por
\n. Usará /auditing/analyzers/bruteForcer/keys.txt
por padrão
--dont-generate Selecione esta opção se não quiser gerar chaves em
tempo real com as seguintes combinações:
1- Combinar o primeiro byte e os últimos quinze bytes.
ex. AABBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
2- Combinar posições pares e ímpares dos bytes
igualmente. ex. AABBAABBAABBAABBAABBAABBAABBAABB
3- Os primeiros 14 bytes em 00 e combinar os últimos 2.
ex. 0000000000000000000000000000BA01
Argumentos obrigatórios:
-a ACCEPT, --accept ACCEPT
Join Accept em formato Base64 para ser forçado por brute
force. ex. -a IHvAP4MXo5Qo6tdV+Yfk08o=
-r REQUEST, --request REQUEST
Join Request em formato Base64 para ser forçado por brute
force. ex. -r AMQAAAAAhQAAAgAAAAAAAADcYldcgbc=
Exemplo:
Quebrar um JoinRequest com um conjunto de chaves do arquivo my-keys.txt e também gerar aproximadamente 200.000 chaves dinamicamente.
python3 BruteForcer.py -a IHvAP4MXo5Qo6tdV+Yfk08o= -r AMQAAAAAhQAAAgAAAAAAAADcYldcgbc= -k ./my-keys.txt
Este script recebe um pacote PHYPayload em Base64 e uma chave que pode ser o NwkSKey ou AppKey, dependendo do tipo de pacote, e gera o novo MIC.
Argumentos opcionais:
-h, --help show this help message and exit
--jakey JAKEY [Somente JoinAccept]. Insira a chave usada para
criptografar o JoinAccept anteriormente (em formato
hex, total de 32 caracteres / 16 bytes). Isso não
pode ser validado antecipadamente por este programa.
ex. 00112233445566778899AABBCCDDEEFF. Uma chave
válida de exemplo para o JoinAccept
"IB1scNmwJRA32RfMbvwe3oI=" é
"f5a3b185dfe452c8edca3499abcd0341"
Argumentos obrigatórios:
-d DATA, --data DATA Dados em Base64 a serem assinados. ex. -d
AE0jb3GsOdJVAwD1HInrJ7i3yXAFxKU=
-k KEY, --key KEY Insira a nova chave (em formato hex, total de 32
caracteres / 16 bytes) para assinar pacotes
(calcular e adicionar um novo MIC). Observe que para
JoinRequest/JoinAccept deve ser o AppKey, e para
pacotes de dados o NwkSKey. Isso não pode ser
validado antecipadamente por este programa.
ex. 00112233445566778899AABBCCDDEEFF
Exemplo:
Assinar o PHYPayload fornecido com o AppKey 00112233445566778899AABBCCDDEEFF.
python3 MicGenerator.py -d AE0jb3GsOdJVAwD1HInrJ7i3yXAFxKU= -k 00112233445566778899AABBCCDDEEFF
Este script recebe um pacote JSON LoRaWAN e o transforma em Base64. Ele faz o inverso do packetParser.py, então a saída desse script pode ser usada aqui e vice-versa.
Argumentos opcionais:
-h, --help show this help message and exit
-k KEY, --key KEY Insira um AppSKey ou AppKey de dispositivo (em
formato hex, total de 32 caracteres / 16 bytes) para
criptografar o FRMPayload ou um Join Accept.
ex. F5A3B185DFE452C8EDCA3499ABCD0341
--nwkskey NWKSKEY Insira a chave de sessão da rede se desejar
gerar um pacote de dados com um MIC válido.
Argumentos obrigatórios:
-j JSON, --json JSON Objeto JSON para analisar. ex. -j '{"mhdr":
{"mType":"JoinRequest","major":"LoRaWANR1"},"macPayloa
d":{"joinEUI":"55d239ac716f234d","devEUI":"b827eb891cf
50003","devNonce":51639},"mic":"7005c4a5"}'
Exemplo:
Obter um PHYPayload de JoinRequest em Base64 com base no JSON com os valores passados.
python3 PacketCrafter.py -j '{"mhdr":{"mType":"JoinRequest","major":"LoRaWANR1"},"macPayload":{"joinEUI":"55d239ac716f234d","devEUI":"b827eb891cf50003","devNonce":51639},"mic":"7005c4a5"}'
Este script analisa e imprime um único dado PHYPayload LoRaWAN em Base64. Ele faz o inverso do packetCrafter.py, então a saída desse script pode ser usada aqui e vice-versa.
Argumentos opcionais:
-h, --help show this help message and exit
-k KEY, --key KEY Insira um AppKey ou AppSKey de dispositivo,
dependendo do pacote a ser decifrado (join accept ou
pacote de dados). Deve estar em formato hex, total de
32 caracteres / 16 bytes.
ex. 00112233445566778899AABBCCDDEEFF
Argumentos obrigatórios:
-d DATA, --data DATA Dados em Base64 a serem analisados. ex. -d
AE0jb3GsOdJVAwD1HInrJ7i3yXAFxKU=
Exemplo:
Obter o JoinRequest em formato JSON do exemplo acima.
python3 PacketParser.py -d AE0jb3GsOdJVAwD1HInrJ7i3yXAFxKU=
Este script recebe um JoinAccept e um JoinRequest em Base64, e um AppKey para gerar as chaves de sessão. Um exemplo de uso:
Argumentos opcionais:
-h, --help show this help message and exit
Argumentos obrigatórios:
-a JACCEPT, --jaccept JACCEPT
Payload JoinAccept em base64
-r JREQUEST, --jrequest JREQUEST
Payload JoinRequest em base64
-k KEY, --key KEY Insira um AppKey de dispositivo (em formato hex,
total de 32 caracteres / 16 bytes).
ex. 00112233445566778899AABBCCDDEEFF
Exemplo:
Obter o AppSKey e NwkSKey com os seguintes dados de join.
python3 SessionKeysGenerator.py -r AE0jb3GsOdJVAwD1HInrJ7i3yXAFxKU= -a IB1scNmwJRA32RfMbvwe3oI= -k f5a3b185dfe452c8edca3499abcd0341
Estas são funções auxiliares usadas por UdpSender.py e UdpProxy.py. Em Fuzzer.py, você pode ver os modos de fuzzing implementados.
O propósito geral deste diretório é coletar pacotes LoRaWAN e analisar diferentes aspectos do tráfego, bem como tentar um conjunto de chaves para tentar forçar brute force no AppKey.
Este diretório contém um conjunto de scripts que recebem pacotes LoRaWAN de diferentes fontes (por exemplo, gateway packet_forwarder, The Things Network, etc.) e os salvam em arquivos, com um formato padrão. Esses arquivos devem ser buscados posteriormente pelo script /auditing/analyzers/LafProcessData.py para executar diferentes sub-ferramentas.
Este script conecta ao broker mqqt, recupera todos os tópicos e salva as mensagens em um arquivo no campo especificado. O nome do arquivo é composto pela data em que este script foi iniciado.
Argumentos opcionais:-h, --help mostra esta mensagem de ajuda e sai --collector-id COLLECTOR_ID O ID do dataCollector. Este ID será associado aos pacotes salvos no BD. ex. --id 1 --organization-id ORGANIZATION_ID O ID do dataCollector. Este ID será associado aos pacotes salvos no BD. ex. --id 1 --topics TOPICS [TOPICS ...] Lista o(s) tópico(s) que deseja inscrever separados por espaços. Se nada for informado, o padrão será "#.
Argumentos obrigatórios:
--ip IP IP do broker MQTT, ex. --ip 192.168.3.101.
--port PORT Porta do broker MQTT, ex. --port 623.
Exemplo:
Conecte-se ao broker MQTT com ip 200.200.200.200 na porta padrão (1883).
python3 GenericMqttCollector.py --ip 200.200.200.200 --port 1883
Este script conecta-se a um broker mqqt loraserver.io e salva mensagens no BD. Você deve especificar um collectorID único e pode especificar os tópicos aos quais deseja se inscrever.
Argumentos opcionais:
-h, --help mostra esta mensagem de ajuda e sai
--port PORT Porta do broker MQTT, ex. --port 623. Padrão 1883.
--collector-id COLLECTOR_ID
O ID do dataCollector. Este ID será
associado aos pacotes salvos no BD. ex. --id 1
--organization-id ORGANIZATION_ID
O ID do dataCollector. Este ID será
associado aos pacotes salvos no BD. ex. --id 1
--topics TOPICS [TOPICS ...]
Lista o(s) tópico(s) que deseja inscrever separados por
espaços. Se nada for informado, o padrão será "#.
Argumentos obrigatórios:
--ip IP IP do broker MQTT, ex. --ip 192.168.3.101.
Este script recebe pacotes UDP do proxy UDP no formato packet_forwarder do gateway e os persiste.
Argumentos opcionais:
-h, --help mostra esta mensagem de ajuda e sai
--collector-id COLLECTOR_ID
O ID do dataCollector. Este ID será
associado aos pacotes salvos no BD. ex. --id 1
--organization-id ORGANIZATION_ID
O ID do dataCollector. Este ID será
associado aos pacotes salvos no BD. ex. --id 1
Argumentos obrigatórios:
-n NAME, --name NAME Identificador de string único do Coletor de Dados. ex.
--name semtech_collector
-p PORT, --port PORT Porta onde escutar por pacotes UDP. --port 1702.
Exemplo:
Grave dados entre um gateway enviando para a porta local 1700 e um xserver de rede ouvindo em (localhost, 1701). Salve os dados no diretório ./.
python3 PacketForwarderCollector.py --name semtech_collector --port 1700
Este script lê de um arquivo, arquivos ou stdin e executa diferentes sub-ferramentas. Dependendo da opção selecionada, você pode executar uma análise do tráfego LoRaWAN, tentar fazer brute force do AppKey, ou analisar todos os pacotes recebidos. Essas opções podem ser combinadas.
Argumentos opcionais:
Este script recupera pacotes do BD e executa diferentes sub-ferramentas.
Em seguida, cada sub-ferramenta salvará os dados de saída no BD. Veja cada opção para
mais informações.
argumentos opcionais:
-h, --help mostra esta mensagem de ajuda e sai
-a, --analyze Coleta e analisa diferentes aspectos do tráfego. Se o
Bruteforcer (-b) estiver ativado, os resultados serão
correlacionados
-b, --bforce Tenta fazer brute force das AppKeys com JoinRequests e
JoinAccepts payloads
-k KEYS, --keys KEYS [Bruteforcer] Caminho do arquivo de chaves. Se não fornecido,
"bruteForcer/keys.txt" será usado
--no-gen [Bruteforcer] Não gerar chaves, apenas tentar chaves de
arquivos
-p, --parse Analisar o PHYPayload em informação legível
--from-id FROM_ID ID do pacote a partir do qual iniciar o processamento.
--to-id TO_ID Último ID do pacote a ser processado.
Exemplo:
Processe pacotes no BD a partir do ID de pacote 1000, execute uma análise de tráfego e tente quebrar AppKeys fornecidas em my-keys.txt, mas não gere mais chaves dinamicamente.
python3 LafProcessData.py -a -b -k my-keys.txt --no-gen --from-id 1000
Estes scripts fornecem a funcionalidade orquestrada por LafProcessData.py. Abaixo, os alertas que são implementados por LafPacketAnalysis.py e LafBruteForcer.py:
Este diretório fornece um conjunto de wrappers para a biblioteca https://github.com/brocaar/lorawan/, que é escrita em Golang. Essas funções são implementadas pelas ferramentas.
Aqui você encontrará uma série de scripts destinados a automatizar diferentes tarefas. Certifique-se de dar permissão de execução a eles, se necessário (chmod +x seu_script para Linux/MacOS).
Configure facilmente seu gateway e altere seus canais para fins de sniffing. Para mais informações sobre como usá-los, você pode ver o readme neste diretório.
Este script é usado para instalar todos os pacotes de software necessários em um Raspberry PI para criar um Gateway LoRaWAN em conjunto com um Concentrador LoRa conectado (iC980-SPI, RHF0M301-SPI, RAK831-SPI ou qualquer outro por configuração manual).
Como não é possível saber em quais frequências os dispositivos LoRa estão operando, criamos um script que pode alternar os canais dos gateways das faixas de frequência US915 e EU868 para fins de sniffing. Embora existam gateways profissionais e caros que suportam 32 ou 64 canais, a maioria dos gateways suporta até 8 canais. Este script é destinado a ser executado neste tipo de gateways.
Pelo menos na faixa de frequência US915, os primeiros 8 canais são os mais usados. Mas existem implementações conhecidas que usam outro grupo de canais, como por exemplo The Things Networks, que usam o segundo grupo (8-15) de canais para comunicação uplink.
Atualmente não suportamos outras faixas de frequência, mas com algumas alterações nesses scripts você seria capaz de fazer isso por conta própria :)
TODO
This project is licensed under BSD-3-Clause License.
export GOPATH="$HOME/go"Compile a biblioteca go:
cd laf/lorawanwrapper/utilsgo build -o lorawanWrapper.so -buildmode=c-shared jsonUnmarshaler.go lorawanWrapper.go micGenerator.go sessionKeysGenerator.go hashGenerator.goDependendo de qual banco de dados você deseja usar:
a. PostreSQL: Siga as instruções 'Instalar LAF usando Docker' até o 3º passo.
b. SQLite:
cd laf/auditing/db__init__.py com seu editor de texto preferido e comente as linhas a serem usadas com Postgres (conexão com o banco e variáveis de ambiente) e descomente a linha a ser usada com sqlite.| ID | Título | Analisador | Nível de risco | Descrição | Ação Recomendada |
|---|
| LAF-001 | DevNonce repetido | LafPacketAnalysis.py | Baixo | DevNonces para cada dispositivo devem ser aleatórios o suficiente para não colidirem. Se o mesmo DevNonce foi repetido em muitas mensagens, pode-se inferir que um dispositivo está sob um ataque de repetição. Isto é, um atacante que capturou um JoinRequest e está tentando enviá-lo novamente ao gateway. | Verifique como os DevNonces são gerados: a função que os gera deve ser implementada usando uma biblioteca aleatória. Além disso, certifique-se de que o servidor verifique os DevNonces históricos (eles devem ser persistidos no BD), para não aceitar um JoinRequest antigo e válido enviado anteriormente pelo dispositivo e, assim, gerar uma nova sessão. |
| LAF-002 | DevEUIs compartilhando o mesmo DevAddr | LafPacketAnalysis.py | Informação | Dois dispositivos diferentes podem ter recebido o mesmo DevAddr. Isso não é uma ameaça de segurança. | Se o dispositivo for ativado por over the air (OTAA): Verifique a lógica usada para atribuir DevAddrs e certifique-se de que o servidor não atribua o mesmo DevAddr a dispositivos diferentes. Se o dispositivo for ativado por personalização (ABP): Verifique se o DevAddr configurado no firmware de um dispositivo é único na rede LoRaWAN. |
| LAF-003 | Join repetido | TODO | Médio | Um pacote de join request duplicado foi detectado, o que pode implicar que o servidor LoRaWAN está sob um ataque de repetição. Isto é, um atacante que pode ter capturado um pacote de join request anterior e está enviando-o novamente ao servidor LoRaWAN, para tentar gerar uma nova sessão. | Verifique como os DevNonces são gerados: a função que os gera deve ser implementada usando uma biblioteca aleatória. Além disso, certifique-se de que o servidor verifique os DevNonces históricos (eles devem ser persistidos no BD), para não aceitar um JoinRequest antigo e válido enviado anteriormente pelo dispositivo e, assim, gerar uma nova sessão. |
| LAF-004 | Repetição de pacotes de uplink de dados | TODO | Médio | Um pacote de uplink duplicado foi detectado, o que pode implicar que o servidor LoRaWAN está sob um ataque de repetição. Isto é, um atacante que pode ter capturado um pacote de uplink (enviado pelo dispositivo) e está enviando-o novamente ao servidor LoRaWAN. | Em dispositivos ativados por over the air (OTAA): Certifique-se de que as chaves de sessão sejam regeradas após cada reinicialização do dispositivo ou estouro de contador para evitar qualquer efeito deste ataque. Em dispositivos ativados por personalização (ABP) do LoRaWAN v1.0.*, nada pode ser feito para prevenir um ataque de repetição, exceto mudar o dispositivo para OTAA. |
| LAF-005 | Repetição de pacotes de downlink de dados | TODO | Alto | Um pacote de downlink duplicado foi detectado. O servidor está respondendo a um ataque de repetição ou está gerando tráfego atípico para dispositivos. | Verifique os logs do servidor e verifique se as ações recomendadas anteriores foram implementadas |
| LAF-006 | Possível dispositivo ABP (contador reiniciado e sem join) | LafPacketAnalysis.py | Alto | Se o contador foi reiniciado (voltou a 0), o DevAddr permaneceu o mesmo, e nenhum processo de Join anterior foi detectado, pode implicar que o dispositivo está ativado por personalização (ABP). A implementação de dispositivos ABP é desencorajada porque nenhum processo de join é feito, o que significa que as chaves de sessão permanecem as mesmas para sempre. Um dispositivo que não altera suas chaves de sessão está sujeito a diferentes ataques, como espionagem ou repetição. | Todos os dispositivos ativados por personalização (ABP) devem ser substituídos por dispositivos ativados por over the air (OTAA) se possível. A implementação de dispositivos ABP é desencorajada. |
| LAF-007 | Recebido contador menor que o esperado (distinto de 0) | LafPacketAnalysis.py | Médio | Se um atacante obtiver um par de chaves de sessão (por ter roubado a AppKey em dispositivos OTAA ou a AppSKey/NwkSKey em dispositivos ABP), ele/ela seria capaz de enviar dados falsos e válidos para o servidor. Para que o servidor aceite mensagens falsificadas, é necessário que o FCnt (Frame Counter) da mensagem seja maior que o FCnt da última mensagem enviada. Em um cenário onde o dispositivo falsificado original continua enviando mensagens, o servidor começaria a descartar mensagens (válidas) pois elas teriam um FCnt menor. Portanto, quando mensagens com um valor de FCnt menor que o esperado pelo servidor LoRaWAN estão sendo recebidas, é possível inferir que uma sessão paralela foi estabelecida. | Se o dispositivo for ativado por over the air (OTAA), altere sua AppKey porque provavelmente foi comprometida. Se for ativado por personalização, altere sua AppSKey e NwkSKey. Além disso, certifique-se de que o servidor LoRaWAN esteja atualizado e não esteja aceitando mensagens duplicadas. |
| LAF-008 | Senha quebrada com JoinRequest | LafBruteforcer.py | Alto | Foi possível descriptografar uma mensagem JoinRequest usando uma AppKey conhecida. | Use AppKeys diferentes das fornecidas pelos fabricantes ou use chaves mais aleatórias. |
| LAF-009 | Senha quebrada | LafBruteforcer.py | Alto | A AppKey do dispositivo foi encontrada tentando com uma string conhecida ou não aleatória. Foi descriptografada usando um par de mensagens de join (Request e Accept). | Use um gerador de chaves aleatório para a AppKey, em vez de usar as fornecidas pelos fabricantes. Além disso, não defina a mesma AppKey para mais de um dispositivo e não gere AppKeys usando uma lógica previsível (ex. valores incrementais, inverter certos bytes, etc.) |
| LAF-010 | Gateway mudou de localização | LafPacketAnalysis.py | Médio | Se o gateway não deve mudar de localização. Pode ter sido roubado, movido, ou um gateway falso pode estar tentando se passar pelo gateway legítimo. | Certifique-se de que o gateway não foi adulterado, tanto fisicamente quanto logicamente. |