..

google25 - メガ

Overview

  • CTF: GoogleCTF 2025
  • Challenge name: メガ
  • Author: ?
  • Category: misc
  • Difficulty: easy
  • ctf files: zip archive

Challenge description

Join the 16-bit revolution! Can you help Sonk the Rabbit find all flags? Submit your recording to get the flag: python3 submit.py solution.inp mega.2025.ctfcompetition.com 1337 Note: Submit the flag starting with “CTF{A:” here. For submitting the other flag, see the challenge titled “メガB”.

Recon

% la misc-mega-rust-1
0755 drwxr-xr-x 601k tom tom 30 Jun 18:33 game
0755 drwxr-xr-x  84k tom tom 30 Jun 18:33 libs
0755 drwxr-xr-x 3.4k tom tom 30 Jun 18:33 rom
0755 drwxr-xr-x  18k tom tom 30 Jun 18:33 toolchain
0644 .rw-r--r--   91 tom tom 31 Dec  1979 .gitignore
0644 .rw-r--r-- 5.3k tom tom 31 Dec  1979 Cargo.lock
0644 .rw-r--r--  173 tom tom 31 Dec  1979 Cargo.toml
0644 .rw-r--r--  623 tom tom 31 Dec  1979 Makefile
0644 .rw-r--r--  846 tom tom 31 Dec  1979 megadrive.x
0644 .rw-r--r-- 2.2k tom tom 31 Dec  1979 pow.py
0644 .rw-r--r--  840 tom tom 31 Dec  1979 README.md
0644 .rw-r--r--   64 tom tom 31 Dec  1979 rustfmt.toml
0644 .rw-r--r--  17M tom tom 31 Dec  1979 sonk.md
0644 .rw-r--r-- 1.1k tom tom 31 Dec  1979 submit.py

Trying to cat sonk.md crashed my terminal as it’s not a markdown file, but a Sega Mega Drive / Genesis ROM image.

From README.md:

  • run the game with: mame genesis -cart sonk.md
  • record solution with: mame genesis -cart sonk.md -record solution.inp
  • send solution to server with: python3 submit.py /home/user/.mame/inp/solution.inp mega.2025.ctfcompetition.com 1337
  • rebuild the game with: make sonk.md

Game

After starting the game we are greeted with this screen.

first-start

We can control the rabbit (whose name is sonk apparently) with the LEFT, RIGHT and UP arrow keys. Going through the level we find two flags. One on top of a tree (out of range for us)

location-flag-b

and one in a a spike cage.

location-flag-a

When touching the spikes or the wasp, the rabbit is knocked back and can’t move until he touches ground again. Landing on another spike or another wasp when airborne already, gives the rabbit another push back. This continues until he doesn’t land on a spike or wasp.

ouch

Source code

% tree game/src
game/src
├── anim.rs
├── flag.rs
├── game.rs
├── lib.rs
├── map_data.rs
├── map.rs
├── palettes.rs
├── physics.rs
├── sonk.rs
├── spike.rs
├── tiles.rs
└── wasp.rs

The game is written in rust. As someone who never tried programming in rust, I think the code is pretty readable, but …

SPOILER ALERT

… we don’t need to understand the code to get the flags.

Flag B

I did the second flag first as it is the first flag that you encounter in the level (for whatever reason). When fooling around a bit I noticed that it is possible to spawn multiple wasps by moving the (right) frame border.

flag-b-multiple-bees

Apparently the wasps spawn when the frame border is pushed beyond this point.

Then I found out that slowly approaching this border generates a “big wasp”. It’s really just a few wasps stacked on top of each other.

When repeating this a few times the game glitches out (probably because there are too many entities on screen) and the rabbit teleports into the sky.

flag-b-glitch

After walking around in the sky for a bit, I got the flag.

Then I had to record the inputs of a run that got the flag in under 300 seconds and send it to the server with the provided python script.

Flag: CTF{B:1v3_CoM3_T0_m4k3_An_aNn0unC3mEn7}

Flag A

This flag took me a bit longer, because I was locked in to the first idea that came to my mind. Looking at the cage I thought that the spikes were a bit too far apart and that it could be possible to glitch through the little gap.

cage-hitboxes

That however was a big waste of time.

After spending hours on this idea, I noticed that the frame border doesn’t update when the rabbit is hit by a spike or a wasp. So it is possible for the rabbit to be out-of-bounds. Then it clicked. Entities (spikes and wasps) are only spawned when they are in the current frame. So the spike cage doesn’t exist when the player is knocked out-of-bounds, which means that he should land directly on the flag.

Flag: CTF{A:g0Tt4gOF4stGO7TAg0f45tg07TAGoFA5T}

Extra: TAS

After completing the challenges I thought that the 300 second solution recording maximum is way too high, so I did a Tool Assisted Speedrun for the game with bizhawk’s TAStudio.

Flag A

My TAS for the first flag needs 795 frames until the You got flag A! string is shown on the screen, which is exactly 15.9 seconds at 50 FPS.

Flag B

This run is slightly slower with 877 frames (17.54 seconds) until the You got flag B! string is shown, but I’m pretty sure that there are still some big time saves as the flag collection itself is kind of random.