SkillAgentSearch skills...

Laf

This project intends to provide a series of tools to craft, parse, send, analyze and crack a set of LoRaWAN packets in order to audit or pentest the security of a LoraWAN infrastructure.

Install / Use

/learn @IOActive/Laf

README

LoRaWAN Auditing Framework - ALPHA VERSION

IoT deployments just keep growing and one part of that significant grow is composed of millions of LPWAN (low-power wide-area network) sensors deployed at hundreds of cities (Smart Cities) around the world, also at industries and homes. One of the most used LPWAN technologies is LoRa for which LoRaWAN is the network standard (MAC layer). LoRaWAN is a secure protocol with built in encryption but implementation issues and weaknesses affect the security of most current deployments.

This project intends to provide a series of tools to craft, parse, send, analyze and crack a set of LoRaWAN packets in order to audit or pentest the security of a LoraWAN infrastructure.

Below, the structure of this 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

Getting Started

We provide different options to have your LoraWAN Auditing Framework up and running:

  1. The first is for those people that want to install it locally. We recommend this option if your main goal is to use pentesting tools located in tools/ dir, in order to avoid problems with docker port mapping.
  2. The other option is for those people that want to run it into a Docker container, thus avoiding to manually install any dependency. We recommend this option in case you want use the analyzers and don't have much time to manually set up the environment.
  3. Of course, you can run LAF locally and use Postgres DB from the Docker container instead of sqlite ;). LAF will try to connect to Postgres through localhost. See instructions below to set up Docker.

Install LAF in your local environment

These instructions will get you a copy of the project and its dependencies in your local machine. Commands below are for a Debian based environment:

  1. Clone this repository: git clone --recurse-submodules https://github.com/IOActive/laf.git

  2. Install python3:

    1. sudo apt-get update
    2. sudo apt-get install python3.6
  3. Download and install python dependencies:

    1. sudo pip3 install paho-mqtt && sudo pip3 install sqlalchemy && sudo pip3 install psycopg2-binary &&sudo pip3 install python-dateutil
  4. Set PYTHONPATH and ENVIRONMENT

    1. cd laf && export PYTHONPATH=$(pwd) && export ENVIRONMENT='DEV'
  5. Install and setup golang:

    1. Download golang from https://golang.org/dl/ depending on your operating system.
    2. Move to the folder where the go installer was downloaded: cd ~/Downloads
    3. Decompress the installer: sudo tar -C /usr/local -xvzf YOUR_GOLANG_FILE
    4. Export to PATH: export PATH=$PATH:/usr/local/go/bin
    5. Set GOPATH: export GOPATH="$HOME/go"
  6. Compile go library:

    1. cd laf/lorawanwrapper/utils
    2. go build -o lorawanWrapper.so -buildmode=c-shared jsonUnmarshaler.go lorawanWrapper.go micGenerator.go sessionKeysGenerator.go hashGenerator.go
  7. Depending on which DB you'd like to use:

    a. PostreSQL: Follow instructions 'Install LAF using Docker' until 3rd step.

    b. SQLite:

    1. cd laf/auditing/db
    2. Modify __init__.py with your preferred text editor and comment the lines to be used with Postgres (DB connection and environment variables) an uncomment the line to be used with sqlite.

And that's it!

Install LAF using Docker

This approach avoids dealing with the installation of dependencies and start a PostgreSQL DB where the tools save packets and data. Containers:

  • Tools.
  • PostgreSQL.
  • PgAdmin4.

Steps:

  1. Clone this repository: git clone https://github.com/IOActive/laf.git
  2. Go to cd laf/
  3. Start containers: docker-compose up --build
  4. If you want to use the tools into the container docker exec -ti laf_tools_1 /bin/bash
  5. Enjoy!

pgAdmin database connection

You can check data in DB using pgAdmin:

First, access to pgAdmin:

  • URL: http://localhost:5001
  • User: pgadmin
  • Pass: pgadmin

Then, you need to add the server:

  • Host: db
  • Port: 5432
  • User: postgres
  • Pass: postgres

Tools description

Here is description of the directories and the tools / function inside them.

/tools

The main purpose of the tools provided in this directory is to ease the execution of a penetration test to a LoRaWAN infrastructure.

UdpSender.py

This tool is intended to send uplink packets (to the network server or gatewayBridge, depending on the infrastructure) or downlink packets (to the packet-forwarder). Optionally, packets can be fuzzed and a valid MIC can be calculated.

Optional arguments:

-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

Required arguments:

--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'\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=\"}]}'" ***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}'"

Example:

To send a single packet every 2 seconds to (localhost, 10001) from port 10000 fuzzing randomly the MIC and the 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=\"}]}'"

UdpProxy.py

This UDP proxy is mainly intended to be placed between a series gateways (packet_forwarders) and a network server or gateway bridge depending on the infraestructure being evaluated. It also offers the posibility to fuzz data in the desired direction (uplink or downlink)

Optional arguments:

-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 [FU
View on GitHub
GitHub Stars183
CategoryDevelopment
Updated1mo ago
Forks37

Languages

Python

Security Score

100/100

Audited on Feb 26, 2026

No findings