Winner's writeup for CodeMash CTF 2020

Austin Schertz won the CodeMash CTF this year, and he dropped off his answers to all 19 challenges.  Here they are:


Access Control

We got the password dump (400)

                This challenge provided a set of passwords. I recognized that they were hashes and used an online tool to look up the hash values and put them in the correct format. (cm20-XXXX-XXXX-XXXX in this case)

Binary Analysis

 Need more coffee!!! (100)

                The file had no extension, so I used an online file checker to identify it as a java.class file. From there, I renamed the file with the proper extension and ran it from the command line.

 Need even MOAR coffee!!!!! (300)

                This one was a bit more confusing. Renaming it (first to .class and then to cm.class) and running it produced a cryptic error about a missing class. Decompiling revealed some very obfuscated java code. Ultimately, someone suggested that I run the file, and look more closely at the errors. The error suggested that I needed to create another class that would be referenced by the original file. After creating a separate class, I was then informed by the errors that an interface was expected. Changed to an interface, and found that I needed to add an annotation, and then that the annotation needed to be a runtime annotation. Running it this way produced the flag. 

 One Time at Band Camp (300)

                This one provided an AmericanPie audio file. I googled ways to hide text in an audio file, and I came across a few articles about audio steganography that referenced using sonic visualizer and applying a spectrogram. I did that and found the flag around the 6 minute mark. It looked a little off, but I substituted cm20 for what looked like cy20, and it worked just fine.

I C What You Did There (400)

                I got some help on this one from an older and wiser friend of mine. I had tried several ways to look at the audio file, but he listened to the file and immediately recognized it as the sound of a Commodore 64 file. Once I knew it was a C64 file I downloaded a converter to go from WAV to TAP. I ran the tap file in an online C64 emulator.

Binary Deserialization

The button doesn't do what you want (300)

                I was super over thinking this one. I tried all kinds of JSON stuff to no avail. In the “thislooksinteresting” element, I decoded the value from Base64 and saw <GiveMeFlag> I tried lots of complicated things, but the ticket was changing the “n” to a “y”. I did it by looking up the base 64 value for “n” and replacing it with the base64 value for “y” in chrome dev tools. After that, it was as easy as pushing the button.


All your base are belong to us! (100)

                The string was base64. Decoding produces the flag.

These soundex exactly the same! (100)

                I used the government soundex page to understand what soundex was. All three of the statements in the hint have the same soundex translation. Appending cm20 and putting dashes in the right locations produced the flag.

All your base are belong to us - level 2 (300)

                The string was base 64. Decoding it produced what appeared to be a PNG file. I copied it to a blank file and opened the image. There was the flag.

All your base are belong to us - level 3 (500)

                This one was base 64, but with a twist. A close look revealed the word “fish” at the end of the file. Removing that allowed for base 64 decoding, but the result was still base 64, and there was another instance of “fish” at the end. I wrote some C# to remove fish and decode from base 64 in a loop. Doing this 42 times produced the flag.


Where's the bacon? (100)

                This one was a bacon cipher. I used a tool called dcode to reveal the flag.

What is missing? (200)

                I recognized another bacon cipher hiding in the bold and italics tags. I manually copied the tags in order to notepad, and fed the result to dcode to produce the flag.

Incident Response

Ghost In The Keys (400)

                I opened the file in wireshark, and saw the leftover transfer data. I looked at some articles about how to recognize keyboard data in wireshark, and how to setup custom columns. When I had gotten the data that I wanted, I dumped the results to excel and manipulated them converting the leftover data to keystrokes, noting that the 02’s are shifts, and the other data was keypresses. Ultimately this created a powershell execution with a reference to a web page in it. Accessing the web page produced the flag.


Why did you do this to us, iOS? (200)

                I looked up how to open the file, and found that I could rename it and unzip it. After I unzipped it, I found a flag element in the plist file. It was a bunch of numbers, and I manually translated those numbers to other characters. This produced the flag.

On Site Challenges

You're gonna need a broom (1000)

The reference to the scytale was apt. I found a strip of paper attached to the wall in the game room, and a broom up against the wall. I wrapped the paper around the broom, and read off the numbers. I recognized the Hex code (no letters from late in the alphabet.) Plugging it into a hex converter, I found that the section I read off was only “cm20”. So I went back over, got the broom and read off the other sides of it and converted the hex to get the rest of the flag.

Social Engineering

Slack Challenge (100)

                Searching for cm20 in the capture the flag slack channel produced the flag.


                I did this the hard way. . . I was not sure that I could get someone to loan me their badge to tinker with, so I went and got the source from bill’s github, and found a file that contained an array that would eventually become a bitmap. So I grabbed the array, manipulated it, loaded it to excel, and used conditional formatting to make a QR code in a spreadsheet. Scanning it with my phone produced the flag.

Web Security

Leprechaun Rally (200)

                This one was clever. I attempted to speed up the calling process to get more coins, but I got throttled. At that point I understood the hint. You need to BECOME the leprechaun with the most coins. So I set my efforts to obtaining a fraudulent session. I realized that clicking the “stay logged in” button, there was another cookie added to all the requests. It was URL encoded, and base64 encoded, but ultimately it was just “[Username]_ThisIsBadSalt”.  I created a new cookie value for the user Lucky_McPlucky, and edited my cookie in chrome dev tools. This allowed me to become the luckyiest leprechaun and retrieve the flag.

Philosopher's Stone (300)

                I spent a decent amount of time looking at the page source for this one before getting a tip that I needed to look closely at the image. I messed with the image in luna pic, and found a message in the bottom right corner of the image. Entering that led to another cryptic message. I thought it might be base 64, but discovered eventually that it was chess notation. After significant manipulation to the string, I entered it to This loaded the match, but I am no good at chess. It took running it as an AI to realize that white’s next move was a checkmate. I spent a while trying permutations of that move in chess notation in the solution bar. I found one that worked! But then I found another challenge was waiting for me. It looked like a flag, but it wasn’t. I looked at the page source and found a bunch of hidden whitespace characters in the middle of the flag string. Removing them didn’t work, so I thought maybe the whitespace was the flag? I pulled out the whitespace pattern and realized that it was morse code. The decoded morse was added to cm20{XXXXXX} to get the flag.

Comments (1) -

  • Jack Gould
    FYI, on  THE BADGE CHALLENGE, another way to get the QR code is to use an HTML5 canvas to render the bitmap:

    <!DOCTYPE html>

    <canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;"></canvas>

    // Convert hex to 0 or 1
    var mypicture = [
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ...
    var c = document.getElementById("myCanvas");
    var ctx = c.getContext("2d");
    var imgData = ctx.createImageData(100, 100);

    var i;
    for (i = 0; i <; i += 4) {[i+0] = mypicture[i/4]*255;[i+1] = mypicture[i/4]*255;[i+2] = mypicture[i/4]*255;[i+3] = 255;

    ctx.putImageData(imgData, 10, 10);

Comments are closed