
The landscape of edge computing has shifted dramatically over the past few years. In my previous research on The Autonomous Edge: A New Frontier for Industrial Compute, we focused heavily on securing legitimate deployments. We explored how full-disk encryption and strict access controls are vital to protect sensitive localized data on deployed single-board computers (SBCs). This is especially critical now that edge devices are no longer just basic relays passing a raw stream of sensor telemetry back to a central cloud.
Today, modern edge platforms possess octa-core processors and dedicated Neural Processing Units (NPUs) capable of running complex local AI inference. They operate with high autonomy, monitoring entire physical sites, processing raw video feeds, and making automated operational decisions locally.
However, this exact jump in compute power has caught the attention of sophisticated threat actors. Attackers are leveraging the same cheap, high-performance edge hardware to build highly capable, deployable rogue devices. These rogue nodes are designed to function as persistent out-of-band backdoors, network sniffers, covert surveillance platforms, or even card skimmers.
To make matters worse, defenders are increasingly blind to how these devices communicate. While enterprise intrusion detection systems actively sweep for unauthorized 2.4 GHz or 5 GHz WiFi access points and Bluetooth Low Energy (BLE) beacons, threat actors are now bypassing these checks entirely. They are turning to sub-GHz communication protocols like LoRa, Wi-Fi HaLow (802.11ah), and DigiMesh (XBee 3) to establish ultra-long-range, highly evasive command-and-control (C2) channels.
The Shift from WiFi to Sub-GHz Communications
The motivation for an attacker to abandon traditional 2.4 GHz WiFi or BLE is straightforward: range, penetration, and evasion.
A standard 2.4 GHz WiFi signal typically struggles to maintain a stable connection beyond 100 meters, especially when obstructed by thick concrete walls, steel reinforcement, or industrial machinery. Bluetooth BLE is even more restricted, often losing utility after just a dozen meters.
Furthermore, modern enterprise environments deploy sophisticated Wireless Intrusion Prevention Systems (WIPS). These tools continuously monitor the 2.4 GHz and 5 GHz spectrum, logging unauthorized MAC addresses, alerting on rogue access points, and even executing automated de-authentication attacks to neutralize unauthorized connections.
In contrast, sub-GHz communications operating in the unlicensed Industrial, Scientific, and Medical (ISM) bands (specifically 915 MHz in the United States and 868 MHz in Europe) present a massive challenge for traditional defense monitoring.
Consider the capabilities of LoRa (Long Range) spread spectrum modulation. By swapping a 2.4 GHz link for a 915 MHz LoRa connection, an attacker gains an approximate 10,000 percent increase in transmission range. A low-profile transmitter can easily broadcast data across 10 to 15 kilometers in line-of-sight conditions, or up to 2 to 3 kilometers through dense urban and industrial structures.
The trade-off for this massive range increase is speed. While WiFi provides hundreds of megabytes per second, LoRa typically tops out around 50 kilobits per second. For an attacker, this is a highly acceptable trade-off. A speed of 50 kbps is more than enough to transmit interactive shell commands, keystroke logs, captured credentials, or low-frequency system telemetry.
Furthermore, because enterprise security suites rarely monitor sub-GHz bands for rogue activity, these transmissions easily slip under the radar.
Anatomy of a Rogue Edge Device: Radxa Cubie A7S and REYAX RYLR998
To understand how easily these devices can be deployed, we can look at a possible hardware build out. An attacker can construct an autonomous, long-range rogue gateway for well under 100 dollars using commercially available hobbyist hardware.
| Budget SBC Comparison | Orange Pi Zero 3W (4GB) | Radxa Zero 3W (4GB) | Arduino UNO Q (4GB) | Radxa Cubie A7S (4GB) |
|---|---|---|---|---|
| Cost | Est. ~$75 USD | Est. ~$65 USD | Est. ~$79 USD | Est. ~$45 USD |
| Processor + Cores and Speed | Allwinner A733 (8-Core: 2x A76 + 6x A55) | Rockchip RK3566 (4-Core: 4x A55) | Qualcomm QRB2210 + STM32U585 (4-Core: 4x A53 + MCU) | Allwinner A733 (8-Core: 2x A76 + 6x A55) |
| Local AI Capabilities | NPU 3 TOPS | NPU 0.8 TOPS | No NPU (Software ML) | NPU 3 TOPS |
| Size | Dimensions 65 x 30 mm (Pi Zero Shape) | Dimensions 65 x 30 mm (Pi Zero Shape) | Dimensions 69 x 54 mm (Shield Compatible) | Dimensions 51 x 51 mm (Square) |
| Storage | MicroSD Slot | MicroSD Slot | 32GB Built-in eMMC | MicroSD Slot |
The brain of my chosen deployable is the new Radxa Cubie A7S single-board computer, which is documented in detail on the official Radxa Cubie A7S Documentation site. This compact SBC features an octa-core Allwinner A733 SoC, a built-in 3 TOPS NPU for edge AI acceleration, dual USB-C ports, gigabit Ethernet, and onboard WiFi 6. It runs standard Debian Linux, providing a full-featured pentesting and exploitation environment.
To achieve long-range out-of-band communication, the Radxa Cubie A7S is paired with the REYAX RYLR998 Transceiver Module. The RYLR998 is a low-power, high-performance LoRa module controlled via standard UART AT commands over a serial interface. It utilizes a custom REYAX protocol built on top of the Semtech LoRa engine, allowing developers to configure custom addresses and network IDs easily.
| Module | Cost | Chipset | Frequencies Supported | Transmit Power | Native Encryption | Max Range |
|---|---|---|---|---|---|---|
| EBYTE E220-900T22S | ~$11.30/pcs | Semtech LLCC68 | 868 MHz / 915 MHz | Up to +22 dBm | No (Uses custom keying) | Up to 5 km |
| Reyax RYLR998 | ~$11.80/pcs | Semtech SX1276 | 433 MHz / 470 MHz / 868 MHz / 915 MHz | Up to +22 dBm | Yes (AES-128 via AT commands) | Up to 15 km |
| NiceRF LoRa611Pro | ~$12.60/pcs | Semtech SX1268 | 433 MHz / 470 MHz / 868 MHz / 915 MHz | Up to +30 dBm | Yes (AES-128 hardware) | Up to 5 km |
By combining the Radxa Cubie A7S with the RYLR998, the attacker could build a dual-homed bridge. The Cubie A7S can connect directly to the target’s local network via its gigabit Ethernet port or WiFi 6 chip to sniff traffic, intercept credentials, or exploit local vulnerabilities. Meanwhile, the RYLR998 UART module provides a completely separate, out-of-band command-and-control link back to the attacker’s remote station miles away.
The following diagram outlines the control flow of this deployment, showing how the handler maintains access through the encrypted sub-GHz air interface.

Hardware Setup Guide: Radxa Cubie A7S and RYLR998 with PSK
Setting up a physical rogue node prototype (or a defensive honey-node for testing) requires proper wiring and configuration. Because the REYAX RYLR998 operates at 3.3V logic levels, it can interface directly with the Radxa Cubie A7S GPIO header without requiring an external logic level shifter.
To explore the wiring and pinouts of the RYLR998 in more depth, you can consult the Cirkit Designer RYLR998 Component Specs.
Step 1: Physical Connections
Connect the RYLR998 pins to the specific SBCs GPIO header per the vendors linked documentation or with my recommendations as follows:
| GPIO Pinout Connections per SBC | Orange Pi Zero 3W Pinout | Radxa Zero 3W GPIO | Arduino UNO Q Pinout | Radxa Cubie A7S GPIO |
|---|---|---|---|---|
| VCC (RYLR998 Pin 1) | 3.3V Power (via 3.3V Pin) | 3.3V Power (GPIO Pin 17) | 3.3V Power ( via +3v3 Out Pin) | 3.3V Power (GPIO Pin 17) |
| RESET (RYLR998 Pin 2) | Optional RESET (GPIO Pin PB4) | Optional RESET (GPIO Pin 12) | Optional RESET (via Pin D2) | Optional RESET (GPIO Pin 12) |
| RXD (RYLR998 Pin 3) | UART2-TX (GPIO Pin PB0) | UART4_TX_M1 (GPIO Pin 18) | USART1_TX (via Pin D1) | UART4-TX (GPIO Pin 16) |
| TXD (RYLR998 Pin 4) | UART2-RX (GPIO Pin PB1) | UART4_RX_M1 (GPIO Pin 16) | USART1_RX (via Pin D0) | UART4-RX (GPIO Pin 18) |
| GND (RYLR998 Pin 5) | GND (via GND pin) | GND (GPIO Pin 14) | GND (via GND Pin) | GND (GPIO Pin 14) |
Note: In almost all cases, whether GPIO or USB to TTL converter you must swap your RX/TX. So RX wire one the LoRa module should connect to the TX pin on the SBC/converter and similarly the TX wire on the module should connect to the RX pin on the SBC/converter. Also keep in mind that UART0 is often utilized for serial login to the SBCs for debugging and is standard for Radxa boards, so it best avoided.
Step 2: Enabling the Serial Port on Debian Linux
Power on your Radxa Cubie A7S and open a terminal. By default, you may need to enable the hardware UART overlay. You can manually edit your overlays within /etc/default/u-boot (like this NPU example) or use just the system configuration utility rsetup to ensure the desired UART4 interface is enabled. Once active, the interface will be exposed in Linux as /dev/ttyS4 or similar after restart. The TTY is normally numerically mapped to the UART interface number, but you can always find the lines within the kernel messages sudo dmesg | grep -iE 'ttys'.
Verify the serial connection by running a terminal emulator like minicom at 115200 baud (the default factory baud rate for the RYLR998):
sudo minicom -b 115200 -o -D /dev/ttyS4
Type AT and press Enter. The module should respond with +OK.
If you have issues with minicom or putty hanging your TX and RX pins are likely connected directly and not swapped/crossed as described above. If you consciously get +ERR=1 its because your sending only a new line feed when you hit enter instead of the required carriage return & line feed. Here is a more simplistic pyserial one-liner to connect and issue the AT status command.
sudo python3 -c "import serial; s = serial.Serial('/dev/ttyS4', 115200, timeout=2); s.write(b'AT\r\n'); print(s.readline()); s.close()"
Alternatively you can utilize a simple python lora testing script like the one I vibe coded up, which only required pyserial (
pip install pyserial).
Step 3: Configuring the Shared Secret (PSK Encryption)
For detailed context on configuring secure nodes, refer to the community examples on Arduino Project Hub: Send LoRa Encrypted Data with RYLR998.
To ensure the over-the-air signals cannot be read by passive RF listeners, we configure a Pre-Shared Key (PSK). The RYLR998 supports a built-in encryption feature using the AT+CPIN command. This command sets an 8-character hexadecimal or alphanumeric password. When configured, the transceiver automatically encrypts all payload transmissions over the air.
Run the following AT commands sequence on both the rogue edge node and your handler’s receiver node:
AT+ADDRESS=10
+OK
AT+NETWORKID=18
+OK
AT+BAND=915000000
+OK
AT+CPIN=F38A7C9D
+OK
In this example, both modules are configured to network ID 18, the rogue edge node is set to address 10, the band is set to the US 915 MHz frequency, and a unique 8-character PSK (F38A7C9D) is applied. Any module that does not have the exact same CPIN password will receive only encrypted garbage data.
Evasion Trends: Weather Data Camouflage
While setting a CPIN/PSK password secures the wireless payload from decryption with AES-128, the sheer presence of structured, repeating transmissions can still trigger detection if a defender is actively monitoring the RF spectrum. To bypass automated signal classification systems, threat actors are turning to steganography and signal camouflaging.
Instead of sending raw hex strings or command line responses, attackers write custom wrapper scripts that format their encrypted payloads to resemble standard, benign telemetry. A common choice is to mimic the data packets of consumer-grade weather stations. Many residential and commercial buildings have wireless meteorological sensors transmitting temperature, humidity, wind speed, and pressure metrics on the 915 MHz band.
The following Python script demonstrates how a threat actor might encode an arbitrary command payload into a fake weather station broadcast, as well as how the handler decodes it on the receiving end.
import re
# Simple mapping dictionary to encode hex characters into plausible weather metrics.
# We will use the decimals of different weather readings to encode our payload data.
HEX_MAP = {
'0': (15.1, 45.1), '1': (15.2, 45.2), '2': (15.3, 45.3), '3': (15.4, 45.4),
'4': (15.5, 45.5), '5': (15.6, 45.6), '6': (15.7, 45.7), '7': (15.8, 45.8),
'8': (16.1, 46.1), '9': (16.2, 46.2), 'a': (16.3, 46.3), 'b': (16.4, 46.4),
'c': (16.5, 46.5), 'd': (16.6, 46.6), 'e': (16.7, 46.7), 'f': (16.8, 46.8)
}
# Reverse mapping for decoding
REV_MAP_TEMP = {v[0]: k for k, v in HEX_MAP.items()}
REV_MAP_HUMID = {v[1]: k for k, v in HEX_MAP.items()}
def encode_to_weather(hex_payload):
"""
Encodes a hexadecimal payload string into a series of mock weather telemetry packets.
For demonstration, each hex character pair is mapped to simulated Temp (T) and Humidity (H) decimals.
"""
encoded_packets = []
# Ensure lowercase hex
clean_hex = hex_payload.lower().strip()
# Process the hex string in pairs
for i in range(0, len(clean_hex), 2):
char1 = clean_hex[i]
char2 = clean_hex[i+1] if i+1 < len(clean_hex) else '0'
t_val = HEX_MAP.get(char1, (15.0, 45.0))[0]
h_val = HEX_MAP.get(char2, (15.0, 45.0))[1]
# Format the fake weather string
fake_packet = f"ID:WS915,T:{t_val}C,H:{h_val}%,P:1013.2hPa,W:2.4m/s"
encoded_packets.append(fake_packet)
return encoded_packets
def decode_from_weather(packet_list):
"""
Decodes a list of mock weather telemetry packets back into the original hex payload.
"""
decoded_hex = ""
for packet in packet_list:
# Extract the Temperature and Humidity values using regular expressions
t_match = re.search(r"T:([0-9.]+)C", packet)
h_match = re.search(r"H:([0-9.]+)%", packet)
if t_match and h_match:
t_val = float(t_match.group(1))
h_val = float(h_match.group(1))
char1 = REV_MAP_TEMP.get(t_val, '?')
char2 = REV_MAP_HUMID.get(h_val, '?')
decoded_hex += char1 + char2
return decoded_hex
# Example Usage
if __name__ == "__main__":
# Simulated command to execute: "CMD: WHOAMI" converted to hex
original_data = "CMD: WHOAMI"
hex_data = original_data.encode('utf-8').hex()
print(f"Original String: {original_data}")
print(f"Hex Representation: {hex_data}\n")
# Encode payload as benign weather data
weather_packets = encode_to_weather(hex_data)
print("--- Transmitted Weather Packets ---")
for pkt in weather_packets:
print(pkt)
print("------------------------------------\n")
# Decode back to original command
extracted_hex = decode_from_weather(weather_packets)
reconstructed_string = bytes.fromhex(extracted_hex).decode('utf-8')
print(f"Decoded Hex: {extracted_hex}")
print(f"Reconstructed String: {reconstructed_string}")
Using this method, an analyst reviewing a log of raw sub-GHz packets would only see routine, minor fluctuations in temperature and humidity readings from an un-indexed home weather station. This bypasses signature-based alerts and ensures long-term operational persistence.
For a more detailed example of pulling this all together, check out my lora_weather_encoder and lora_weather_decoder python example scripts. Together they can be utilized on separate LoRa devices to transmit encoded commands as described above.
Defensive Sweeping: How to Locate Rogue LoRa Nodes
To defend physical perimeters against unauthorized edge nodes, security teams must proactively scan for sub-GHz communications. Relying entirely on traditional network inventory dashboards is a recipe for failure, as rogue nodes communicate out-of-band.
Defenders have two primary methods for sweeping the spectrum: using a local UART transceiver configured as a diagnostic listener, or leveraging a Software Defined Radio (SDR).
Method 1: Using a REYAX RYLR998 as a Broad-Spectrum Listener
You could always manually and/or programmatically use a RYLR998 module to listen for transmissions on your site. Doing so would likely require you sweeping through the network IDs from 3 to 255 and listening on each for a set period of time to try and detect unusual signals.
Connect your LoRA module to a laptop/SBC via a USB-to-UART bridge, connect with putty/minicom, and execute:
AT+ADDRESS=0
+OK
AT+NETWORKID=18
+OK
Monitor the incoming serial stream. If you begin receiving unsolicited encrypted strings or repeated structures resembling weather data, a rogue node may be active nearby.
Method 2: Software Defined Radio (SDR) Sweeping
An SDR provides a much more comprehensive view of the RF spectrum, allowing you to visualize and record signal energy across the entire 915 MHz band.
A budget-friendly option is the RTL-SDR dongle, which can be researched on the RTL-SDR Official Community Site. For capturing and reverse-engineering the physical layer packets, Universal Radio Hacker (URH) on GitHub is the gold standard open-source tool.
Follow these steps to conduct an RF sweep:
- Connect your SDR to a laptop and launch your preferred spectrum analyzer software, such as GQRX or SDR Sharp (SDR#).
- Tune the center frequency to 915.00 MHz and set the bandwidth to 2.0 MHz to cover the entire US ISM band.
- Analyze the Waterfall Display: LoRa transmissions utilize Chirp Spread Spectrum (CSS) modulation. In a waterfall display, CSS does not look like a sudden burst or a single narrow spike. Instead, it appears as a series of distinctive, diagonal sweeps moving across the frequency range over time.
- Signal Demodulation: Use URH to record the raw IQ data of the suspected transmission. If the signal is unencrypted, you can demodulate the CSS chirps to reveal the binary data. If it is encrypted (via
AT+CPIN), you will still see the characteristic diagonal sweeps, but the resulting demodulated stream will present as high-entropy, random noise. - Physical Triangulation (Direction Finding): Attach a directional Yagi-Uda antenna tuned to the 915 MHz band to your SDR. Walk the perimeter of your facility while observing the Received Signal Strength Indicator (RSSI) of the suspect frequency. As you move closer to the physical transmitter, the signal amplitude will peak. By taking bearings from three different physical positions on-site, you can triangulate the exact physical location of the hidden rogue node.
Proactive Defenses for the Modern Security Engineer
Rogue edge computing is no longer a theoretical threat vector. The combination of high-compute octa-core SBCs and cheap, long-range sub-GHz UART modules has given threat actors a powerful, low-cost toolkit to bypass traditional enterprise physical security boundaries.
To counter this threat, information security teams must expand their threat modeling beyond the traditional boundaries of the Ethernet jack and the WiFi network. Regular physical security audits must be paired with proactive RF spectrum monitoring. By implementing routine 915 MHz sweeps and understanding the signatures of LoRa communications, you can detect rogue autonomous nodes before they have a chance to compromise your internal infrastructure.