Hardwear.io Capture The Signal Write-Up

Filter by category:

September 17, 2020 by Vincent Lopes
Hardwear.io Capture The Signal Write-Up
On 30th April and 1st May took place the Hardwear.io convention. Due to the current circumstances, it was taking place online, on Zoom. We have to admit we spent much more time on the Capture The Signal challenge than on listening to the speakers. Here is our experience of this challenge.
We realized before the beginning of the CTS that we were going to need GNU Radio 3.7 to receive the signals. We installed Ubuntu 18.04, got GNU Radio from the default repository, and got ready for the first signal.

Day 1

Signal 1

After having some trouble with the reception of the signals, we finally managed to get the signal 1. We jumped on one of our favourite signal processing tools, Inspectrum. It can plot a spectrogram of the signal, that is to say the amplitude against time and frequency. It is also able to plot the frequency, the phase, the amplitude or the samples and to extract symbols from any of the characteristics of the signal.

In this spectrogram, it clearly seems there is something written here, but it is not that easy to read. It would have been possible to think about a way to invert the signal in frequency, or to take a screenshot and then apply some symmetry and rotation, or even to read this flipped writing, but to be honest we only used a mirror here. It gave us the first flag: “HWIO2020: welcome! Listen @ 236MHz”.


Signal 2

Signal 2 didn’t seem to be a digital modulation. In fact, we were told before the challenge that signal 1 and 2 did not contain any encoded data. Therefore, we guessed it was FM modulation. It could have been possible to check this by visualising the waveform in Audacity or Kwave for example, but we decided to check this by sending it to the audio card and by trying to hear something. Demodulating this in GNU Radio is quite easy, you only have to be careful about the sample rate. The input sample rate is 64 KHz, and the audio card accepts, among others, signals with a sample rate of 48 KHz. The least common multiple of 64 and 48 being 192, we want to use an interpolator here, upsampling the signal to 192 KHz, then the WBFM demodulator block, downsampling it to 48 KHz. We could then listen to the flag : “hello hello hello 1.44GHz sync A7”.


Signal 3

According to its spectrogram, Signal 3 seemed to be OOK (on-off keying). We used Inspectrum to extract the symbols, and then Python to decode the bits. We tend to prefer Inspectrum to Universal Radio Hacker for several reasons:
- Inspectrum has a better management of huge files
- We can see what is happening since nothing is automatic
- Inspectrum provides more visualisations of the signal (amplitude, IQ, phase and frequency)
Of course, Universal Radio Hacker provides tons of functionalities that Inspectrum does not, but in this context, these functionalities were not useful. It may be faster to use Universal Radio Hacker if everything works, but you may lose a lot of time if you come to struggle with it.

The Python script we used is below. It does not take into account the format of the packets since the aim here was to be fast, not to be accurate. Thus, the script ASCII decodes every possible shift of the recorded bits, to be sure one of them will be correctly bit aligned. We just had to read the output of the script to find the flag: “FREQ:514MHz,SYNC:0x4F”.

The format of the packet is the following
- Synchronisation bits : eight times ‘01’
- Syncword on one byte (given in the previous flag)
- Length of the payload on two bytes
- ASCII encoded payload
Again, knowing the format of the packet was not actually necessary here, but it will be to implement the receivers.

Signal 4

Plotting the frequency of signal 4 shows that it is modulated using BFSK (binary frequency shift keying). A simple extraction in Inspectrum followed by the use of the previous Python script gave the flag. Again, the format of the packet is the same as signal 3, using the synchronization byte from the last flag : “FREQ:592MHz,SYNC:0x850D32F1”.


Signal 5

At first, we thought Signal 5 was something like M-PSK (M-ary phase shift keying). This is why we spent a lot of time on this signal. Actually, the synchronization bytes were modulated in BFSK, whereas the other part of the signal, the flag, was modulated using QFSK (Quaternary Frequency Shift Keying). For quite a long time, we did not manage to see there were four distinct levels for the frequency of the signal. Actually, demodulating this signal was not so hard. Now that we know it, it almost seems obvious. We extracted the samples thanks to Inspectrum, and then we found the thresholds between symbols by looking at the samples.

Then, we used another Python script to test all possible permutations to know which symbol corresponded to which pair of bits. It is a bit like using a sledgehammer to crack a nut, but it works anyway. We only had to look for something readable in the output of the script and it gave us the flag: “FREQ:2.54GHz,SYNC:0xC00F”.

It turned out the coding employed was a Gray code, which reduces the bit error rate.


Day 2

On day two, we no longer had to demodulate signals, but to provide receivers for signals instead. The receivers had to be GNU Radio flowgraphs and could use some Python as well.


Receiver 1

Receiver 1 was, like Signal 3, OOK. Demodulating it using Inspectrum is simple. Using GNU Radio, it is a bit less straightforward. First, we had to find the symbol rate. We can do this using a GNU Radio Time Sink for example. It could have been possible to use a more mathematical tool, like an FFT or an autocorrelation. Then we designed a flowgraph recording the bits in a file. The flowgraph below first applies a threshold to the input, and then takes one sample for each symbol.

Finally, below is a Python script to read the bits and to print the payload of the packet in the signal.

We got a warning here from the admins since our Python script worked but did not use the whole format of the packet. Actually, our script did not take into account the synchronization bits. A careless mistake.


Receiver 2

Finally, Receiver 2 was, like Signal 4, BFSK. After doing Receiver 1, it was very similar to implement a receiver for BFSK. By replacing the Amplitude block by a Quadrature Demod block, we can apply a threshold to the frequency. Then, the last part of the demodulation chain is the same.

The Python script we used is below. It is very similar to the last one. Thanks to the warning we had before, we did not forget to spot not only the synchronization word but also the synchronization bits, for our script to be validated.

We submitted the flag sixteen minutes before the second, and then all we could do was hoping no one had managed to decode Signal 6.

Signal 6 was, according to the clue given, something close to 802.11a. The signal actually looked like OFDM (orthogonal frequency-division multiplexing) but since we have never played with this kind of modulation for now, we did not try to work on this one. Fortunately for us, no one managed to decode it.
As we were the first to send the flag for Receiver 2, we finished first and won this contest!