Joel Eriksson
CEO/Founder of ClevCode. Vulnerability researcher, exploit developer and reverse-engineer. Previous CTO and co-founder of Bitsec, which was acquired by Nixu, and Cycura which was acquired by WELL Technologies. 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! :)