SKIP TO MAIN CONTENT

[ WRITEUP NODE / FIELD REPORTS ]

SOLVED CHALLENGES & FIELD ANALYSIS

SECURITY RESEARCH KNOWLEDGE TECHNIQUES
B3S/WRITEUPS/CYBERGAMES-KENYA-2026-FLAPPY-WRITEUP
← BACK TO ARCHIVE
EVENT: CyberGames Kenya 2026CATEGORY: WebPOINTS: 500 PTS

Cybergames Kenya 2026 - Flappy Writeup

AUTHORED BY:@bealthguy8/15/2026

CTF Write-up: Flappy

Challenge Information

1. Initial Discovery

Upon visiting the challenge URL, we are presented with a Flappy Bird game clone. The page title is "Flappy Bird (Rust/WASM)", indicating it's built using Rust and WebAssembly.

Inspecting the HTML source reveals a hidden div with the ID score-sync, which contains a "Sign in" form styled like Google's login page. There is also a suggestive comment in the HTML:

<!-- TODO: remove before production flag{n0t_th3_r34l_fl4g_l0l} class="hljs-keyword">-->

The game's logic is loaded via a WebAssembly module:

class="hljs-keyword"><script type="module">
    import init from './pkg/flappy_wasm.js';
    (async()=>{await init()})();
class="hljs-keyword"></script>

2. Analyzing the Sign-in Process

By manually showing the hidden modal and attempting to sign in, we can observe the network traffic. We used a Playwright script to automate this:

# Snippet of the interception logic
page.evaluate(class="hljs-string">"document.getElementById(class="hljs-string">&#039;score-sync&#039;).style.display = class="hljs-string">&#039;flex&#039;;")
page.fill(class="hljs-string">"#sc-email", class="hljs-string">"test@example.com")
page.fill(class="hljs-string">"#sc-pass", class="hljs-string">"password123")
page.click(class="hljs-string">".sc-btn")

The sign-in attempt triggers a POST request to http://exp.cybergame.sk:7010/api/v1/oauth/token with the following JSON payload:

{
  "grant_type": "authorization_code",
  "code": "Jy5eNwU3LBoUQBkXcQAdXl5DD0QaQwMBOwVAAA==",
  "client_id": "894271536842-k3jhf9x2v7m1n5p4q6r0s8t.apps.googleusercontent.com",
  "redirect_uri": "http://exp.cybergame.sk:7010/callback",
  "ua": "Mozilla/5.0 (X11; Linux x86_64) ...",
  "res": "1280x720",
  "ts": 1775226704008
}

3. Reverse-Engineering the code Parameter

The code parameter appears to be a base64-encoded string that changes based on the input email. Given the nature of CTF challenges, this is a common pattern for client-side XOR encryption.

If the code is generated by email ^ flag, we can retrieve the flag by calculating code ^ email.

4. Extracting the Flag

We wrote a script to submit a long email address and perform the XOR operation on the resulting code.

import base64
import json

def xor_bytes(b1, b2):
    return bytes(a ^ b for a, b in zip(b1, b2))

# ... after capturing the code ...
decoded = base64.b64decode(code_b64)
email_bytes = email.encode()
flag_bytes = xor_bytes(decoded, email_bytes)
print(fclass="hljs-string">"Flag: {flag_bytes.decode(class="hljs-string">&#039;utf-8&#039;, errors=class="hljs-string">&#039;ignore&#039;)}")

Using the email a_very_very_long_email_longer_@cybergame.sk, we successfully extracted the flag.

5. Final Flag

SK-CERT{y0ur_cr3d3n7i4ls_4r3_fl4pping_4w4y}

Conclusion

The challenge demonstrates the danger of performing "encryption" or data obfuscation on the client side with static keys. By intercepting the request and controlling the input plaintext (the email), the secret XOR key (the flag) was easily recovered.