
このプロジェクトは、LoRaWANインフラストラクチャのセキュリティを監査またはペネトレーションテストするために、一連のLoRaWANパケットを作成、解析、送信、分析、クラックするためのツール群を提供することを目的としています。
IoTデプロイメントは成長を続けており、その大きな成長の一部は、世界中の何百もの都市(スマートシティ)や産業、家庭に展開された数百万のLPWAN(低消費電力広域ネットワーク)センサーで構成されています。最も使用されているLPWAN技術の1つが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データベースを起動します。 コンテナ:
手順:
git clone https://github.com/IOActive/laf.gitcd laf/ に移動docker-compose up --builddocker exec -ti laf_tools_1 /bin/bashpgAdminを使用してデータベース内のデータを確認できます:
まず、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バイト)を入力し、新しいMICを計算して追加します。
JoinRequestsの場合はAppKey、データパケットの場合はNwkSKeyでなければならないことに注意してください。
これは事前にこのプログラムで検証できません。例:
00112233445566778899AABBCCDDEEFF
-a DEVADDR, --devaddr DEVADDR
なりすますデバイスアドレス。16進形式(合計8文字)で指定、
例: AABB0011
--fcnt FCNT 指定されたデータパケットに設定するフレームカウンタ。
これはJoinRequest/JoinAcceptでは機能しません。これらのパケットにはfCntがないためです。
必須引数:
--dst-ip DST_IP 送信先IP、例: --dst-ip 192.168.3.101
--dst-port DST_PORT 送信先ポート、例: --dst-port 623
--data DATA UDPパケット。このスクリプトの最後にある "data" 配列にさらにパケットを追加することもできます。
パケットはバイト文字列でなければなりません(二重引用符はエスケープする必要があります)。
***例*** パケットフォワーダー形式: --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秒ごとに1つのパケットを(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プロキシは主に、一連のゲートウェイ(パケットフォワーダー)とネットワークサーバーまたはゲートウェイブリッジ(評価中のインフラに応じて)の間に配置するためのものです。また、希望する方向(アップリンクまたはダウンリンク)でデータをファズする機能も提供します。
オプション引数:
-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 ...]
dst-portに送信するデータを指定されたモードでファズ(
ファジングモードは 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 ...]
dst-portに送信するデータを指定されたモードでファズ(
ファジングモードは 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パケットを解析、作成、ブルートフォースなどするための一連のスクリプトが含まれています。
このスクリプトは、JoinAcceptまたはJoinRequestをBase64で受け取り、ファイルで提供されるか動的に生成される可能性のある鍵のセットを使用して、そのAppKeyの復号を試みます。
オプション引数:
-h, --help このヘルプメッセージを表示して終了
-k KEYS, --keys KEYS 鍵のリストを含むファイル。\nで区切られる。
デフォルトは /auditing/analyzers/bruteForcer/keys.txt
--dont-generate 以下の組み合わせで鍵を動的に生成したくない場合に選択:
1- 最初のバイトと最後の15バイトを組み合わせる。例:
AABBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
2- 偶数と奇数のバイト位置を均等に組み合わせる。例:
AABBAABBAABBAABBAABBAABBAABBAABB
3- 最初の14バイトを00にして、最後の2バイトを組み合わせる。例:
0000000000000000000000000000BA01
必須引数:
-a ACCEPT, --accept ACCEPT
ブルートフォースするJoin AcceptのBase64形式。例: -a
IHvAP4MXo5Qo6tdV+Yfk08o=
-r REQUEST, --request REQUEST
ブルートフォースするJoin RequestのBase64形式。例:
-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のみ]。以前にJoinAcceptを暗号化するために使用した鍵(16進形式、合計32文字/16バイト)を入力します。
これは事前にこのプログラムで検証できません。例:
00112233445566778899AABBCCDDEEFF
JoinAccept "IB1scNmwJRA32RfMbvwe3oI=" に対する有効な鍵の例は
"f5a3b185dfe452c8edca3499abcd0341" です。
必須引数:
-d DATA, --data DATA 署名するBase64データ。例: -d
AE0jb3GsOdJVAwD1HInrJ7i3yXAFxKU=
-k KEY, --key KEY パケットに署名するための新しい鍵(16進形式、合計32文字/16バイト)を入力し、
新しいMICを計算して追加します。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 デバイスのAppSKeyまたはAppKey(16進形式、合計32文字/16バイト)を入力し、
FRMPayloadまたはJoin Acceptを暗号化します。例:
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"}'
このスクリプトは、単一のLoRaWAN PHYPayloadデータをBase64で解析して表示します。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
JoinAcceptペイロード(base64形式)
-r JREQUEST, --jrequest JREQUEST
JoinRequestペイロード(base64形式)
-k KEY, --key KEY デバイスのAppKey(16進形式、合計32文字/16バイト)を入力します。例:
00112233445566778899AABBCCDDEEFF
例:
以下のJoinデータからAppSKeyとNwkSKeyを取得します。
python3 SessionKeysGenerator.py -r AE0jb3GsOdJVAwD1HInrJ7i3yXAFxKU= -a IB1scNmwJRA32RfMbvwe3oI= -k f5a3b185dfe452c8edca3499abcd0341
これらは、UdpSender.py と UdpProxy.py で使用される補助関数です。Fuzzer.py には実装されたファジングモードが表示されています。
このディレクトリの全般的な目的は、LoRaWANパケットを収集し、トラフィックのさまざまな側面を分析すること、およびAppKeyをブルートフォースするための鍵のセットを試すことです。
このディレクトリには、異なるソース(例:ゲートウェイパケットフォワーダー、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 mqqtブローカーに接続し、メッセージをDBに保存します。一意のコレクタIDを指定する必要があり、購読するトピックを指定できます。
オプション引数:
-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。
このスクリプトは、UDPプロキシからゲートウェイのpacket_forwarder形式で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が(localhost, 1701)で待ち受ける間のデータを記録します。データを./ディレクトリに保存します。
python3 PacketForwarderCollector.py --name semtech_collector --port 1700
このスクリプトはファイルまたはstdinから読み取り、異なるサブツールを実行します。選択したオプションに応じて、LoRaWANトラフィックの解析、AppKeyのブルートフォース試行、受信したすべてのパケットの解析を実行できます。これらのオプションは組み合わせ可能です。
オプション引数:
このスクリプトはDBからパケットを読み取り取得し、異なるサブツールを実行します。
その後、各サブツールは出力データをDBに保存します。各オプションの詳細については各オプションを参照してください。
オプション引数:
-h, --help このヘルプメッセージを表示して終了します
-a, --analyze トラフィックからさまざまな側面を収集し分析します。ブルートフォーサー(-b)が有効な場合、結果が関連付けられます。
-b, --bforce JoinRequestsとJoinAcceptsのペイロードを使用してAppKeyをブルートフォース試行します。
-k KEYS, --keys KEYS [ブルートフォーサー] 鍵ファイルへのファイルパス。指定しない場合、"bruteForcer/keys.txt"が使用されます。
--no-gen [ブルートフォーサー] 鍵を生成せず、ファイルからの鍵のみを試行します。
-p, --parse PHYPayloadを解析して読み取り可能な情報に変換します。
--from-id FROM_ID 処理を開始するパケットID。
--to-id TO_ID 処理する最後のパケットID。
例:
パケットID 1000からDB内のパケットを処理し、トラフィック分析を実行し、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を参照してください。
このスクリプトは、接続されたLoRaコンセントレーター(iC980-SPI、RHF0M301-SPI、RAK831-SPI、または手動設定によるその他)と組み合わせてLoRaWANゲートウェイを構築するために、Raspberry PIに必要なすべてのソフトウェアパッケージをインストールするために使用されます。
LoRaデバイスがどの周波数で動作しているかを知ることは不可能であるため、スニッフィング目的でUS915およびEU868周波数帯からゲートウェイのチャンネルを切り替えるスクリプトを作成しました。32または64チャンネルをサポートするプロフェッショナルで高価なゲートウェイもありますが、ほとんどのゲートウェイは最大8チャンネルをサポートしています。このスクリプトはこの種のゲートウェイで動作することを目的としています。
少なくともUS915周波数帯では、最初の8チャンネルが最も使用されています。しかし、The Things Networksのように、アップリンク通信に2番目のグループ(8-15)のチャンネルを使用する有名な実装があります。
現在、他の周波数帯はサポートしていませんが、これらのスクリプトに少し変更を加えることで、自分でそれを実行できるようになります :)
TODO
This project is licensed under BSD-3-Clause License.
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: 3番目のステップまで 'Dockerを使ってLAFをインストール' の手順に従ってください。
b. SQLite:
cd laf/auditing/db__init__.py を開き、Postgres用の行(DB接続と環境変数)をコメントアウトし、sqlite用の行をコメント解除します。| ID | タイトル | アナライザー | リスクレベル | 説明 | 推奨される対応 |
|---|
| LAF-001 | DevNonceの繰り返し | LafPacketAnalysis.py | 低 | 各デバイスのDevNonceは衝突しないように十分にランダムであるべきです。同じDevNonceが多くのメッセージで繰り返された場合、デバイスがリプレイ攻撃を受けている可能性があります。つまり、JoinRequestをキャプチャした攻撃者が、それをゲートウェイに再度送信しようとしている可能性があります。 | DevNonceの生成方法を確認してください。それらを生成する関数はランダムライブラリを使用して実装する必要があります。さらに、サーバーが過去のDevNonceをチェックするようにしてください(それらはDBに永続化されるべきです)。そうすることで、以前にデバイスから送信された有効なJoinRequestを受け入れて新しいセッションを生成することを防ぎます。 |
| LAF-002 | 同じDevAddrを共有するDevEUI | LafPacketAnalysis.py | 情報 | 2つの異なるデバイスに同じDevAddrが割り当てられている可能性があります。これはセキュリティ上の脅威ではありません。 | デバイスが空中でアクティベーション(OTAA)されている場合:DevAddrの割り当てに使用されるロジックを確認し、サーバーが異なるデバイスに同じDevAddrを割り当てないようにしてください。デバイスがパーソナライゼーション(ABP)でアクティベーションされている場合:デバイスのファームウェアに設定されたDevAddrがLoRaWANネットワーク内で一意であることを確認してください。 |
| LAF-003 | Joinリプレイ | TODO | 中 | 重複したJoinRequestパケットが検出されました。これはLoRaWANサーバーがリプレイ攻撃を受けている可能性があります。つまり、以前のJoinRequestパケットをキャプチャした攻撃者が、新しいセッションを生成しようとしてサーバーに再度送信している可能性があります。 | DevNonceの生成方法を確認してください。それらを生成する関数はランダムライブラリを使用して実装する必要があります。さらに、サーバーが過去のDevNonceをチェックするようにしてください(それらはDBに永続化されるべきです)。そうすることで、以前にデバイスから送信された有効なJoinRequestを受け入れて新しいセッションを生成することを防ぎます。 |
| LAF-004 | アップリンクデータパケットのリプレイ | TODO | 中 | 重複したアップリンクパケットが検出されました。これはLoRaWANサーバーがリプレイ攻撃を受けている可能性があります。つまり、デバイスから送信されたアップリンクパケットをキャプチャした攻撃者が、それをサーバーに再度送信している可能性があります。 | 空中でアクティベーション(OTAA)されているデバイスの場合:セッションキーがデバイスのリセットやカウンターオーバーフローのたびに再生成されることを確認して、この攻撃の影響を回避してください。LoRaWAN v1.0.*のパーソナライゼーション(ABP)デバイスの場合、リプレイ攻撃を防ぐためにできることは何もありません。ただし、デバイスをOTAAに切り替えることは可能です。 |
| LAF-005 | ダウンリンクデータパケットのリプレイ | TODO | 高 | 重複したダウンリンクパケットが検出されました。サーバーがリプレイ攻撃に応答しているか、デバイスに対して異常なトラフィックを生成しています。 | サーバーのログを確認し、以前に推奨された対策が実装されていることを確認してください。 |
| LAF-006 | ABPデバイスの可能性(カウンターリセットとJoinなし) | LafPacketAnalysis.py | 高 | カウンターがリセットされ(0に戻った)、DevAddrが同じままで、以前のJoinプロセスが検出されなかった場合、デバイスがパーソナライゼーション(ABP)でアクティベーションされている可能性があります。ABPデバイスの実装は推奨されません。なぜなら、Joinプロセスが行われず、セッションキーが永久に同じままになるからです。セッションキーを変更しないデバイスは、盗聴やリプレイなどのさまざまな攻撃に対して脆弱です。 | 可能であれば、すべてのパーソナライゼーション(ABP)デバイスを空中でアクティベーション(OTAA)デバイスに交換してください。ABPデバイスの実装は推奨されません。 |
| LAF-007 | 予想よりも小さいカウンターを受信(0以外) | LafPacketAnalysis.py | 中 | 攻撃者がセッションキーのペアを入手した場合(OTAAデバイスのAppKeyを盗んだ、またはABPデバイスのAppSKey/NwkSKeyを盗んだなど)、サーバーに偽の有効なデータを送信できるようになります。サーバーが偽装されたメッセージを受け入れるためには、メッセージのFCnt(フレームカウンター)が最後のメッセージのFCntよりも高い必要があります。元の偽装デバイスがメッセージを送信し続けているシナリオでは、サーバーは(有効な)メッセージを破棄し始めます。なぜなら、それらはより小さなFCntを持つからです。したがって、LoRaWANサーバーが期待するよりも小さいFCnt値のメッセージを受信している場合、並行セッションが確立された可能性があります。 | デバイスが空中でアクティベーション(OTAA)デバイスの場合、AppKeyを変更してください。おそらく危険にさらされています。パーソナライゼーションでアクティベーションされている場合、AppSKeyとNwkSKeyを変更してください。さらに、LoRaWANサーバーが更新されており、重複メッセージを受け入れていないことを確認してください。 |
| LAF-008 | JoinRequestでパスワードがクラックされました | LafBruteforcer.py | 高 | 既知のAppKeyを使用してJoinRequestメッセージを復号化できました。 | ベンダーが提供するものとは異なるAppKeyを使用するか、よりランダムなキーを使用してください。 |
| LAF-009 | パスワードがクラックされました | LafBruteforcer.py | 高 | よく知られているまたはランダムでない文字列を試行して、デバイスのAppKeyが見つかりました。Joinメッセージのペア(RequestとAccept)を使用して復号化されました。 | AppKeyにランダムキージェネレーターを使用し、ベンダー提供のものは使用しないでください。さらに、同じAppKeyを複数のデバイスに設定せず、予測可能なロジック(例:増分値、特定のバイトの反転など)でAppKeyを生成しないでください。 |
| LAF-010 | ゲートウェイの位置が変更されました | LafPacketAnalysis.py | 中 | ゲートウェイがその位置を変更することが想定されていない場合、盗まれたか、移動されたか、または偽のゲートウェイが正当なゲートウェイを偽装しようとしている可能性があります。 | ゲートウェイが物理的にも論理的にも改ざんされていないことを確認してください。 |