Since I was on the winning team during last month's SecDSM, I was charged with designing the July challenge.
1st place miniCTF winners! pic.twitter.com/vSz7uUBFYp— SecDSM (@SecDSM) June 22, 2018
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.
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!
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 DECIMAL HEXADECIMAL DESCRIPTION ----------------------------------------------------------- 0 0x0 PNG image, 1090 x 182, 8-bit /color RGBA, non-interlaced 3278 0xCCE Unix path: /www.w3.org/1999 /02/22-rdf-syntax-ns#"> 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.
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 decode.fr 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.
#!/bin/python text =  with open('somefile') as f: for line in f: line = line.rstrip().split(' ') for word in line: text.append(word) for i in range(len(text)): print("[" + str(i) + "]: " + text[i])
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.
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.