SpeedHacking CTF at Hacktivity 2023 – Behind the Scenes

All posts


At this year’s Hacktivity conference we organized the SpeedHacking CTF competition. Now it’s time to tell you how the idea came together, what we did and why we did things the way we did, the technical challenges we had with the CTF itself, and, of course, the solutions to the challenges.

In my vocabulary, speed hacking is about two people (or teams) competing, where their screens are shared with the audience, and, to make things even more exciting, there are “sports commentators” to tell everyone what’s going on.

— Zoltan Balazs

How It Started

At the beginning of 2023, when the AI-hype train was already going at hyperspeed, I looked into how AI tools like OpenAI’s ChatGPT and GitHub’s Copilot could help me code. As I did not have a programming project at the time, I decided to write the Snake game. I had never coded a game before, so this seemed like a challenging (but reachable) goal. At that point, I didn’t have the CTF or any other goal in mind.

Screenshot of a February 13, 2023 headline that says: How will ChatGPT change the way we think and work? Stanford scholar examines. 
Also, the first sentence is shown in the screenshot: We need to think about the human aspect of using AI in our everyday lives and how it will influence the ways in which we perceive and interact with one another, says communication scholar Jeff Hancock.

I subscribed to both ChatGPT and Copilot and started coding in VScode. I chose Python because that was the language I had practiced recently.

The beginning with ChatGPT 4.0 was amazing. The skeleton game it created was awesome. ChatGPT introduced me to excellent Python modules like pygame. But, as soon as I started adding more ideas and functions to the game, ChatGPT fell apart. It started hallucinating variables, objects, functions, and methods that were never defined.

It was time to switch to Copilot.

And Copilot delivered. This made sense, as ChatGPT was never designed for programming. It is just a happy accident that it can help you code. Since Copilot is fine-tuned for just that, it does the job properly. I sometimes still found myself using ChatGPT rather than Copilot, but it was mostly for asking about problems that were not connected to the current code base.

image of an old nokia mobile phone running a game of Snake

And while I was coding Snake, I started thinking about hacking it or even intentionally putting vulnerabilities into the game. Around this time, I found the amazing pygbag Python module. With just a little bit of code modification, I could host the game on the web and run games in a browser. You can find some details on how this is done, but the two main keywords here are WebAssembly and CPython.

And this is how the idea for the CTF was born.

Back in 2019, I had organized a SpeedHacking CTF competition at Hacktivity, so I thought it would be nice to do a comeback this year and organize a CTF with these challenges. In my vocabulary, speed hacking is about two people (or teams) competing, where their screens are shared with the audience, and, to make things even more exciting, there are two “sports commentators” to tell everyone what’s going on. Fortunately, we had the privilege of current and former ZDI employees entertaining the audience during this year’s competition.

The Qualification Round

Since we needed to get two capable hackers for the finals, I also had to arrange a qualification round. What made things challenging was that the quals were hosted online, while the finals were hosted locally on my MacBook at the event. This meant that I had to set up two CTF infrastructures 🙂 I expected both the qualification round and the finals to be solvable in ~90 minutes and I am happy that my estimates were correct.

To solve the quals, you had to perform the following steps:

First, you had to find the QR code at the event. This redirected you to a YouTube rickroll video. If you paid attention, you could see that the QR code pointed to the actual CTF web server, which then redirected you to the video.

The root webpage had all the rules and a decoy challenge. It’s only purpose was to provide hints for finding the real challenge. The real challenge was hidden in the good old robots.txt. In the beginning, Cloudflare caches played a trick on us but, luckily, we resolved the issue.

screenshot showing a robots.txt rule that has a User-agent and link to the real challenge

Once you had the URL and used the special user-agent, you needed to buy a ticket for a different price, which was set by the server. This beginner challenge could be solved by modifying the page in the browser’s developer tools or changing the browser request in an intercepting proxy.

The next challenge was bypassing a custom authorization page. It was a bit tricky and not obvious even from reading the source code, but the solution was to change the order of the GET parameters.

a screenshot of the code used in the challenge

The next challenge involved a hidden login page with obfuscated JavaScript. One solution was to check the JS code and find that the key parts were not obfuscated. By creating proper local storage keys and modifying JS variables, it was possible to enable the login form. The other solution was to find out where the form was being decoded and simply dump the decoded format into the DOM via document.write or a similar method.

screenshot of the page's code showing a function with unobfuscated key parts

As we were looking at the server logs in real-time, we sometimes let the participants know whether they were on the right track on Slack. I have no idea how they could check Slack while hacking, but it looks like they are better at multitasking than I am.

The final challenge was to read the contents of the file called flag by using the login form. Clearly, this was an injection challenge, and we provided hints that the challenge uses Jinja. There also was another hint about a flash.

The solution was to use Server Side Template Injection (SSTI), but, for security reasons, only a few functions were allowed. Checking our favorite payload repository, it was easy to figure out that we must have used the function get_flashed_messages.

And this was the end of the quals! The flag contained a URL to a Google Forms form. What made things exciting was that the first three people finished solving the challenges in a 5-minute window. After announcing the winners, the second place withdrew from the finals.

The Finals

photo of the Hacktivity speedhacking CTF room with dozens of people looking at a large screen

As I’ve mentioned, we ran the finals at the conference. I am always afraid of CTF dependencies that I don’t control, so I put a significant effort into making everything available from the local network. Unfortunately, modern OSes and browsers can trick you.

The CTF setup used a valid Internet domain (speedhack.xyz), but it pointed to a local IP address (192.168.x.x). When the Internet is not available, modern browsers don’t even try to connect to the local IP, even if they can resolve the domain via a local DNS server. Through many hours of frustration, I learned about scutil --dns (thanks, GHost), that nslookup and netcat use different subsystems to resolve names, that I could put domains into the /etc/resolver directory, and about complex projects like https://github.com/Jamesits/alwaysonline.

But let’s get back to the finals. The entry point to the finals was a Workadventure level with a custom Christmas map.

screenshot of a Christmas Workadventure level on the left side and a black welcome page with green letters and a Matrix-inspired vertical code background for the CTF on the right side

What makes Workadventure amazing is that you can self-host it for free. But it is also a complex beast, as it starts with 13 containers. Fortunately, it wasn’t hard to start and leave it running.

My initial idea was to deeply integrate Workadventure into the CTF platform. Unfortunately, this plan failed due to the complexities in the maps, incompatibilities in the maps and editors, and my lack in design skills. In the end, the Workadventure platform was used only for providing hints, finding the entry URL to the real CTF platform, and hosting the first challenge.

The first challenge had hints that were provided randomly from a pool of answers, but if you checked the source code, you could find a hint that was impossible to get. From there, the challenges involved only the Python Snake game.

Photo of the CTF finalists staring intensely ant their laptops
The finalists, Balázs Bucsay from Mantra Information Security, and Özgün Kültekin from Trendyol Group

The goal of the first challenge was to reach a score higher than 4,294,967,000. The game had three types of food for the snake: one normal and two special ones. The first special food added bonus points, increased the snake’s speed and added new walls. The second special decreased the total points, decreased the snake’s speed, and removed some walls. The solution was to eat the second special food and cause an integer underflow in the game.

Screenshot of the snake game with a rainbow-colored snake and three types of food: green, pink, and red

The goal of the second challenge was to reach a high score of 1337. This was impossible by default, as the points were increased or decreased by 10. The solution was to use string injection in the high score page. As the game stored the high scores in a “nickname,score” format, one could trick the parser by submitting a nickname like CoolJoe,1337 .

screenshot of the Game over window with a score of 20. The nickname entered is zh4ck,1337

The goal of the third challenge was to re-enable the Python debug interface. By default, pygbag provides a debug interface to the games with a full Python console in the browser. I removed this functionality by commenting out some lines in the JavaScript code. The solution was to uncomment those lines of code. This can be a little tricky, as you have to modify the response from the webserver. Modifying it locally in the browser does not do the trick.

Photo of a macbook screen with developer tools open for the speedhacking CTF

The fourth challenge was to teleport the Snake into a box. Once you had access to the Python debug console, you could change anything you wanted, including the snake’s coordinates.

Photo of a laptop with the CTF Level 4  page open. The page has green text on a black background and the Matrix-inspired vertical code background under the text box

The final challenge was about getting the source code of the Snake game, reverse engineering it, figuring out how the communication is encrypted between the browser and the server, finding the encryption algorithm and keys, then forging a valid message “Hack The Planet” and sending it to the server.

During the game, Özgün was always ahead of Balázs by 2-5 minutes. But Balázs took the lead in the final round and finished the CTF right before Özgün!

It was a very challenging game in a very exotic platform and both hackers deserved the prize, but there could be only one winner.

Photo of the Hacktivity speedhacking CTF final with both finalists and the organizer. The winner holding a PS5 box, and the organizer is holding the microphone.

I would like to thank Marton Bak for helping brainstorm and test the challenges, Veres-Szentkirályi András from Hackerspace Budapest for video mixing, the commentators from ZDI, and the organizers of Hacktivity for the amazing event.

Group photo of Hactivity's organizers

Other posts by Zoltan Balazs

header image
IoT Labs
Cybersecurity Labs