In our last post, part 2, we successfully captured the binary messages sent from the Score9 scoreboard controller to the receiver. Our main tools were the HackRF One software-defined radio and the Universal Radio Hacker tool. We had the binary, but unfortunately, as we discovered, it was encrypted - this became a serious challenge for us, and that is when we broke out the hardware attacks. Senior Security Engineer Maxwell Dulin has published an outstanding write-up for his approach to this. I recommend that you check it out for an insight into our process.

Part 3: Executing the Attack!

RF Transceiver Module

The transmitter and receiver units have nice plastic shells, but it didn't take long to crack those open so we could look at the bare circuit boards. The receiver appeared to be built using a Raspberry Pi and a couple of additional hardware modules. None of this seemed secret; Googling the labels on these modules opened up a wealth of information. You can see it for yourself. Here's the product page for the RFM69HCW transmitter, and here is its instruction manual. These told us a lot about what we were dealing with.

Maxwell tried several different approaches for attaching to the hardware. He found that while the manufacturers had correctly enabled the security mode in ICSP and thus blocked us from directly connecting to the modules, there was one major weakness on the board. We could see that the RF module and the processor module are wired together and speak to each other over a Serial Peripheral Interface (SPI) bus. However, we also knew from the instruction manual that the processor knows the encryption key, and it MUST send it to the RF module for the encryption step. This key is just sent over the wire. We can sniff it right off the board!

man-in-the-middle attack between RF module and Atmel Processor

For that, Maxwell broke out his logic analyzer of choice, Salae Logic. 

After restarting the receiver, Salae sniffed the wires and revealed the key to be: 0x01020304050607080102030405060708. Not the most random. I'm guessing that this is some default key.

The extraction of this key was a massive step for us. Without this key, we'd still be able to execute replay attacks or maybe other types of blind attacks, but with this key, many new approaches were unlocked for us. 

The Final Encoding

We still had a few puzzle pieces left here, some big ones too. And again, the documentation was a huge help with these. First, it told us exactly how they are encoding the bits in the air. It may seem counter-intuitive, but at this layer, you typically can't send the raw 1s and 0s from the data that you actually want to deliver. The problem is that some numbers or data will be naturally represented by consecutive 1s and 0s; take the number 15, which in binary is 00001111. If you transform these bits into an analog or electrical signal, how is the receiver supposed to know precisely when the next 0 or 1 begins? It can't. It's going to lose track of them almost immediately.

The solution to this is a simple line code, transforming the data bits into transmission bits so that there are no more than two consecutive 1s or 0s in a row. So now, 15 might be 10010110, which will be more easily decoded on the receiving end. Line code is a simple transformation and easily reversed. There are a couple of different approaches here: In one way, you can take each bit and encode it as two bits that transition, such as a 01 or 10. This is the method used by the popular Manchester Encoding line code. On the other hand, you can also transform the data bits directly to avoid excessive identical bits in a row, a method called data whitening.

manchester encoding line both conventions signal

In our experience with signals, we expected Manchester encoding or a similar stratagem. To our surprise, we discovered in the documentation that they were doing the other method, data whitening. After some thought, this does make sense. As we described in Part 2, the controller's signal is already at an astounding 250,000 bits/second on a single FSK stream, which is stretching the limits there. Manchester Encoding and its transformation of each bit into the transition of two symbols mean that we'd double the baud rate to 500,000. Ludicrous! Data whitening just makes sense.

Luckily, the RF module's documentation told us a lot about their data whitening. It uses a Linear Feedback Shift Register (LFSR), which can be found in some random number generator algorithms. The LFSR operates by cyclically shifting and XORing the data bits with themselves, producing a transformed output that avoids the excessive consecutive bits problem. This process can be easily reversed to recover the original bits, and the cycle starts with an initialization value. This initialization value didn't seem to be documented, but a couple of engineers at Security Innovation put our heads together (shoutout to Max Arnold!) and were able to brute-force it. Maxwell has an excellent write-up of his approach to tackling the LFSR, explaining the technique. With this solved, only one piece remained in our data packet: the CRC checksum at the very end of the packet.

packet format length emphasis on data whitening, CRC checksum calculation

The CRC is similarly cyclic to the LFSR. In the CRC, a small pattern of bits, defined by a polynomial, is repeatedly XORed with a shifting section of the data bits. In the end, this produces a final code that is a checksum for all the data bits, which won't match if any data bits are changed. Clearly, computing this CRC code is necessary, or the receiver won't accept our synthetic signal. However, this CRC proved to be another challenge. The RF module's documentation told us this polynomial, but we couldn't compute the CRC correctly because it didn't tell us the initialization value to start the cycle. In fact, the module didn't seem to be using any standard initialization value at all. Ultimately, we had to rely on a tool, the CRC RevEng. The CRC RevEng is a convenient tool considering all you do is plug in your data bits, and it produces all the parameters for the CRC. We plugged those in, and it worked!

discord_screenshot

At this point, we completed the remaining pieces of the puzzle. Maxwell had written a Python class that effectively acted as a driver, taking commands to the scoreboard over an API and delivering the final digital sequence. We knew our reverse engineering was successful when we compared the output of this Python class to the digital data we extracted from the radio signal.

Transmission!

One final step remained. Our code could only produce the sequence in software, and we needed to deliver it wirelessly. Maxwell and I are both licensed amateur radio operators, so we put that to good use. Our tool of choice was GNU Radio, a framework to do Digital Signal Processing (DSP) in software. GNU Radio allows us to assemble individual DSP steps into a bigger flowgraph, which can then modulate our scoreboard bits into an FSK signal. We can then couple the GNU Radio into a Software-Defined Radio, such as the company's HackRF One. After some invaluable assistance from Derek Kozel, we came up with this flowgraph:

gnu radio flowgraph

The flowgraph starts with the Vector Source block, which simply delivers the digital_sequence variable, our array of bits, into the flowgraph. From there, the Repeat block applies interpolation, duplicating each bit 20 times, and oversampling so that we can deliver them at our target of 250,000 per second while delivering the minimum of 5 million samples/second into our HackRF One hardware. The Throttle block ensures that we keep to this speed. From there, the oversampled bits are sent into the Voltage Controlled Oscillator (VCO), a block that produces a frequency signal whose pitch is based on the input. Since we just have 1s and 0s flowing in, we effectively get high and low frequencies going out - this is Frequency Shift Keying! After this, the Low Pass Filter block cleans up some high-frequency noise generated from the VCO, and we have our fully modulated signal ready to send. 

The last step in this flowgraph gets us around a flaw in our SDR hardware. The HackRF One produces a large spike of energy in the center of the target frequency, which would otherwise interfere with our signal. This is easily avoided in software, though; the Rotator block shifts our signal down 500 kHz, and then we simply transmit 500 kHz above normal, so everything lines up where it should, and that spike is out of the way. Our final block, the Osmocom Sink, accepts our modulated samples, our fully FSK-modulated scoreboard signal, and sends it into the HackRF One.

hardware-hackrf-one-sdr-software-defined-radioTo now deliver the attack, we assembled some hardware. As shown in the picture (right), we have our HackRF One SDR, a low-noise amplifier from GPIO, and a Yagi-Uda antenna for 922 MHz that we custom-built for cheap using some sticks and copper wire from Home Depot. The SDR, the amp, and the directional Yagi work together to deliver our signal as loud as possible, near the ISM band's legal maximum power limits.

We connected the USB ports to our laptops, hooked our Python code to the GNU Radio modulator, and fired it up. Success! With such a loud signal, our commands overpower the real controller, giving us complete control over the scoreboard at a significant distance.

Now we could execute some really stealthy attacks. Our favorite, by far, is what we call the Fast Clock Attack. 

Do you see what's happening here? The attacker can speed up the game clock just enough to take precious seconds away from an opposing team but still relatively imperceptible to the human spectators.

We also found a strange denial-of-service attack too. If we command the scoreboard to turn the horn on and off extremely rapidly using our RF signal, faster than a human could repeatedly tap the button on the controller, the whole scoreboard will lock up. After diving into the Raspberry Pi component, we realized this occurs because a Bash script powers the horn. Rapidly toggling it consumes so many resources and builds race conditions that lead to a complete system freeze. The only way to recover is by physically restarting the whole scoreboard – obviously not ideal in the middle of a game.

Maxwell and I naturally realized that a malicious attacker could run these attacks in some stealthy ways. They could slow the game clock down imperceptibly or, even better, continually deliver the normal scoreboard state with the horn flag set to "off." This way, when a team scored, and the game staff pressed the horn button, the two radio commands would intermingle and conflict, creating a very fast toggling that would lock up the entire scoreboard. If properly executed, this would look to game staff like a bug in the scoreboard, some error firing off the horn.

The scoreboard is considered a source of truth in professional games. It is trusted. If you can crack the signal and completely reverse-engineer the commands, as we did here, there are so many ways that attacks can be strategically valuable. To the best of our knowledge, this is the first time that a scoreboard has been reverse-engineered and cracked at the RF layer like this. It was also an extremely educational project, and we walked away with new skills and experiences from each step of the process. We have released our Python APIs and the GNU Radio driver on Github. Please let us know if you would like us to apply our knowledge to your own RF project.

In closing, I'm reminded of something Charlie Sheen once said, 

"… but like in baseball, the scoreboard doesn't lie. Never has." 

 Well, I don't think I could trust this:

fuzz_screenshot


About Jesse Victors, Senior Security Engineer
Jesse Victors is a senior security engineer at Security Innovation. His technical interests include privacy and anonymity systems, password cracking, RF attacks, and applied cryptography. Jesse has also published The Onion Name System: Tor-powered Decentralized DNS for Tor Onion Services and spoken at the Privacy-Enhancing Technology Symposium. In the evening you can often find him in virtual reality games, fiddling with amateur radio antennas, and networking with orbiting satellites. Jesse has pursued information security since 2014. Connect with him on LinkedIn.

About Maxwell Dulin, Senior Security Engineer
Maxwell Dulin is a senior security engineer at Security Innovation who specializes in web application security and IoT security. He has also spoken at DEFCON for his IoT research on the Zyxel NAS and is the founder/creator of the Spokane Cyber Cup. In his free time, he plays dodgeball and enjoys hiking. Connect with him on LinkedIn.