Recently a colleague of mine made me aware of the Snyk CTF competition that is happening in November. It is a set of challenges where you have to find a vulnerability and exploit it to reveal a unique Id (flag) which you can validate to get progress your team up the leaderboard. We decided it would be fun to take part, and so I began looking at the challenges Snyk set last year in order to prepare. I will write a separate post on the experiences of this years CTF challenge but this post goes into the fun I had solving one of last years challenges.
I decided to throw myself in the deep end and go for one of the challenges that hadn’t been solved. Other challenges already had blog post solution and I didn’t want to have a way out if I got stuck. The challenge was called ‘Disco Dancer’ and it consisted of an image and the description ‘Ooh, I just wanna move! I’m feeling so antsy!’. Typically the description is meant to contain clues to how to solve the challenge. I read this over and over trying to click with something in my brain. With nothing concrete I decided to analyse the image for ideas.
The first thing that came to mind was QR code. Do I need to somehow translate the pixels to just black and white to generate a QR code containing the flag. I counted the width and height and it was 33 x 33 pixels. A quick Google revealed that this matches the size of Version 4 of the QR code specification. I generated a QR code with a fake Snyk flag and low and behold it generated a version 4 QR code as that is the most appropriate size for this amount of text. That can’t be a coincidence right? This has to be a QR code!
My other initial observations were that there are a lot of different colours used and all greys (except for the centre pixel of course). Next I decided to check the RGB colour values for a few pixels to see if that revealed anything interesting. All pixels had an equal value for the R, G and B values. This seemed relevant. I looked up the ASCII value for curly braces as the flag would need these.
} = 125
This would need to be a light grey pixel. I check a whole bunch of the ones that looked the brightest and the highest number I could find was 122 (z). I dismissed that the flag was just hidden in a specific set of pixels.
The wrong path
I revisited the challenge description now I had some information from the image. The word that jumped out at me was ‘move’. It felt like the green pixel was a starting point and that somehow we would need to move around the image. Still convinced on the end game being a QR code I refreshed my memory on how QR codes are constructed to see if any connections could be made.
I started by setting all the mandatory black and white pixels to create a starting point. Then looked at the pixels in the bottom right corner as this would be the start of the flag. i.e. section D1 should be the binary notation for ‘S’ (01010011).
I played with trying to convert the RGB numbers down to binary.
- Odd v Even – didn’t work
- Higher v Lower – didn’t work
- First digit of the RGB value as binary – didn’t work
- Last digit of the RGB value as binary – didn’t work
I was stuck. Nothing was matching up with the idea of this being a QR code. I had a nights sleep and the next morning I decided to go back and look at all the observations I had made.
- colour pixels all have equal RGB values
- green centre pixel – why?
- description keywords: ‘move’ ‘antsy’
- image is QR code sized
I asked myself one question, ‘what if its not a QR code?’
It turned out that this was the breakthrough I needed. What should I try if I don’t treat this as a QR code? I was convinced that ‘move’ was a clue and that the green pixel was the starting place. Then I thought about the word ‘antsy’. It’s an unusual word, very deliberate. Saying it over and over again I realised. ‘ANCI’. This was the confirmation I needed that the colours related to the ANSI Character Set (ASCII). I started translating the pixels that surround the centre pixel.
Mostly garbage characters, but one was an ‘S’. Quickly I checked the pixel to the right of the ‘S’. It was an ‘N’! Quickly I translated the next few and sure enough I found the open curly brace that I thought didn’t exist.
I knew I was well on my way to solving this challenge. I kept going until I got a character that would not be present in a hexadecimal string. At that point I checked all surrounding pixels and found multiple possible routes. I kept following the valid hexadecimal characters.
Eventually, I hit the closing curly brace and I knew I had found my flag.
All that was left was to submit the flag and watch the challenge turn green.
This is a perfect example of being blinded by an assumption. For so long I was convinced this would turn out to be a QR code. If I had just looked a bit harder near the start when looking for the light grey curly braces pixels I would have found them and almost instantly would have solved the challenge. I have no doubt that the Snyky people at Snyk deliberately made the image the right size to send us down the wrong path.
I’m sure the upcoming CTF challenge will be difficult. There is a 6 hour time limit so going down the wrong path is not an option. Solving this challenge gave me the little boost I needed to feel like I have a chance of getting one right, but time will tell!