Skip to main content

Live Art picoCTF 2022 Solution

Exploit a vulnerability in a collaborative web app to trick the admin bot into leaking the flag.

Published: July 20, 2023Updated: August 13, 2026

Description

A collaborative pixel-art web app with an admin bot. This was one of the hardest web challenges of picoCTF 2022 (500 points) and went largely unsolved. No verified public solution is available, so the page below is an honest, clearly-labeled methodology for auditing this kind of admin-bot web app, not a confirmed step-by-step solve. Treat the endpoints and payloads as illustrative until verified against the real source.

Interact with the pixel-art app to understand the drawing mechanics.

Analyze the source code for CSRF protections, XSS sinks, or race conditions.

Set up an exfiltration listener and craft a malicious payload.

bash
# Open the challenge URL in your browser and inspect the page source
bash
curl -s http://saturn.picoctf.net:<PORT_FROM_INSTANCE>/ | grep -i csrf
bash
curl -s http://saturn.picoctf.net:<PORT_FROM_INSTANCE>/ | grep -i script

Solution

Want to try it yourself first?

The guided walkthrough reveals hints one step at a time.

Walk me through it
  1. Step 1Audit the app for vulnerabilities
    Observation
    The challenge is a collaborative pixel-art app with an admin bot that visits URLs. The attack surface is that bot's authenticated session, which narrows the audit to CSRF, stored XSS, and race conditions.
    Read the page source and JavaScript. Look for: missing CSRF tokens on state-changing requests, unsanitized innerHTML rendering of art titles or descriptions, or unprotected admin-only endpoints.
    Learn more

    CSRF (Cross-Site Request Forgery): if the app uses cookie-based authentication and doesn't validate a CSRF token, an attacker can create a page that makes requests on the victim's behalf. Example: an image tag or form submission that calls an admin action.

    XSS: if artwork names, descriptions, or chat messages are rendered without escaping, injecting a script payload will execute in the admin bot's browser when it views the art.

    Race condition: if there's a check-then-act pattern (e.g., check if pixel is owned, then write), two concurrent requests can both pass the check before either updates the state, allowing double writes or privilege escalation.

  2. Step 2Exploit the identified vulnerability
    Observation
    The bot visits attacker-supplied URLs with its privileged session cookie live. So craft a CSRF form, or a stored XSS payload, that fires at a real state-changing endpoint and performs admin actions on the bot's behalf.
    Craft a CSRF page (if CSRF) or inject a stored XSS payload (if XSS sink found) to execute actions as the admin bot.
    bash
    # NOTE: there is no known 'give_flag' endpoint - the form below is a GENERIC
    # CSRF template to adapt only after you confirm a real state-changing endpoint
    # and parameter names in the actual source. Do not assume these exist.
    cat > exploit.html << 'EOF'
    <form id='f' action='http://CHALLENGE_URL/REAL_ENDPOINT' method='POST'>
      <input name='REAL_PARAM' value='REAL_VALUE'>
    </form>
    <script>document.getElementById('f').submit()</script>
    EOF
    What didn't work first

    Tried: Submitting the exploit page URL to the admin bot before verifying a real state-changing endpoint exists.

    The CSRF template carries placeholder endpoint and parameter names. Submit it before reading the source and the bot visits the page, fires a POST at a route that does not exist, and returns a 404 with no visible effect. Confirm the real path and parameter names from the app's JavaScript or its network traffic first.

    Tried: Using a stored XSS payload with alert() to confirm injection rather than an exfiltration payload.

    alert() runs inside the bot's headless browser, which has no window you will ever see, so the popup fires into nothing. Exfiltrate instead: a fetch() or an image source pointing at a webhook listener gives you an out-of-band HTTP request that confirms execution and carries the cookie or flag data.

    Learn more

    For a CSRF attack: host the exploit page on a public server (or use webhook.site), then report that URL to the admin bot. When the bot visits your exploit page, the embedded form or fetch() request will fire against the challenge server, carrying the bot's session cookie automatically (same-origin cookies).

    CSRF defenses include: CSRF tokens (random values bound to the session), SameSite cookie attribute (SameSite=Strict or Lax prevents the cookie from being sent in cross-site requests), and checking the Origin header.

    For a race condition exploit: send many simultaneous requests (using asyncio, threading, or Burp Repeater's parallel send feature) to win the race between the check and the update.

  3. Step 3Collect the flag from the admin's response or session
    Observation
    Once the bot executes the crafted request, the flag has to surface somewhere reachable. Check the app's public state, an out-of-band webhook listener, or the admin panel, depending on whether the exploit elevates privileges or exfiltrates data.
    After the admin bot executes your action, the flag appears in the app's state, in a response, or is exfiltrated to your listener.
    Learn more

    After exploitation, check: the app's main page for newly visible content (the flag may appear publicly), your webhook listener for exfiltrated data, or the admin panel URL directly (if the admin action gave you elevated privileges).

    Real-world collaborative apps (Figma, Miro, Notion) have extensive security reviews precisely because user-generated content is rendered to other users. Content security policies, DOMPurify sanitization, and strict CSRF protections are standard defenses. This challenge illustrates what happens without them.

Flag

Reveal flag

picoCTF{...}

Hard, largely-unsolved 500pt web challenge with no verified public solution. The steps are an honest auditing methodology (CSRF / stored XSS / race condition on the pixel logic), not a confirmed solve; there is no known give_flag endpoint, so adapt only to real endpoints found in the source.

Key takeaway

Admin-bot challenges combine two bug classes: a stored injection point the attacker controls, and a privileged browser session that visits attacker-supplied content. The bot becomes a proxy, issuing requests with its elevated cookies against the same origin, which is why SameSite cookie policy and Content Security Policy are the primary defenses. The same threat model drives real phishing, where an authenticated employee clicks a link that acts on their behalf inside a corporate application.

Related reading

Useful tools for Web Exploitation

Where to go next