SpaceHeroes: RF Math in Space

back · home · ctf · posted 2022-04-01 · processing "broadcasted" QPSK-encoded bytes · (495 points, 8 solves)
Table of Contents

I'm sure no ones listening....right?! Someone thought it would be a good idea to transmit their access keys to their constellation in the clear. Luckily you have a subscription to an RF monitoring service. Author: Cromulence

Context

We're provided with a file called samples.bin as well as generate_samples.grc. From that, we can guess that they did some stuff to a file/signal that holds the flag, and the resulting data is in the .bin file.

And the .grc extension means, of course, GNU Radio Companion, the holy light of FOSS signal processing. (Thanks Stallman, may His Browser Be Wget and His Emacs Buffers All-Encompassing.)

What is GNU Radio Companion?

I am nowhere near qualified to talk authoritatively on this, so take everything with a grain of salt. Refer to the official website and documentation for more info.

GNU Radio is a Python/C++ library and toolkit, and GNU Radio Companion is a GUI (written in Qt) that lets you interact with GNU Radio in a very cool and intuitive way. Like, look at this:

When you hit the play button:

Hopefully that shows how intuitive it can be, with some context. There are some gotchas and confusing conventions, but we'll deal with those as they come.

I like this chall because there aren't any tricks, and you don't see radio stuff often in CTFs. It wasn't /difficult/ per se, but it was fun.

Failed Attempts

Enough bloviating, here's the graph they used to generate the samples:

Even without knowing what the blocks do (or what the words mean), we can make educated guesses, or at least loosely understand the processing flow. We see it repacks the bytes, passes it through a differential encoder, then a constellation encoder, repeats it 100 times, and adds in some Gaussian noise. My initial approach (that failed) was to reverse it like this (note that the QT GUI blocks are for interactivity/visualization and don't affect the data):

This outputs garbage (that vaguely looks like Lisp, lol):

$ cat key.txt
(B(4
@4((p
p
(((
(4(p4

I even threw in a squelch, thinking that the noise was messing it up. As always, the problem was a simple oversight (not deduplicating the signal from the repeat block). But past me didn't know that (there's no unrepeat block!), so the next reasonable step was to start from what I knew worked.

Rebuilding Process

Let's start with the simplest graph:

This must work, right? I put a fake flag (CTF{FAKEFLAG}) in mykey.txt for testing.

$ xxd deconstructedkey.txt
00000000: 0303 0000 0003 0101 0003 0301 0001       ..............

Ok... it doesn't work. Our first clue is to see that the output is the same number of bytes as our flag.

$ xxd mykey.txt
00000000: 4354 467b 4641 4b45 464c 4147 7d0a       CTF{FAKEFLAG}

So, we attempt to enlighten ourselves with the official documentation, which is decidedly not much help. But, this Wikipedia article and this blog post explain a lot about QPSK (quadrature phase shift keying-- which sounds like something from Star Trek. Fit for a space-themed CTF).

As I understand it, this magic block turns each byte into a point on a graph via the phase shift of the signal. Since it only encodes four possible locations with our configuration, that means we get two bits per byte (either 00, 01, 10, or 11). I'm not sure how GNU Radio is deciding which of my bits to execute, but the byte repacking makes a lot more sense now.

If we add those in, add a QT GUI Constellation Sink (you can search blocks by pressing the magnifying glass on top), and make the key repeating (so it doesn't end too quickly), we can see the points.

With the constellation sink looking like this. There's no noise, so each value is one of the same four points.

Cool beans, now we have something that works.

$ cat deconstructedkey.txt
CTF{FAKEFLAG}
CTF{FAKEFLAG}
CTF{FAKEFLAG}
CTF{FAKEFLAG}
CTF{FAKEFLAG}
CTF{FAKEFLAG} # (multiple times, since the source file is set to repeat)

After this, we can add in almost all other blocks, and they sort themselves out.

Isn't the noise an issue? Don't you have to build a polyphase clock sync block, a fractional resampler, compensate for inter symbol interference with a series of Nyquist RCC filters, then pass it into a Costas Loop?

See this guided tutorial for details on all that...

Our Cromulon overlords were kind today, and the signal was nice and clean. The constellation decoder didn't have any issues with the noise. I was worried about it, but it only resulted in a couple missed bytes (like in this part of the decoded stream, spoilers):

Alas, adding the final piece, the repeat block, makes our graph output gibberish. It's all at signs, 4s, and null bytes.

$ xxd deconstructedkey.txt | head
00000000: 4000 0000 0000 0000 0000 0000 0000 0000  @...............
00000010: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000020: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000030: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000040: 0000 0000 0000 0000 0000 00c0 0000 0000  ................
00000050: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000060: 0000 0000 4000 0000 0000 0000 0000 0000  ....@...........
00000070: 0000 0000 0000 0000 0000 0000 0040 0000  .............@..
00000080: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000090: 0000 0000 0000 4000 0000 0000 0000 0000  ......@.........

The official docs were more helpful for this one. It seems every value gets repeated however many times, not the entire coherent sequence (which is why I thought it would work without compensating for it). This makes sense in hindsight, since it's a kind of stream operation.

source

The block we're looking for here then is Keep 1 in N, not helpfully named Deduplicate or Unrepeat.

Solution

So yeah, it was just reversing the operations.

If we add a throttle (mine is the default samp_rate at 32k), we can see the data on the QT GUI Waterfall and Constellation sinks.

$ less deconstructedkey.txt

Flag: shctf{GnuRadio_And_Digital_Signal_Processing_And_Spacemath_Is_Fun_Right??}

If you have any questions or feedback, please email my public inbox at ~sourque/public-inbox@lists.sr.ht.