Since I was on the winning team during last month's SecDSM, I was charged with designing the July challenge.

This was my first time writing a CTF question, so here's a write up about what I did and why. I was a bit self conscious about writing a challenge (normal anxiety and imposter syndrome type stuff) and I was concerned that people would find my challenge to be too easy and solve it within 30 minutes. It took about 1.5 hours before our first solve and people who had never attempted a miniCTF at SecDSM gave it a shot.

Note about Imposter Syndrome: We all get it or have had it at one point or another. You're doing great. We're all just winging it, I promise. The best way to fight it is to just do the thing.

I wanted to create a challenge that would approachable, but still require some time and thought. This led me immediately to a crypto-style challenge because they don't require a broad range of technical acumen, just some determination and creativity. I knew right away that I wanted to use the Pigpen cipher, Baconian cipher, and something to throw people off just a bit.

So let's dive into the challnge. You can follow along by downloading the beginning image from the SecDSM July MiniCTF site.

Image Inception

The challenge begins with an image and some instructions:

Welcome to the July 2018 MiniCTF

Let's flex that crypto muscle. Challenge: First person to tweet the picture of the famous artwork wins. Note - All passwords are lowercase without spaces

Good luck!

Pigpen Cipher


We start with a simple pigpen cipher. Visit the pigpen Wikipedia page to learn how it works, but for simplicity here's the key.

Decoding the cipher leaves us with who knows why the caged bird sings. Many people thought this was the end of the challenge and I told them to take a deeper look. Try doing a binwalk on the file.

$ binwalk secdsm_july.png 

0             0x0             PNG image, 1090 x 182, 8-bit
/color RGBA, non-interlaced
3278          0xCCE           Unix path: /
21588         0x5454          Zip archive data, at least 
v1.0 to extract, name: secret_0/
21655         0x5497          Zip archive data, encrypted 
at least v2.0 to extract, compressed size: 413, uncompressed 
size: 1025, name: secret_0/cagedbird.txt
22164         0x5694          Zip archive data, encrypted 
at least v1.0 to extract, compressed size: 29, uncompressed 
size: 17, name: secret_0/fragment
22284         0x570C          Zip archive data, encrypted 
at least v2.0 to extract, compressed size: 45176, 
uncompressed size: 50584, name: secret_0/secdsm_july_0.png
67560         0x107E8         Zip archive data, encrypted 
at least v2.0 to extract, compressed size: 109399, 
uncompressed size: 132844, name: secret_0/secdsm_july_1.png
177509        0x2B565         End of Zip archive

You'll notice there's a zip file in the picture with 3 itmes in it, cagedbird.txt, fragment, secdsm_july_0.png, and secdsm_july_1.png. However, if you try to simply unzip the image you'll be prompted for a password. This brings us back to the decoded Pigpen cipher.

It is a reference to Maya Angelou's autobiography, I Know Why The Caged Bird Sings and by answering the question we get our first password 'mayaangelou'.

Note: Windows users, I was able to get things unzipped using the 7z file explorer

Unzipping the files gives us the following to png files, we'll come back to the text files in a moment. If you do a binwalk on both files, you'll notice they're both zip files too.


This one really stumped a couple of people. My hint was "It's something you see everyday, but probably don't realize it." If you guessed Braille, then you're right. My hope was that people would go to the Braille Wikipedia site and learn about how Braille works. If you did so, you'll find out that there are formatting markers in Braille that indicate what the next character is. So that "upside down L" tells us that the next character is a number and that lone dot on the lost row in the column on the right tells us that the next character is a capital letter.

Note: Lately I've noticed that we don't take enough time to understand the experiences that we don't necessarily have to have. I wanted to expose people to something they, otherwise, might ignore. Hopefully people left feeling like they learned just a little bit about Braille.

This decodes to hex, 4B 27 0F 0A 88 10 05 9D 10 43 B4 19 57. For many the first instinct is to decode to ASCII, but that spits out gibberish. This is because that hex decodes to decimal.


It can be a little difficult to find a decoder that can do a full string of hex all at once, so if you're looking for one check out this one on Rapid Tables.

Save that string of Decimal text somewhere, we'll need it in a moment.

Bacon's Cipher


At first glance this probably looks like a ransom note, but if you isolate those letters they don't spell anything. In a CTF, sometimes the text on the image matters. If you Google 'Francis Bacon cipher', you might find out that along with being a philospher and having some weird drama about secretly being Shakespere, he's the creator of the Bacon's Cipher. Bacon's Cipher is less cipher and more steganography. It involves hiding a message in text by converting a message to a series of A's and B's, matching that up to the source text and changing the font of a letter that indicates either an A or a B. Binary can also be substituted for this.

Note: I chose the Bacon Cipher because I find it interesting that so many philosophers spent time having d**k measuring contests by sending ciphers to one another to try to crack. I chose Bacon specifically because of his contributions to science and the interesting conspiracy theory surrounding Shakespeare.

Decoding the text leads to ABAAA BAABA BAAAB ABAAA ABBAA AABBA BAAAB ABBAB AABAB AABAB BAAAA AABAA AABAA AAABB ABBAB ABABB and if you throw that into the Bacon Cipher decoder on then you get itsingsoffreedom. You can use that to unzip the Bacon Cipher image. Unzipping the image gives you another fragment and a python script.


text = []
with open('somefile') as f:
	for line in f:
		line = line.rstrip().split(' ')
		for word in line:
for i in range(len(text)):
	print("[" + str(i) + "]: " + text[i])

Book Cipher

We have a python script that takes in a file and prints out a numbered list of every word in the file. We also have a list of numbers (the string of decimals from the Braille). Remember the cagedbird.txt file from earlier? It is a formatted version of Maya Angelou's Caged Bird poem. I created a book cipher using the poem.

A free bird leaps
on the back of the wind   
and floats downstream   
till the current ends
and dips his wing
in the orange sun rays
and dares to claim the sky.
But a bird that stalks
down his narrow cage
can seldom see through
his bars of rage
his wings are clipped and   
his feet are tied
so he opens his throat to sing.
The caged bird sings   
with a fearful trill   
of things unknown   
but longed for still   
and his tune is heard   
on the distant hill   
for the caged bird   
sings of freedom.
The free bird thinks of another breeze
and the trade winds soft through the sighing trees
and the fat worms waiting on a dawn bright lawn
and he names the sky his own
But a caged bird stands on the grave of dreams   
his shadow shouts on a nightmare scream   
his wings are clipped and his feet are tied   
so he opens his throat to sing.
The caged bird sings   
with a fearful trill   
of things unknown   
but longed for still   
and his tune is heard   
on the distant hill   
for the caged bird   
sings of freedom.

If you replace 'somefile' with 'cagedbird.txt', you get a numbered list of every word in the file. For this book cipher, you used the first letter of the words that the decimal matched to get the final password. You can modify the script a little bit to get the words you need. The final password, uncagedbird, can be used to unzip the Braille image for the final fragment.

The Fragment Files

Fragment from pigpen image

Fragment from Bacon image

Fragment from Braille image

Note: Some times people will try to decode partial text to get hints about what the full text is. Turns out you needed the last fragment to be able to decode that whole thing. This was a happy accident.

Your mission is the figure out the correct way to arrange the fragments to get decoded text. I used Base32 to encode the text. The Base32 decodes to The Protector of Home and Family

*Note: This is one of my favorite poems and Maya Angelou is one of my favorite black woman celebrities and I really wanted to expose other people to just a piece of who she was, even if it was just for a CTF challenge.

The Winner?

Revisiting the instructions.
Challenge: First person to tweet the picture of the famous artwork wins.
As you'll notice in the above tweet, one person solved my challenge but only tweeting the name of the artwork and the name was off by a word. Meanwhile, someone else saw this and tweeted the actual picture of the artwork; thus he was crownded the winner. Since I created the challenge, I had final say. The person who tweeted the image has never had the opportunity to write a challenge while the other person has. I wanted to give someone new an opportunity to try it out. I also have an appreciation for the social engineering aspect of what happened. So I crowned the guy who tweeted the image first the winner even though he wasn't the first to solve everything within the challenge.

I had a lot of fun writing this challenge and next time I hope to try something a bit different while retaining the approachability.