This was the only challenge remaining for us (ClevCode Rising) in the GITS 2015 Teaser CTF (http://ghostintheshellcode.com/2015-teaser/final_scores.txt), 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:
key.iq
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 key.iq file into a key.jpg file, that contains the flag. # # Joel Eriksson2014 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): gr.top_block.__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, "key.iq") 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( grc_blks2.packet_decoder( callback=lambda ok, payload: self.packet_decoder_1.recv_pkt(ok, payload), ), ) self.packet_decoder_0 = grc_blks2.packet_demod_b( grc_blks2.packet_decoder( 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() tb.start() sys.stdout.write("Running...\n") time.sleep(3) sys.stdout.write("Open key.jpg to see the flag. :)\n") tb.stop() tb.wait()
Or, this GNU Radio Companion file:
dontpanic.grc
Which yields this image, containing the flag! :)