Hardwear.io CTS 2020

Capture the Signal

This year Hardwear.io went virtual! How great was that! And Capture the Signal (CTS) was part of it. We hadn’t heard of it before but danyc0’s interest was piqued, and we thought we’d give it a go. I (neko3) have never played around with any of the tools (GQRX, URH, GnuRadio, etc) and don’t have experience with radio signals, so why not. And what great fun it was, we learnt so many new things. Might even get inspired and do a signals challenge for the next AFNOM WTCTF!.

Below we’ve done writeups for the first three challenges. We got the 3rd one half an hour after the CTS ended but… a solve is a solve. We solved 4-6 the following week during a hacking club session. We’ll update (or do a new post) if/when we solve the rest of them. There were 7 challenges in total, I think we did okay for newbies .


The organisers have kindly provided a VM with all the tools needed. They also pointed us to CTS Tools (go through the README, it’s a big help), which were needed in order to connect to the CTS infrastructure and receive RF data over IP. So we could concentrate on decoding the signals, and not faff around with setups. The whole idea of sending RF signals over IP is really cool, and you can read more on their Github on how they do it. We found that we needed to run sudo dhclient <interface> to get a working internet connection (thanks Ubuntu!), install python-qt4 on the VM and rebuild CTS Tools for them to work. But everything else worked like a charm.

First, we had to resolve rf.cts.ninja to get the server IP (CTS tools needs an IP):

$ ping rf.cts.ninja
PING rf.cts.ninja ( 56(84) bytes of data.

There was a test signal @ 400MHz, so we started off with that to understand how to connect and capture signals. CTS Tools writes the data to a fifo file, and you can point other tools to the file and consume the data. In order to do this, we run the rx_to_fifo.py script, giving as arguments the server IP and the signal’s frequency:

$ python rx_to_fifo.py --server-ip= --rx-frequency=400000

You then have to start consuming some data from the fifo file, in order to get the bitrate, which is required for most tools.

$ cat cts.fifo > /dev/null

Data from the fifo can also be redirected to a file, in order to be used with various tools.

$ cat cts.fifo > signal.data

Signal 1

The first signal was transmitted @ 435MHz, and had a bitrate of 128000. Using GQRX, the signal can be consumed straight from the fifo file by configuring the IO device string to be


Viewing the spectrum of the signal revealed text is actually spelled out by it:

HWIO2020: welcome! Listen @ 236 Mhz

Nice warm-up challenge!

Signal 2

So the 2nd signal is transmitted @ 236 Mhz, and the bitrate is 64000. Still using GQRX, we reconfigure the IO device string to be:


Looking at the waterfall spectrogram doesn’t reveal anything interesting. Here is when dancy0 had an ‘aha!’ moment! He noticed that the audio wave could look like there is voice transmitted. Initially, it was not clear at all, but after realising there is a mirrored transmission, for left and right, we adjusted the frequency, and there it was, some comprehensible audio! The voice said:

hello hallo hello 1.44 GHz sync a7