
이 프로젝트는 LoRaWAN 인프라의 보안을 감사하거나 침투 테스트하기 위해 일련의 LoRaWAN 패킷을 제작, 구문 분석, 전송, 분석 및 크랙할 수 있는 도구 모음을 제공하는 것을 목표로 합니다.
IoT 배포는 계속해서 성장하고 있으며, 그 상당한 성장의 일부는 전 세계 수백 개 도시(스마트 시티), 산업 및 가정에 배포된 수백만 개의 LPWAN(저전력 광역 네트워크) 센서로 구성됩니다. 가장 많이 사용되는 LPWAN 기술 중 하나는 LoRa이며, LoRaWAN은 네트워크 표준(MAC 계층)입니다. LoRaWAN은 내장된 암호화를 사용하는 보안 프로토콜이지만, 구현 문제와 취약점으로 인해 대부분의 현재 배포의 보안이 영향을 받습니다.
이 프로젝트는 LoRaWAN 인프라의 보안을 감사하거나 침투 테스트하기 위해 일련의 LoRaWAN 패킷을 조작, 구문 분석, 전송, 분석 및 크랙하는 도구 세트를 제공하고자 합니다.
아래는 이 저장소의 구조입니다:
|-- 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
LoRaWAN 감사 프레임워크를 실행할 수 있는 다양한 옵션을 제공합니다:
tools/ 디렉토리에 있는 침투 테스트 도구를 사용하는 것이라면 Docker 포트 매핑 문제를 피하기 위해 이 옵션을 권장합니다.localhost를 통해 Postgres에 연결을 시도합니다. Docker 설정에 대한 지침은 아래를 참조하세요.다음 지침을 통해 프로젝트와 그 종속성을 로컬 머신에 복사합니다. 아래 명령어는 Debian 기반 환경을 위한 것입니다:
이 저장소를 클론합니다: git clone --recurse-submodules https://github.com/IOActive/laf.git
python3를 설치합니다:
sudo apt-get updatesudo apt-get install python3.6Python 종속성을 다운로드하여 설치합니다:
sudo pip3 install paho-mqtt && sudo pip3 install sqlalchemy && sudo pip3 install psycopg2-binary &&sudo pip3 install python-dateutilPYTHONPATH 및 ENVIRONMENT를 설정합니다:
cd laf && export PYTHONPATH=$(pwd) && export ENVIRONMENT='DEV'golang을 설치하고 설정합니다:
cd ~/Downloadssudo tar -C /usr/local -xvzf YOUR_GOLANG_FILEexport PATH=$PATH:/usr/local/go/binexport GOPATH="$HOME/go"이상입니다!
이 방법은 종속성 설치를 처리할 필요가 없으며, 도구가 패킷과 데이터를 저장하는 PostgreSQL DB를 시작합니다. 컨테이너:
단계:
git clone https://github.com/IOActive/laf.gitcd laf/로 이동합니다.docker-compose up --builddocker exec -ti laf_tools_1 /bin/bashpgAdmin을 사용하여 DB의 데이터를 확인할 수 있습니다:
먼저, pgAdmin에 접속합니다:
그런 다음, 서버를 추가해야 합니다:
다음은 디렉토리와 그 안에 있는 도구/기능에 대한 설명입니다.
이 디렉토리에 제공된 도구의 주요 목적은 LoRaWAN 인프라에 대한 침투 테스트 실행을 용이하게 하는 것입니다.
이 도구는 업링크 패킷(인프라에 따라 네트워크 서버 또는 게이트웨이 브리지로) 또는 다운링크 패킷(패킷-포워더로)을 전송하기 위한 것입니다. 선택적으로 패킷을 퍼징하거나 유효한 MIC를 계산할 수 있습니다.
선택적 인수:
-h, --help 도움말 메시지를 표시하고 종료합니다.
--lcl-port LCL_PORT 소스 포트, 예: --lcl-port=623.
--timeout TIMEOUT 전송된 각 패킷 사이의 시간(초). 기본값은
1초입니다. 이 시간 동안 발신자는 응답을 기다립니다.
--repeat 메시지를 여러 번 보냅니다.
--fuzz-out FUZZ_OUT [FUZZ_OUT ...]
대상 포트로 전송되는 데이터를 퍼징합니다(utils/fuzzer.py의 퍼징 모드 참조), 예: --fuzz-out 1 2.
--key KEY 패킷에 서명하기 위해 키를 입력합니다(16진수 형식, 총 32자
/ 16바이트). JoinRequest의 경우 AppKey여야 하며,
데이터 패킷의 경우 NwkSKey여야 합니다. 이는 이 프로그램에서
사전에 검증할 수 없습니다. 예:
00112233445566778899AABBCCDDEEFF
-a DEVADDR, --devaddr DEVADDR
가장할 장치 주소를 16진수 형식으로 입력합니다(8자
총), 예: AABB0011.
--fcnt FCNT 주어진 데이터 패킷에 설정할 프레임 카운터입니다.
이 패킷에는 fCnt가 없으므로 JoinRequest/JoinAccept에서는 작동하지 않습니다.
필수 인수:
--dst-ip DST_IP 대상 IP, 예: --dst-ip 192.168.3.101.
--dst-port DST_PORT 대상 포트, 예: --dst-port 623.
--data DATA UDP 패킷입니다. 이 스크립트 끝의 "data" 배열에 추가 패킷을
추가할 수도 있습니다. 패킷은 바이트 문자열이어야 합니다(큰따옴표는
이스케이프해야 합니다). ***예제*** 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=\"}]}'" ***예제*** gatevice
[GV] 형식을 즉시 모드로 보내는 경우, BW125 및
주파수 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}'"
예제:
2초마다 (localhost, 10001)로 포트 10000에서 단일 패킷을 보내고, MIC와 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=\"}]}'"
이 UDP 프록시는 주로 평가 중인 인프라에 따라 여러 게이트웨이(packet_forwarders)와 네트워크 서버 또는 게이트웨이 브리지 사이에 배치되도록 설계되었습니다. 또한 원하는 방향(업링크 또는 다운링크)으로 데이터 퍼징 기능을 제공합니다.
선택적 인수:
-h, --help 도움말 메시지를 표시하고 종료합니다.
--collector-port COLLECTOR_PORT
패킷 포워더 데이터 수집기 포트, 예: --collector-
port 1701. 자세한 내용은
auditing/datacollectors/PacketForwarderCollector.py를 참조하세요.
--collector-ip COLLECTOR_IP
패킷 포워더 데이터 수집기 IP. 기본값은
localhost입니다. 예: --collector-ip 192.168.1.1. 자세한 내용은
auditing/datacollectors/PacketForwarderCollector.py를 참조하세요.
--fuzz-in FUZZ_IN [FUZZ_IN ...]
대상 포트로 전송되는 데이터를 주어진 모드로 퍼징합니다(utils/fuzzer.py의 퍼징 모드 참조), 예: --fuzz-in 1 2
...
--fuzz-out FUZZ_OUT [FUZZ_OUT ...]
(소스) 포트로 전송되는 데이터를 주어진 모드로 퍼징합니다(utils/fuzzer.py의 퍼징 모드 참조), 예: --fuzz-out
1 2 ...
-k KEY, --key KEY 장치 AppSKey를 입력합니다(16진수 형식, 총 32자
/ 16바이트)로 FRMPayload를 복호화하고
일반 텍스트로 출력합니다. 또한 Join Accept를 복호화하려면
AppKey를 입력할 수도 있습니다. 예:
00112233445566778899AABBCCDDEEFF
-p PATH, --path PATH 데이터를 저장할 파일 경로. 제공되지 않으면
데이터가 저장되지 않습니다.
--no-log UDP 패키지를 콘솔에 출력하지 않습니다.
--no-parse PHYPayload를 구문 분석하지 않습니다. 이 옵션을 선택하면
/lorawanwrapper/의 Golang 라이브러리를 가져오지 않습니다(golang
라이브러리 컴파일이 필요하지 않습니다).
필수 인수:
--port PORT 수신할 로컬 포트, 예: --port 623.
--dst-ip DST_IP 대상 호스트 IP, 예: --dst-ip 192.168.3.101.
--dst-port DST_PORT 대상 호스트 포트, 예: --dst-port 623.
예제:
포트 1234에서 수신된 패킷을 (localhost, 1235)로 보내고 그 반대로 보냅니다. 포트에서 수신된 패킷은 퍼징(devNonce가 무작위로 변경됨)된 후 (localhost, 1235)로 전달됩니다.
python3 UdpProxy.py --port 1234 --dst-ip 127.0.0.1 --dst-port 1235 --fuzz-in 9
이 TCP 프록시는 주로 네트워크 서버와 MQTT 브로커 사이에 배치되도록 설계되었습니다. 또한 데이터 퍼징 기능을 제공합니다.
선택적 인수:
-h, --help 도움말 메시지를 표시하고 종료합니다.
--fuzz-in FUZZ_IN [FUZZ_IN ...]
대상 포트로 전송되는 데이터를 주어진 모드로 퍼징합니다(utils/fuzzer.py의 퍼징 모드 참조).
필수 인수:
--lcl-port LCL_PORT 수신할 로컬 포트, 예: --lcl-port=623.
--dst-ip DST_IP 대상 호스트 IP, 예: --dst-ip=192.168.3.101.
--dst-port DST_PORT 대상 호스트 포트, 예: --dst-port=623.
예제:
(localhost, 1884)와 (localhost, 1883) 간에 데이터를 송수신합니다.
python3 TcpProxy.py --lcl-port 1884 --dst-ip 127.0.0.1 --dst-port 1883
이 디렉토리에는 LoRaWAN 패킷을 구문 분석, 조작, 무차별 대입 등 하는 스크립트 시리즈가 포함되어 있습니다.
이 스크립트는 Base64 형식의 JoinAccept 또는 JoinRequest를 받아 파일로 제공되거나 즉석에서 생성될 수 있는 가능한 키 세트를 사용하여 AppKey를 복호화하려고 시도합니다.
선택적 인수:
-h, --help 도움말 메시지를 표시하고 종료합니다.
-k KEYS, --keys KEYS 키 목록을 포함하는 파일(줄바꿈으로 구분). 기본값은
/auditing/analyzers/bruteForcer/keys.txt를 사용합니다.
--dont-generate 이 옵션을 선택하면 다음 조합으로 키를 즉석에서 생성하지 않습니다:
1- 첫 번째 바이트와 마지막 15바이트를 결합합니다. 예:
AABBBBBBBBBBBBBBBBBBBBBBBBBBBBBB 2- 짝수 및 홀수
바이트 위치를 동일하게 결합합니다. 예:
AABBAABBAABBAABBAABBAABBAABBAABB 3- 처음 14바이트를
00으로 설정하고 마지막 2바이트를 결합합니다. 예:
0000000000000000000000000000BA01
필수 인수:
-a ACCEPT, --accept ACCEPT
무차별 대입할 Base64 형식의 Join Accept. 예: -a
IHvAP4MXo5Qo6tdV+Yfk08o=
-r REQUEST, --request REQUEST
무차별 대입할 Base64 형식의 Join Request. 예:
-r AMQAAAAAhQAAAgAAAAAAAADcYldcgbc=
예제:
my-keys.txt의 키 세트로 JoinRequest를 크랙하고 동적으로 약 200,000개를 더 생성합니다.
python3 BruteForcer.py -a IHvAP4MXo5Qo6tdV+Yfk08o= -r AMQAAAAAhQAAAgAAAAAAAADcYldcgbc= -k ./my-keys.txt
이 스크립트는 Base64 형식의 PHYPayload 패킷과 패킷 유형에 따라 NwkSKey 또는 AppKey가 될 수 있는 키를 받아 새 MIC를 생성합니다.
선택적 인수:
-h, --help 도움말 메시지를 표시하고 종료합니다.
--jakey JAKEY [JoinAccept ONLY]. 이전에 JoinAccept를 암호화하는 데 사용된 키를 입력합니다(16진수 형식, 총 32자
/ 16바이트). 이는 이 프로그램에서 사전에
검증할 수 없습니다. 예:
00112233445566778899AABBCCDDEEFF. JoinAccept "IB1scNmwJRA32RfMbvwe3oI="에 대한
유효한 키 샘플은 "f5a3b185dfe452c8edca3499abcd0341"입니다.
필수 인수:
-d DATA, --data DATA 서명할 Base64 데이터. 예: -d
AE0jb3GsOdJVAwD1HInrJ7i3yXAFxKU=
-k KEY, --key KEY 패킷에 서명할 새 키를 입력합니다(16진수 형식, 총 32자
/ 16바이트). JoinRequest/JoinAccept의 경우
AppKey여야 하며, 데이터 패킷의 경우 NwkSKey여야 합니다.
이는 이 프로그램에서 사전에 검증할 수 없습니다. 예:
00112233445566778899AABBCCDDEEFF
예제:
주어진 PHYPayload를 AppKey 00112233445566778899AABBCCDDEEFF로 서명합니다.
python3 MicGenerator.py -d AE0jb3GsOdJVAwD1HInrJ7i3yXAFxKU= -k 00112233445566778899AABBCCDDEEFF
이 스크립트는 lorawan JSON 패킷을 받아 Base64로 변환합니다. packetParser.py의 역을 수행하므로 해당 스크립트의 출력을 여기서 사용할 수 있고 그 반대도 마찬가지입니다.
선택적 인수:
-h, --help 도움말 메시지를 표시하고 종료합니다.
-k KEY, --key KEY FRMPayload 또는 Join Accept를 암호화할 장치 AppSKey 또는 AppKey를 입력합니다(16진수 형식, 총
32자 / 16바이트). 예:
F5A3B185DFE452C8EDCA3499ABCD0341
--nwkskey NWKSKEY 유효한 MIC로 데이터 패킷을 생성하려면 네트워크 세션 키를 입력합니다.
필수 인수:
-j JSON, --json JSON 구문 분석할 JSON 객체. 예: -j '{"mhdr":
{"mType":"JoinRequest","major":"LoRaWANR1"},"macPayloa
d":{"joinEUI":"55d239ac716f234d","devEUI":"b827eb891cf
50003","devNonce":51639},"mic":"7005c4a5"}'
예제:
JSON에 전달된 값을 사용하여 JoinRequest PHYPayload를 Base64로 얻습니다.
python3 PacketCrafter.py -j '{"mhdr":{"mType":"JoinRequest","major":"LoRaWANR1"},"macPayload":{"joinEUI":"55d239ac716f234d","devEUI":"b827eb891cf50003","devNonce":51639},"mic":"7005c4a5"}'
이 스크립트는 Base64 형식의 단일 LoRaWAN PHYPayload 데이터를 구문 분석하고 출력합니다. packetCrafter.py의 역을 수행하므로 해당 스크립트의 출력을 여기서 사용할 수 있고 그 반대도 마찬가지입니다.
선택적 인수:
-h, --help 도움말 메시지를 표시하고 종료합니다.
-k KEY, --key KEY 복호화할 패킷(join accept 또는 데이터 패킷)에 따라 장치 AppKey 또는 AppSKey를 입력합니다.
16진수 형식이어야 하며, 총 32자 / 16바이트입니다. 예:
00112233445566778899AABBCCDDEEFF
필수 인수:
-d DATA, --data DATA 구문 분석할 Base64 데이터. 예: -d
AE0jb3GsOdJVAwD1HInrJ7i3yXAFxKU=
예제:
위 예제의 JoinRequest를 JSON 형식으로 얻습니다.
python3 PacketParser.py -d AE0jb3GsOdJVAwD1HInrJ7i3yXAFxKU=
이 스크립트는 Base64 형식의 JoinAccept와 JoinRequest, 그리고 AppKey를 받아 세션 키를 생성합니다. 사용 예:
선택적 인수:
-h, --help 도움말 메시지를 표시하고 종료합니다.
필수 인수:
-a JACCEPT, --jaccept JACCEPT
base64 형식의 JoinAccept 페이로드
-r JREQUEST, --jrequest JREQUEST
base64 형식의 JoinRequest 페이로드
-k KEY, --key KEY 장치 AppKey를 입력합니다(16진수 형식, 총 32자
/ 16바이트). 예:
00112233445566778899AABBCCDDEEFF
예제:
다음 조인 데이터로 AppSKey와 NwkSKey를 얻습니다.
python3 SessionKeysGenerator.py -r AE0jb3GsOdJVAwD1HInrJ7i3yXAFxKU= -a IB1scNmwJRA32RfMbvwe3oI= -k f5a3b185dfe452c8edca3499abcd0341
이것들은 UdpSender.py와 UdpProxy.py에서 사용되는 보조 함수입니다. Fuzzer.py에서 구현된 퍼징 모드를 볼 수 있습니다.
이 디렉토리의 일반적인 목적은 LoRaWAN 패킷을 수집하고 트래픽의 다양한 측면을 분석하며, AppKey를 무차별 대입하려는 키 세트를 시도하는 것입니다.
이 디렉토리에는 다양한 소스(예: 게이트웨이 packet_forwarder, The Things Network 등)에서 LoRaWAN 패킷을 수신하고 표준 형식으로 파일에 저장하는 스크립트 세트가 포함되어 있습니다. 이 파일들은 나중에 하위 도구를 실행하기 위해 스크립트 /auditing/analyzers/LafProcessData.py에 의해 가져와야 합니다.
이 스크립트는 MQTT 브로커에 연결하고 모든 토픽을 검색하며 메시지를 지정된 필드의 파일에 저장합니다. 파일 이름은 이 스크립트가 시작된 날짜로 구성됩니다.
선택적 인수:-h, --help 이 도움말 메시지를 표시하고 종료합니다. --collector-id COLLECTOR_ID 데이터 수집기의 ID입니다. 이 ID는 DB에 저장된 패킷과 연결됩니다. 예: --id 1 --organization-id ORGANIZATION_ID 데이터 수집기의 ID입니다. 이 ID는 DB에 저장된 패킷과 연결됩니다. 예: --id 1 --topics TOPICS [TOPICS ...] 공백으로 구분하여 구독할 토픽 목록을 입력합니다. 아무것도 입력하지 않으면 기본값은 "#"입니다.
필수 인수:
--ip IP MQTT 브로커 IP, 예: --ip 192.168.3.101.
--port PORT MQTT 브로커 포트, 예: --port 623.
예시:
IP 200.200.200.200, 기본 포트(1883)의 MQTT 브로커에 연결합니다.
python3 GenericMqttCollector.py --ip 200.200.200.200 --port 1883
이 스크립트는 loraserver.io MQTT 브로커에 연결하여 메시지를 DB에 저장합니다. 고유한 collectorID를 지정해야 하며, 구독할 토픽을 지정할 수 있습니다.
선택적 인수:
-h, --help 이 도움말 메시지를 표시하고 종료합니다.
--port PORT MQTT 브로커 포트, 예: --port 623. 기본값은 1883입니다.
--collector-id COLLECTOR_ID
데이터 수집기의 ID입니다. 이 ID는 DB에 저장된 패킷과 연결됩니다. 예: --id 1
--organization-id ORGANIZATION_ID
데이터 수집기의 ID입니다. 이 ID는 DB에 저장된 패킷과 연결됩니다. 예: --id 1
--topics TOPICS [TOPICS ...]
공백으로 구분하여 구독할 토픽 목록을 입력합니다. 아무것도 입력하지 않으면 기본값은 "#"입니다.
필수 인수:
--ip IP MQTT 브로커 IP, 예: --ip 192.168.3.101.
이 스크립트는 게이트웨이의 packet_forwarder 형식으로 UDP 프록시로부터 UDP 패킷을 수신하여 저장합니다.
선택적 인수:
-h, --help 이 도움말 메시지를 표시하고 종료합니다.
--collector-id COLLECTOR_ID
데이터 수집기의 ID입니다. 이 ID는 DB에 저장된 패킷과 연결됩니다. 예: --id 1
--organization-id ORGANIZATION_ID
데이터 수집기의 ID입니다. 이 ID는 DB에 저장된 패킷과 연결됩니다. 예: --id 1
필수 인수:
-n NAME, --name NAME 데이터 수집기의 고유 문자열 식별자입니다. 예: --name semtech_collector
-p PORT, --port PORT UDP 패킷을 수신할 포트입니다. --port 1702.
예시:
게이트웨이(로컬 포트 1700으로 전송)와 네트워크 xserver(로컬호스트, 1701에서 수신) 간의 데이터를 기록합니다. 데이터를 ./ 디렉터리에 저장합니다.
python3 PacketForwarderCollector.py --name semtech_collector --port 1700
이 스크립트는 파일이나 파일들 또는 stdin에서 데이터를 읽고 다양한 하위 도구를 실행합니다. 선택한 옵션에 따라 LoRaWAN 트래픽 분석, AppKey 무차별 대입 시도, 또는 수신된 모든 패킷 구문 분석을 실행할 수 있습니다. 이러한 옵션은 결합할 수 있습니다.
선택적 인수:
이 스크립트는 DB에서 패킷을 검색하고 다양한 하위 도구를 실행합니다.
그런 다음 각 하위 도구는 출력 데이터를 DB에 저장합니다. 자세한 내용은 각 옵션을 참조하십시오.
선택적 인수:
-h, --help 이 도움말 메시지를 표시하고 종료합니다.
-a, --analyze 트래픽의 다양한 측면을 수집하고 분석합니다.
무차별 대입기(-b)가 활성화된 경우 결과가 상호 연관됩니다.
-b, --bforce JoinRequest 및 JoinAccepts 페이로드를 사용하여 AppKey를 무차별 대입합니다.
-k KEYS, --keys KEYS [무차별 대입기] 키 파일의 경로입니다. 제공되지 않으면
"bruteForcer/keys.txt"가 사용됩니다.
--no-gen [무차별 대입기] 키를 생성하지 않고 파일의 키만 시도합니다.
-p, --parse PHYPayload를 읽을 수 있는 정보로 구문 분석합니다.
--from-id FROM_ID 처리를 시작할 패킷 ID입니다.
--to-id TO_ID 처리할 마지막 패킷 ID입니다.
예시:
DB에서 패킷 ID 1000부터 시작하여 패킷을 처리하고, 트래픽 분석을 실행하며, my-keys.txt에 제공된 AppKey를 크랙하려고 시도하지만 동적으로 더 많은 키를 생성하지 않습니다.
python3 LafProcessData.py -a -b -k my-keys.txt --no-gen --from-id 1000
이 스크립트들은 LafProcessData.py에 의해 조정되는 기능을 제공합니다. 아래는 LafPacketAnalysis.py 및 LafBruteForcer.py에 의해 구현된 경보 목록입니다:
이 디렉토리는 Golang으로 작성된 라이브러리 https://github.com/brocaar/lorawan/에 대한 래퍼 세트를 제공합니다. 이러한 함수들은 도구에 의해 구현됩니다.
여기에는 다양한 작업을 자동화하기 위한 스크립트 시리즈가 있습니다. 필요한 경우 실행 권한을 부여하십시오(Linux/MacOS의 경우 chmod +x your_script).
게이트웨이를 쉽게 설정하고 스니핑 목적으로 채널을 전환합니다. 사용 방법에 대한 자세한 내용은 이 디렉토리의 readme를 참조하십시오.
이 스크립트는 Raspberry PI에 연결된 LoRa 집중기(iC980-SPI, RHF0M301-SPI, RAK831-SPI 또는 수동 설정으로 다른 것)와 함께 LoRaWAN 게이트웨이를 구축하기 위해 필요한 모든 소프트웨어 패키지를 설치하는 데 사용됩니다.
LoRa 장치가 어떤 주파수에서 작동하는지 알 수 없기 때문에, 스니핑 목적으로 US915 및 EU868 주파수 대역의 게이트웨이 채널을 전환할 수 있는 스크립트를 만들었습니다. 32개 또는 64개 채널을 지원하는 전문적이고 비싼 게이트웨이가 있지만, 대부분의 게이트웨이는 최대 8개 채널을 지원합니다. 이 스크립트는 이러한 종류의 게이트웨이에서 실행되도록 설계되었습니다.
적어도 US915 주파수 대역에서는 처음 8개 채널이 가장 많이 사용됩니다. 그러나 The Things Networks와 같이 업링크 통신에 두 번째 그룹(8-15)의 채널을 사용하는 잘 알려진 구현도 있습니다.
현재 다른 주파수 대역은 지원하지 않지만, 이 스크립트를 약간만 수정하면 직접 할 수 있을 것입니다 :).
TODO
이 프로젝트는 BSD-3-Clause 라이선스에 따라 라이선스가 부여됩니다.
Go 라이브러리를 컴파일합니다:
cd laf/lorawanwrapper/utilsgo build -o lorawanWrapper.so -buildmode=c-shared jsonUnmarshaler.go lorawanWrapper.go micGenerator.go sessionKeysGenerator.go hashGenerator.go사용하려는 DB에 따라:
a. PostgreSQL: 'Docker를 사용하여 LAF 설치'의 3단계까지 따릅니다.
b. SQLite:
cd laf/auditing/db__init__.py를 열고 Postgres에 사용할 줄(DB 연결 및 환경 변수)을 주석 처리하고 sqlite에 사용할 줄을 주석 해제합니다.| ID | 제목 | 분석기 | 위험 수준 | 설명 | 권장 조치 |
|---|
| LAF-001 | DevNonce 반복 | LafPacketAnalysis.py | 낮음 | 각 장치의 DevNonce는 충돌하지 않을 만큼 무작위여야 합니다. 동일한 DevNonce가 여러 메시지에서 반복된다면, 장치가 재생 공격을 받고 있다고 추론할 수 있습니다. 즉, 공격자가 JoinRequest를 캡처하여 게이트웨이에 다시 보내려고 하는 것입니다. | DevNonce 생성 방식을 확인하십시오. DevNonce를 생성하는 함수는 무작위 라이브러리를 사용하여 구현되어야 합니다. 또한, 서버가 이전 DevNonce를 확인하도록(DB에 저장되어 있어야 함) 하여 이전에 장치가 보낸 유효한 JoinRequest를 수락하지 않고 새 세션을 생성하지 않도록 해야 합니다. |
| LAF-002 | 동일한 DevAddr을 공유하는 DevEUI | LafPacketAnalysis.py | 정보 | 두 개의 다른 장치에 동일한 DevAddr이 할당되었을 수 있습니다. 이는 보안 위협이 아닙니다. | OTA(Over the Air Activation) 장치: DevAddr 할당에 사용된 로직을 확인하고 서버가 다른 장치에 동일한 DevAddr을 할당하지 않도록 하십시오. ABP(Activation by Personalization) 장치: 장치 펌웨어에 구성된 DevAddr이 LoRaWAN 네트워크에서 고유한지 확인하십시오. |
| LAF-003 | 조인 재생 | TODO | 중간 | 중복된 조인 요청 패킷이 감지되었습니다. 이는 LoRaWAN 서버가 재생 공격을 받고 있음을 의미할 수 있습니다. 즉, 공격자가 이전의 조인 요청 패킷을 캡처하여 새 세션을 생성하기 위해 LoRaWAN 서버에 다시 보내는 것입니다. | DevNonce 생성 방식을 확인하십시오. DevNonce를 생성하는 함수는 무작위 라이브러리를 사용하여 구현되어야 합니다. 또한, 서버가 이전 DevNonce를 확인하도록(DB에 저장되어 있어야 함) 하여 이전에 장치가 보낸 유효한 JoinRequest를 수락하지 않고 새 세션을 생성하지 않도록 해야 합니다. |
| LAF-004 | 업링크 데이터 패킷 재생 | TODO | 중간 | 중복된 업링크 패킷이 감지되었습니다. 이는 LoRaWAN 서버가 재생 공격을 받고 있음을 의미할 수 있습니다. 즉, 공격자가 (장치에서 보낸) 업링크 패킷을 캡처하여 LoRaWAN 서버에 다시 보내는 것입니다. | OTA(Over the Air Activation) 장치: 장치 재설정 또는 카운터 오버플로우 후 세션 키가 다시 생성되어 이 공격의 영향을 방지하도록 하십시오. LoRaWAN v1.0.*의 ABP(Activation by Personalization) 장치의 경우, 장치를 OTAA로 전환하는 것 외에는 재생 공격을 방지할 수 있는 방법이 없습니다. |
| LAF-005 | 다운링크 데이터 패킷 재생 | TODO | 높음 | 중복된 다운링크 패킷이 감지되었습니다. 서버가 재생 공격에 응답하거나 장치에 비정상적인 트래픽을 생성하고 있습니다. | 서버 로그를 확인하고 이전 권장 조치가 구현되었는지 확인하십시오. |
| LAF-006 | 가능한 ABP 장치(카운터 재설정 및 조인 없음) | LafPacketAnalysis.py | 높음 | 카운터가 재설정(0으로 돌아감)되었고 DevAddr이 동일하게 유지되며 이전 조인 프로세스가 감지되지 않은 경우, 장치가 ABP(Activation by Personalization)로 활성화되었음을 의미할 수 있습니다. ABP 장치 구현은 조인 프로세스가 수행되지 않아 세션 키가 영원히 동일하게 유지되므로 권장되지 않습니다. 세션 키를 변경하지 않는 장치는 도청 또는 재생과 같은 다양한 공격에 취약합니다. | 가능한 경우 모든 ABP(Activation by Personalization) 장치는 OTA(Over the Air Activation) 장치로 교체되어야 합니다. ABP 장치의 구현은 권장되지 않습니다. |
| LAF-007 | 예상보다 작은 카운터 수신(0과 다름) | LafPacketAnalysis.py | 중간 | 공격자가 (OTAA 장치의 AppKey 또는 ABP 장치의 AppSKey/NwkSKey를 도용하여) 세션 키 쌍을 획득한 경우, 서버에 가짜 유효 데이터를 보낼 수 있습니다. 서버가 위조된 메시지를 수락하려면 메시지의 FCnt(프레임 카운터)가 마지막으로 보낸 메시지의 FCnt보다 높아야 합니다. 원래 위조된 장치가 계속 메시지를 보내는 시나리오에서는 서버가 더 작은 FCnt를 가지므로 (유효한) 메시지를 폐기하기 시작합니다. 따라서 LoRaWAN 서버가 예상한 것보다 작은 FCnt 값을 가진 메시지가 수신될 때, 병렬 세션이 설정되었음을 추론할 수 있습니다. | OTA(Over the Air Activation) 장치인 경우, AppKey가 손상되었을 가능성이 있으므로 변경하십시오. ABP(Activation by Personalization) 장치인 경우 AppSKey 및 NwkSKey를 변경하십시오. 또한 LoRaWAN 서버가 업데이트되었고 중복 메시지를 수락하지 않는지 확인하십시오. |
| LAF-008 | JoinRequest로 비밀번호 크랙됨 | LafBruteforcer.py | 높음 | 알려진 AppKey를 사용하여 JoinRequest 메시지를 해독할 수 있었습니다. | 공급업체가 제공한 것과 다른 AppKey를 사용하거나 더 무작위적인 키를 사용하십시오. |
| LAF-009 | 비밀번호 크랙됨 | LafBruteforcer.py | 높음 | 잘 알려졌거나 무작위가 아닌 문자열로 시도하여 장치의 AppKey를 찾았습니다. 한 쌍의 조인 메시지(Request 및 Accept)를 사용하여 해독되었습니다. | 공급업체가 제공한 키 대신 AppKey에 무작위 키 생성기를 사용하십시오. 또한 둘 이상의 장치에 동일한 AppKey를 설정하지 말고 예측 가능한 로직(예: 증가 값, 특정 바이트 뒤집기 등)을 사용하여 AppKey를 생성하지 마십시오. |
| LAF-010 | 게이트웨이 위치 변경 | LafPacketAnalysis.py | 중간 | 게이트웨이가 위치를 변경하지 않아야 하는 경우입니다. 도난, 이동되었거나, 가짜 게이트웨이가 합법적인 게이트웨이를 사칭하려고 할 수 있습니다. | 게이트웨이가 물리적으로나 논리적으로 변조되지 않았는지 확인하십시오. |