Joel Eriksson
Vulnerability researcher, exploit developer and reverse-engineer. Have spoken at BlackHat, DefCon and the RSA conference. CTF player. Puzzle solver (Cicada 3301, Boxen)

Ghost in The Shellcode 2015 Teaser: Don’t Panic! Shift Keying! Solution

This was the only challenge remaining for us (ClevCode Rising) in the GITS 2015 Teaser CTF (, after I had solved the Citadel challenge and my team mate Zelik had solved Lost in Time. With no previous GNU Radio experience, I tried my luck, and was able to come very close to solving this in time to win the entire CTF. Unfortunately I had reversed the output-bits from the deinterleave-block… Next time, I won’t do the same mistake. ;)

Since it was a pretty fun challenge, I took the time to fix up my GNU Radio Companion diagram after the challenge ended and I had been made aware of my mistake, and made a cleaned up and minimized Python solution script as well.

This was the information given in the challenge:

In a far away land, shaped like the head of a pwnie,
dem natives found a way to communicate in secret (sorta)
bearly advanced esoteric RF technol0gies...
I once befriended a bear in a bar on pwnie island.
He kept rambling on about Richard Stallman, and some treasure...
He handed me this napkin, and said we could speak through the ether
I captured this message data to a GNU Radio complex data file...
Maybe its a secret to the treasure!?!?

Demodulate the key

Along with this picture:

And this data file:

My final solution was this piece of Python code:

#!/usr/bin/env python
# Solution for 'Don't Panic! Shift Keying!' from the Ghost in the Shellcode 2015 teaser CTF.
# This script decodes the file into a key.jpg file, that contains the flag.
# Joel Eriksson  2014

from gnuradio import blocks, digital, gr
from grc_gnuradio import blks2 as grc_blks2

import time
import sys

class top_block(gr.top_block):

    def __init__(self):

        self.gfsk_demod = digital.gfsk_demod(samples_per_symbol=6)
        self.dpsk_demod = digital.dbpsk_demod(samples_per_symbol=8)
        self.blocks_divide_42 = blocks.multiply_const_vcc((1.0/42.0,))
        self.blocks_interleave = blocks.interleave(gr.sizeof_char)
        self.blocks_file_source = blocks.file_source(gr.sizeof_gr_complex, "")
        self.blocks_file_sink = blocks.file_sink(gr.sizeof_char, "key.jpg")
        self.blocks_endian_swap = blocks.endian_swap(8)
        self.blocks_deinterleave = blocks.deinterleave(gr.sizeof_gr_complex)
        self.packet_decoder_1 = grc_blks2.packet_demod_b(
                callback=lambda ok, payload: self.packet_decoder_1.recv_pkt(ok, payload),
        self.packet_decoder_0 = grc_blks2.packet_demod_b(
                callback=lambda ok, payload: self.packet_decoder_0.recv_pkt(ok, payload),

        self.connect((self.blocks_file_source, 0), (self.blocks_endian_swap, 0))
        self.connect((self.dpsk_demod, 0), (self.packet_decoder_0, 0))
        self.connect((self.gfsk_demod, 0), (self.packet_decoder_1, 0))
        self.connect((self.packet_decoder_1, 0), (self.blocks_interleave, 1))
        self.connect((self.blocks_interleave, 0), (self.blocks_file_sink, 0))
        self.connect((self.packet_decoder_0, 0), (self.blocks_interleave, 0))
        self.connect((self.blocks_endian_swap, 0), (self.blocks_divide_42, 0))
        self.connect((self.blocks_divide_42, 0), (self.blocks_deinterleave, 0))
        self.connect((self.blocks_deinterleave, 0), (self.gfsk_demod, 0))
        self.connect((self.blocks_deinterleave, 1), (self.dpsk_demod, 0))

if __name__ == '__main__':
    tb = top_block()
    sys.stdout.write("Open key.jpg to see the flag. :)\n")

Or, this GNU Radio Companion file:

Which yields this image, containing the flag! :)