Breaking Protocol

Andre Ng
CSG @ GovTech
Published in
13 min readJun 3, 2020

TL;DR: You can remotely open auto-gates of private residences, security turnstiles, sliding glass doors, garage doors, and carpark barriers. This is possible because passcodes are sent wirelessly without encryption and attempting all 6561 possible combinations can be done in minutes. In this article, I detail my research into this pervasive and insecure protocol that is typically transmitted over 433MHz.

Remote control with no security

I chanced upon the means to “duplicate” an auto-gate remote control when I accompanied a friend to Sim Lim Tower to replace his auto-gate remote for his residence. There were only two parameters in the duplication process: the transmission frequency and the position of the DIP switch. There was technically another parameter: the SMC5326 chip used to determine the encoding. However, because these generic remote-control devices are so widely found in the Singapore and Malaysian markets, it would be reasonable to assume the same chip was used.

Having seen these types of remote-control device being used for a wide variety of applications — security turnstiles, residential auto-gates, garage doors, and car park barriers, I bought one for the purposes of tearing it apart for further analysis.

This is how the remote controller device typically looks like.

If you guessed that the wireless protocols generated by these devices are not protected by any encryption or rolling code, you guessed right. 😉

Only three key device parameters

As mentioned earlier, there are three key parameters to the remote control: the frequency it operates on, the chip used for encoding, and the DIP switch configuration which determines the secret passcode.

Internal circuity of a typical 433 MHz remote control

The frequency it operates on is determined by the crystal used in the circuity. Thus, you can tell the frequency by reading the crystal value. 433 MHz are basically 433.92 MHz to be exact. Sometimes, you will see 13.560 MHz crystals used for 433 MHz transmission; this is because the 13.56 MHz frequency is multiplied 32 times to reach exactly 433.92 MHz.

13.560 MHz crystal on a 443MHz transmitter module

The encoder chip generates a specific bitstream and transmits a message in a series of “pulses” on a fixed frequency. In an ASK system, the binary symbol 1 is represented by sending a fixed-amplitude carrier wave at a fixed frequency for a duration (usually in micro or milliseconds). In this case, my remote control uses an SMC5326 chip. This chip can be configured to transmit a range of different message by configuring the DIP switch.

The DIP switch configuration determines the secret passcode that is used to open doors. The DIP switch has eight toggles. Each toggle has three positions. This also means that there is only 3⁸ , or 6561 possible configurations.

6561 passcodes extracted from the DIP Switch

To extract all 6561 passcodes, I needed to read the values it was transmitting. For this, I used a cheap 433 MHz transmitter and receiver pair bought online (they go for less than SGD$4) and connected them to my Arduino.

Transmitter and Receiver pair. Make sure you use the correct hardware.

For the software, I used the rc-switch library.

Once the receiver is connected and you have imported the rc-switch library to your Arduino library, you can use the sketch code below to receive the 433 MHz transmission.

The code below will allow you to receive the signal and print out its value, bit length, and protocol.

include <RCSwitch.h>RCSwitch mySwitch = RCSwitch();void setup() {
Serial.begin(9600);
mySwitch.enableReceive(0); // That is pin #2
}
void loop() {
if (mySwitch.available()) {

Serial.print("Received ");
Serial.print( mySwitch.getReceivedValue() );
Serial.print(" / ");
Serial.print( mySwitch.getReceivedBitlength() );
Serial.print("bit ");
Serial.print("Protocol: ");
Serial.println(mySwitch.getReceivedProtocol());
mySwitch.resetAvailable();
}
}

You can refer to this step-by-step tutorial to get all of the above done if you need more help.

If done correctly, you should see something like this in your serial output when you press the remote-control’s button:

Take note of the value, bit length and protocol number

Toggling the DIP switch incrementally, starting with the lowest value from the right, I noticed that the unsigned integer kept increasing.

Series of readings

To figure out how I could programmatically go through all 6561 possible passcodes, I analysed the first nine captured sequences and looked for patterns within the binary and integer values.

unsigned int    |     Binary
---------------------------------------------------------
469 | 00000001 00000000 00000001 11010101
1493 | 00000001 00000000 00000101 11010101
2005 | 00000001 00000000 00000111 11010101
4565 | 00000001 00000000 00010001 11010101
5589 | 00000001 00000000 00010101 11010101
6101 | 00000001 00000000 00010111 11010101
6613 | 00000001 00000000 00011001 11010101
7637 | 00000001 00000000 00011101 11010101
8149 | 00000001 00000000 00011111 11010101

I learned from the captured signals that when all toggles are set to the lowest value, it results in a value of 469. This is seen in the constant appendage of “1 11010101” in the binary representation of every transmission. This appendage is also known as the “base”, and the “base” is determined by the input instruction. In this case my input instruction was a button press. This “base” changes to 373 when I press the second button.

u_int | Binary
--------------------------------------------------------
469 | 00000001 00000000 0000000 [1 11010101]
|
input instruction (base)

Starting from the right most toggle (number 8), by pushing a toggle by one notch increases the value by 2¹⁰, resulting in a value of 1493.When the same toggle goes up by two notches, it increases the value by 2⁹, resulting in a value of 2005. The picture below illustrates this.

An example with only one of eight toggles pushed up by two notches.

In binary representation, it looks like this

u_int | Binary--------------------------------------------------------
469 | 00000001 00000000 00000[00] [1 11010101]
| |
(-) toggle at its lowest input instruction (base)
--------------------------------------------------------
1493 | 00000001 00000000 00000[10] [1 11010101]
| |
(0) 1 notch up input instruction (base)
--------------------------------------------------------
2005 | 00000001 00000000 00000[11] [1 11010101]
| |
(+) toggle 2 notches up input instruction (base)

With the diagram below, I will be able to determine the passcode value from any DIP switch configuration pattern.

Values in every possible toggle position

Brute forcing all 6561 passcodes

Applying the knowledge obtained from analysing the remote control, we could reasonably transmit passcodes using a brute-force algorithm to attempt all possible configurations of the DIP switch. You will first need to use the transmitter and connect it to the Arduino. Refer to this tutorial here to do so.

I was able to open the auto-gate in my own home with the brute force algorithm below. I would like to take this opportunity to offer special thanks to my colleague Bjorn and JieFeng for helping me find a more efficient way of doing this.

#include <RCSwitch.h>RCSwitch mySwitch = RCSwitch();void setup() {
Serial.begin(9600);
// I used PIN 10
mySwitch.enableTransmit(10);
// select the correct protocol, I used protocol 5 initially
mySwitch.setProtocol(5);
}
void bruteforce() {
int lut[] = {0b00, 0b10, 0b11}; //correspond with -, 0, +
for(int i = 0;i < 6561; i++) { //6561 = 3^8
unsigned long base = 469;
unsigned long dipswitch = 0;
int base3_int = i;
//There are 8 groups of 2 bits each, fill them in
for(int j = 0;j < 8; j++) {
dipswitch |= lut[base3_int % 3] << (2 * j);
base3_int /= 3;
}
base |= (dipswitch << 9);
Serial.println(base);
mySwitch.send(base,25);
}
}
void loop() {
bruteforce();
Serial.println("bruteforce complete!. Restarting sequence in 1 min ...");
delay(60000);
}

Failure at the security turnstile

I was confident that security turnstiles at my office building would operate in a similar fashion like auto-gates. I had previously witnessed the security guards manually overriding controls to allow “VIP or handicap” access using the same remote control. With some patience, I managed to capture the transmission value, or the passcode. However, I was still unable to replay the captured transmission on my Arduino.

With the captured value, I was able to deduce the DIP switch configuration and “clone” a separate remote. This was done by converting the captured value (as an integer) to binary and subsequently looking up the DIP switch mapping.

I was only able to replay the open and close commands with a cloned remote control.

Only the cloned remote succeed at opening the turnstiles

Wrong protocol

After some troubleshooting, I realised that the protocol used by the rc-switch was not accurate. This was why I was not able to successfully transmit a recognisable command to the turnstile using my Arduino while the remote control worked fine. It seems that the security turnstile had a lower tolerance for protocol errors.

Using the SimpleRCScanner, I was able to compare the difference between the protocols from the Arduino transmitter and remote control.

The protocol (protocol 5) transmitted using the SimpleRCScanner library
The unknown protocol transmitted by the remote control

I realised that protocol 5 of the RCSwitch library was close to the unknown protocol from the remote control but not a perfect match. In other words, it shared the same number of long pulses and short pulses but did not have the same width or pulse-length. If I wanted to emulate the signals from the remote control, I had to correct three aspects of the protocol:

1) Pulse Length;
2) Bit representation and
3) the Synchronisation Bit

Pulse Length. A pulse length, also known as a pulse duration or pulse width, is the length of time allocated for the transmission of a HIGH (1) or LOW (0) pulse. This pulse length is usually measured in micro-seconds, not milli-seconds.

Bit Representation. A bit is represented by a series of HIGHs and LOWs. For example: Both 0 and 1 bits are represented by a different combination of four successive HIGH / LOW pulses. In our case, the 0 bit is represented by a single pulse of HIGH followed by three pulses of LOW. The 1 bit is represented by three pulses of HIGH followed by one pulse of LOW.

Synchronisation bit. Finally, there is a synchronisation bit, which determines the start or end of a transmission. Like the 0 or 1 bit, a synchronisation bit is represented by a combination of successive HIGH / LOW pulses. Synchronisation bits are usually short series of HIGH pulses followed by a long series of LOW pulses. In most cases, the LOW pulses are unusually prolonged, consisting of a series of many LOW pulses, to make it clear that a data transmission will soon follow.

Correcting the protocol worked!

If I wanted to emulate the signals from the remote control, I had to correct all three aspects of the protocol: 1) Pulse Length; 2) Bit Representation; and 3) the Synchronisation Bit.

Correcting the pulse length. Each pulse length from the unknown protocol’s visual representation indicates the length at about 300 micro-seconds. You can roughly deduce the pulse length by looking the smallest discrete pulse length value in the graphical representation above. Protocol 5 has a pulse length of about 500 micro-seconds.

Correcting the bit representation. Reading the unknown protocol’s visualisation, the ‘0-bit’ is represented by a series of one HIGH pulse followed by three LOW pulses and the ‘1-bit’ is represented by a series of three HIGH pulses followed by one LOW pulse.

0-bit (represented by one HIGH pulse followed by three LOW pulses)
1-bit (represented by three HIGH pulses followed by one LOW pulse)

Correcting the synchronisation bit. Again, from reading the unknown protocol’s visualisation, with some simple division, I can guess that the Synchronisation Bit is represented by a series of three HIGH pulses (904 / 300 3) followed by (7612 / 300 25) LOW pulses.

Synchronisation bit to mark the start of a transmission

With these changes, it was essentially defining a new protocol. Hence, I added a new line (Line 89 in the screen capture below) called “Protocol 13” within ‘RcSwitch.cpp’.

Specifically, I added the following line:

{ 300, {  3, 25 }, {  1,  3 }, {  3,  1 }, false}.

and what do they mean?

300 = Pulse length{3,25} = Synchronisation bit represented by three HIGH pulses followed by 25 LOW pulses{1,3} = 0-bit represented by one HIGH pulse, followed by three LOW pulses.{3,1} = 1-bit represented by three HIGH pulses, followed by one LOW pulseFalse = Invert signal. Set to false because there is no need to invert the signal.

Once the new protocol entry was created in the library with my corrected code, I was able to open the security turnstiles. 😊

I finally succeeded at replicating the signal. Yay!

With the correct protocol, you will be able to programmatically brute-force receivers with stricter tolerance.

Planting a backdoor as a bonus

With the transmission protocol hacked, I directed my attention at the receiver and wondered if the all automated doors or automated gates worked on the same principle of using a simple relay to signal the open and close of the gate. If this assumption was true, I would be able to plant a simple radio-controlled relay on the control panel to give me an alternative workaround to some physical access controls in my office; something like a backdoor access.

Out of curiosity, I studied the automatic sliding barrier at my office below. Under normal operation, you will need to tap your badge / access card before it slides open.

The sliding gate in my office

I thought that this gate opened rather slowly, and it would be good if it could be opened from a distance as I approached it instead of tapping my access card.

Interestingly the controller board for the sliding gate was not locked and easily accessible using a screwdriver to unmount the casing.

The next step was to identify the control panel model number and search online for some documentation. After a few hours of fruitless searching I could not find any documentation. I was, however, able to identify the distributors of the GLEES control panel or controller board.

After making a few phone calls, I finally met a small business owner who was willing to explain to me how this model of controller board worked. He empathised with me because he knows that there is no formal documentation for this controller board. I met with him to learn more about the board.

This is how the controller board works:

Detaching the screw terminal connector to exposes important labeling

To give the controller board the “open the gate” command, you simply needed a dry switch to close the connection between the common port (COM) and OPEN ONLY port. The same logic applies to CLOSE ONLY and OPEN & CLOSE. This means, the access card reader is a separate “sub-system” that is connected to the controller board that only acts to close a switch if an authorised personnel badges in. If you can connect the OPEN ONLY port to the COM port, you will be able to open the gate.

With this knowledge, I went back to the sliding door at my office and connected a radio-controlled receiver to the controller board. Because the radio-controlled receiver was small, I was able to hide it in the enclosure neatly without any issues.

Professionally concealed receiver using masking tape

With that, I was able to open the sliding barrier with my remote control with the help of the backdoor receiver that I hid in the mess of wires.

Open Sesame!

No happy ending if you don’t ask for it

Resolving the vulnerabilities described in this article requires hardware changes since there is no way to remotely patch these controller boards or change the rudimentary construct of these receivers over a network. Firmware embedded into these controller boards are burnt-in and the only way to patch this is to replace the entire module with one that uses better security, such as rolling codes or encryption. There are plenty of vendors offering such secure alternatives, so it is still possible to remediate such vulnerabilities. Finally, to prevent bad-faith actors from planting backdoors like what I did, you will want to secure physical access to your controller boards such that only authorised personnel are allowed access to them. It also does not hurt to make regular checks on these “sensitive” components to make sure that they have not been tampered with.

Unfortunately, the industry will not change until consumers demand better security for their radio-controlled gates and barriers. This is because selling these rudimentary and vulnerable receivers remain extremely profitable. My market survey on three different vendors revealed that a set of receivers and a pair of remote controls retails between SGD$100 — $200, excluding labour costs. Buying the raw receiver with an accompanying 433MHz remote from AliExpress, however, sets one back less than SGD$5. The mark-up is significant, thereby suggesting that there is no economic impetus for the market to change. Hence, things are unlikely to change until the buyer is enlightened (or reads this article). If you are holding on to one of those remote controls mentioned in this article, perhaps it is time to upgrade to a more secure standard.

In case you were wondering, the office building facilities management have since been informed about this vulnerability and are looking to resolve this at the time of writing this article. The backdoor planted in my office sliding door has also been removed after the proof of concept was accomplished and documented.

Stay safe!

Special shout-out to Bjorn and Inn Fung for being part of this adventure.

--

--