Way West 2022 – Swag Bag Lab 2
Objective
Introduction to capturing, decoding, and replaying radio frequency (RF) 433 MHz signals typically used in activating garage door openers, doorbells, etc.
Outline
Introduction to breadboard circuits
Assemble ESP32 transmitter and receiver boards
Flash Arduino sketches to ESP32 boards
Capture FOB button closures using ESP32 receiver board
Capture FOB button closures using SDR dongle and rtl_433 tool
Analyze and compare findings from the two captures
Replay FOB transmissions using ESP32 transmitter board
Hardware Required
(1) RTL-SDR dongle
(2) ESP32 microcontrollers
(2) Small breadboards
(2) MicroUSB cables
(1) 433 MHz transmitter breakout board
(1) 433 Mhz receiver breakout board
Hookup wires
Software Requirements
Arduino IDE Install (Windows)
Download installer from https://www.arduino.cc/en/software and step through standard Windows software installation.
Arduino IDE Install (Linux)
Download tar file from https://www.arduino.cc/en/software and extract
Open a terminal and navigate to the Arduino folder
sudo ./install.sh (this will also add a desktop shortcut)
Configure Arduino IDE
Select File > Preferences
Additional Boards Manager URLs:
https://dl.espressif.com/dl/package_esp32_dev_index.json
(Note: Multiple boards can be entered, separated by commas)
Click OK
Select Tools > Manage Libraries…
Search: rc-switch
Click Install and Close
Select Tools >Board > Boards Manager…
Type ‘esp32’ in the search window
Find ESP32 by Expressif Systems
Click Install and close window
Select Tools > Board > ESP32 Arduino > ESP32 Dev Modules
Click Install and close window
Install Lab Dependencies
Open a terminal (Windows)
Note: There are some reported problems with PySerial on Windows using Python 3, so stick to Python 2
Type Python <ENTER>
Follow install instructions
pip install pyserial
Open a terminal (Linux)
sudo usermod -a -G dialout $USER (allow non-root permission to access serial device)
sudo reboot
sudo apt install python
sudo apt install python-pip
pip install pyserial
Install SDR drivers (Linux System ONLY)
Create an Ubuntu 18.04 Environment
Download the Ubuntu 18.04 Desktop ISO image from https://releases.ubuntu.com/18.04
Create a virtual machine from the ISO, or (preferred) install it on a UNIX (GNU/Linux, macOS X) compatible system. The software side of SDR can be resource intensive and virtualization can sometimes cause problems such as choppy recordings, which may get in the way of the exercise.
Log in to the Ubuntu system and open a terminal. If prompted, decline the offer to update to “a new version of Ubuntu”.
Open a terminal and confirm you’re in your home directory. This is the preferred convention and will be assumed throughout this text.
Update your distribution.
sudo apt update
Install the tools needed to retrieve, compile, and build the drivers.
sudo apt install -y git cmake build-essential pkg-config libusb-1.0-0-dev
Retrieve, build and compile the RTL2832U Osmocom drivers from the source.
git clone git://git.osmocom.org/rtl-sdr.git
cd rtl-sdr/
mkdir build && cd build
cmake ../
make
sudo make install
sudo ldconfig
Blacklist the driver that Ubuntu already had (which treats the dongle as a TV tuner) because that driver clashes with the new Osmocom drivers we just installed, and we want to use the dongle as a generic receiver, not a TV tuner.
Open your /etc/modprobe.d folder as an administrator.
Create a new file ‘blacklist-rtl.conf’ and add this one line (that’s a lower-case RTL (not RT1) in the middle there)
blacklist dvb_usb_rtl28xxu
Save the file, close the editor and restart the machine.
Install rtl_433 tool
(Linux Only)
sudo apt update
sudo apt install build-essential
sudo apt install cmake
sudo apt install git
git clone https://github.com/merbanan/rtl_433
sudo apt-get install libtool libusb-1.0-0-dev librtlsdr-dev rtl-sdr build-essential cmake pkg-config
cd rtl_433
mkdir build
cd build
cmake ..
make
sudo make install
(Windows install instructions) unsupported
https://github.com/merbanan/rtl_433/blob/master/docs/BUILDING.md
Recommended: Linux PC or Virtual Machine Linux /MacOS X
Building the transmitter and receiver circuits
Introduction to breadboard circuits
The following image (figure 2) demonstrates the physical layout of a typical breadboard. The breadboard allows us to electrically connect components as required for a specific application or project, without the need to solder.
This is often used for prototyping, as it allows the developer to easily change out components or make wiring changes while in the design phase. Breadboards are handy devices for experimenting with electronic circuits and can be used over and over again.
Examining the Inside Connection View of figure 2, we can see the row of connections that run parallel with the blue line (-) are electrically connected. This means that all components and/or wires connected in that row will be electrically connected together (as if they were soldered or welded together). Likewise, we can see the row of connections that run parallel with the red line (+) are also electrically connected. These rows (red and blue) are typically used as power supply rails and allow us to easily provide Vcc (+) and GND (-) connections as needed.
Upon further examination, we can see there are two banks of five-connection rails (a – e) and (f – j) that run perpendicular to the power rails. Each bank consists of thirty rails (numbered 1 – 30). This is useful for the placement of components (resistors, LEDs, ICs, etc).
For example (see figure 3a), if we were to bridge an LED between one bank and the other bank, one leg of the LED could then be connected to Vcc (+) of the power rail and the other leg could be connected to GND (-) of the power rail. Notice that both power rails (left side and right side) are isolated from each other and NOT electrically connected, but can be joined using hookup wire as shown.
Note: It would not be a good practice to wire-up an LED across the power rails without adding a current limiting resistor. Figure 3b shows how we would modify the breadboard connections to include a 330 ohm current limiting resistor to protect the LED.
Assemble ESP32 transmitter and receiver boards
Insert the ESP32 Developer board and Transmitter breakout module into the breadboard as shown below. Be sure to leave the first row (j) open to allow for wiring connections.
Connect the power rails together (not required for this project, but good practice)
Connect ESP32 (3v3) and Transmitter breakout module (Vcc) to Vcc
Connect ESP32 (GND) and Transmitter breakout module (GND) to GND
Connect ESP32 (Rx2) to Transmitter breakout module (DATA)
Insert the ESP32 Developer board and Receiver breakout module into the breadboard as shown below. Be sure to leave the first row (j) open to allow for wiring connections.
Connect the power rails together (not required for this project, but good practice)
Connect ESP32 (3v3) and Receiver breakout module (Vcc) to Vcc
Connect ESP32 (GND) and Receiver breakout module (GND) to GND
Connect ESP32 (Rx2) to Receiver breakout module (DATA)
Flash Arduino sketeches to ESP32 boards
Attach a microUSB cable from the Transmitter board to the PC hosting the Arduino IDE
Select File-New and using your favorite text editor copy and paste the following two Arduino sketches as Transmitter-sketch and Receiver-sketch respectively.
Transmitter-sketch
/*
Example replay previously captured 433 MHz RF signal
*/
#include
RCSwitch mySwitch = RCSwitch();
void setup() {
Serial.begin(9600);
// Transmitter is connected to ESP32 WROOM #16
mySwitch.enableTransmit(16);
// Optional set protocol (default is 1, will work for most outlets)
mySwitch.setProtocol(1);
// Optional set pulse length (used the viewed Spectrogram pulse length data in uSeconds, also appears in Arduino Rcv’d serial output)
mySwitch.setPulseLength(356);
// Optional set number of transmission repetitions (default is 10 reps)
mySwitch.setRepeatTransmit(15);
}
void loop() {
/* using binary code NEW KEY FOB — A – B*/
mySwitch.send(“000011101000100001101000”);
delay(1000);
mySwitch.send(“000011101000100001100100”);
delay(1000);
}
Receiver-sketch
/*
Receiver board sketch
*/
#include
#include “output.h”
#define LED 2
int buttonA = 952424;
int buttonB = 952420;
RCSwitch mySwitch = RCSwitch();
void setup() {
// Set pin mode
pinMode(LED,OUTPUT);
Serial.begin(9600);
mySwitch.enableReceive(16); // Receiver on interrupt 0 => that is pin #2 on Uno –> Pin 16 on ESP32 WROOM
}
void loop() {
if (mySwitch.available()) {
output(mySwitch.getReceivedValue(), mySwitch.getReceivedBitlength(), mySwitch.getReceivedDelay(), mySwitch.getReceivedRawdata(),mySwitch.getReceivedProtocol());
if (mySwitch.getReceivedValue()== buttonA) {
delay(500);
digitalWrite(LED,HIGH);
}
if (mySwitch.getReceivedValue()== buttonB) {
delay(500);
digitalWrite(LED,LOW);
}
mySwitch.resetAvailable();
}
}
Open Windows explorer (or terminal) and navigate to the /Documents/Arduino/Receiver-sketch/ folder Using your favorite text editor copy and paste the following “output” code and save the file as output.h in the folder. (This header file is required for the Receiver-sketch to compile).
output.h (include header file for Receiver-sketch)
static const char* bin2tristate(const char* bin);
static char * dec2binWzerofill(unsigned long Dec, unsigned int bitLength);
void output(unsigned long decimal, unsigned int length, unsigned int delay, unsigned int* raw, unsigned int protocol) {
const char* b = dec2binWzerofill(decimal, length);
Serial.print(“Decimal: “);
Serial.print(decimal);
Serial.print(” (“);
Serial.print( length );
Serial.print(“Bit) Binary: “);
Serial.print( b );
Serial.print(” Tri-State: “);
Serial.print( bin2tristate( b) );
Serial.print(” PulseLength: “);
Serial.print(delay);
Serial.print(” microseconds”);
Serial.print(” Protocol: “);
Serial.println(protocol);
Serial.print(“Raw data: “);
for (unsigned int i=0; i<= length*2; i++) { Serial.print(raw[i]); Serial.print(“,”); } Serial.println(); Serial.println(); } static const char* bin2tristate(const char* bin) { static char returnValue[50]; int pos = 0; int pos2 = 0; while (bin[pos]!=’\0′ && bin[pos+1]!=’\0′) { if (bin[pos]==’0′ && bin[pos+1]==’0′) { returnValue[pos2] = ‘0’; } else if (bin[pos]==’1′ && bin[pos+1]==’1′) { returnValue[pos2] = ‘1’; } else if (bin[pos]==’0′ && bin[pos+1]==’1′) { returnValue[pos2] = ‘F’; } else { return “not applicable”; } pos = pos+2; pos2++; } returnValue[pos2] = ‘\0’; return returnValue; } static char * dec2binWzerofill(unsigned long Dec, unsigned int bitLength) { static char bin[64]; unsigned int i=0; while (Dec > 0) {
bin[32+i++] = ((Dec & 1) > 0) ? ‘1’ : ‘0’;
Dec = Dec >> 1;
}
for (unsigned int j = 0; j< bitLength; j++) { if (j >= bitLength – i) {
bin[j] = bin[ 31 + i – (j – (bitLength – i)) ];
} else {
bin[j] = ‘0’;
}
}
bin[bitLength] = ‘\0’;
return bin;
}
Flash Transmitter Board
Select File > Open/Transmitter-sketch/Transmitter-sketch.ino
Select Sketch > Verify/Compile
Select Tools > Port (select/verify port used by Transmitter board)
Select Sketch > Upload
Flash Receiver Board
Remove microUSB cable from the Transmitter board and PC
Attach a microUSB cable from the Receiver board to the PC hosting the Arduino IDE
Select File > Open /Receiver-sketch/Receiver-sketch.ino
Select Sketch > Verify/Compile
Select Tools > Port (select/verify port used by Receiver Board)
Select Sketch > Upload
Note: After uploading (flashing) the sketch, the Arduino IDE will always perform a hard reset and enable program execution.
Hardware Lab
IMPORTANT: Actual pulse readings will vary from remote to remote. The following remote (FOB) values are for illustrative purposes as a guide only.
Capture FOB button closures using ESP32 receiver board
Connect the Receiver board to the PC hosting the Arduino IDE
Open the Arduino IDE and choose the Receiver board sketch
Note: Upon attaching the Receiver board to the PC, program execution will begin.
Select Tools > Serial Monitor or click the magnifying glass icon in the top right of the screen
With the serial monitor open, press the A-button on the FOB (board internal LED will turn on), followed by the B-button (board internal LED will turn off)
Using your favorite text editor, copy and paste the captured data from the serial monitor to the editor
Copy the comma-separated values (A-Button raw data) to the clipboard
Navigate to https://test.sui.li/oszi/ and paste into the window provided
Copy the comma-separated values (B-Button raw data) to the clipboard
Navigate to https://test.sui.li/oszi/ and paste into the window provided
In this example, we can see the signature differences between the A-Button and the B-Button RF modulations. In this particular case, only the four least significant bits (specifically bit-2 and bit-3) differ.
As an alternative, we can also use an SDR USB dongle and the open source tool rtl_433 (merbanan) to capture the FOB button closures.
Capture FOB button closures using SDR dongle and rtl_433 tool
Attach an SDR dongle to the USB port of the PC hosting the rtl_433 tool software tool (Linux box or VM in this example).
Execute: rtl_433 -G 4
This will configure the SDR dongle to listen for signals tuned to 433.920 MHz, using a default sample rate of 250k samples/second and tuner gain set to auto.
The -G flag enables all blacklisted decoders for testing purposes only and is strongly discouraged for continuous operation. In our case, there’s no problem using it.
While monitoring for RF signals, press the A-Button on the FOB, followed by the B-Button. The following is an example of a successful signal capture:
In this particular case, the protocol was determined to be EnOcean ERP1 (protocol #198) of the 207 supported device protocols listed on the rtl_433 github.
Execute: rtl_433 -G 4 -W FOB_capture (write to file)
This command line instruction will perform the FOB button closure captures and write all of the signal information to the file ‘FOB_capture’ to be analyzed later.
While monitoring for RF signals, press the A-Button on the FOB, followed by the B-Button and then press CTRL-C to end program execution.
Execute: rtl_433 -r FOB_capture -A (read file and analyze)
This command line instruction will read the previously saved file, and display a great deal of information regarding the signals that were captured. The -A flag enables the Pulse Analyzer.
Of particular importance is the generated bit pattern of the demodulated signal. Other useful info is the calculated pulse width value (approximately 356uS). If we navigate to the provided link (yellow), we can see a visual snapshot of the demodulated signal.
Analyze and compare findings from the two capture methods
Comparing the two capture methods, we can see that both methods produced identical on-off pulse timing diagrams. It should be noted that what the Arduino library referred to as ones and zeros and what the rtl_433 tool referred to as ones and zeros differed. However, this discrepancy is of no concern, as the resultant signal is the same.
Replay FOB transmissions using ESP32 transmitter board
Using the information that we gathered through reconnaissance, we can now replay the FOB button closure signals.
Attach the Transmitter board to a power source using the microUSB cable. Note: Leave the Receiver board attached.
Examining the Transmitter Arduino sketch, we can see that our main loop consists of transmitting the binary value of the A-button, followed by a one second delay, followed by transmitting the binary value of the B-Button and a one second delay:
Reminder: Your readings may (very likely) differ from the examples presented in this document. In order to continue with the replay, you will need to modify the loop function to match your actual findings. Upon changing the values, you will need to recompile the sketch.
Following a successful compile, the Transmitter board will begin transmitting the values loaded into the sketch.
With the Receiver board still connected to the PC hosting the Arduino IDE, the running Receiver sketch will enable the internal LED when the A-Button signal is present and disable the LED when the B-Button signal is present.
Monitor the activity of the internal LED on the Receiver board. It should follow the one second intervals established in the Transmitter board sketch.
SUMMARY
Realizing how easy it is to replay remote control signals with very inexpensive tools and components has pushed the technology to safeguard our remote control garage doors and motor vehicles against replay attacks.
Rolling code protection was introduced in 1980, but not standardized for garage door openers until the mid 1990’s. Prior to then, the codes were hard-coded using dip switches and vulnerable to MitM replay attacks.
Using what you have learned in this lab, you can now continue on and attempt to solve a challenge centered around capturing and deciphering OTA 433 MHz signals.
The Swag Bag Challenge can be accessed here: https://wildwesthackinfest.com/way-west/sbl-challenge-2022/