Web Gauntlet 2 picoCTF 2021 Solution

Published: April 2, 2026

Description

This website looks familiar... Log in as admin, and use the filter to find the flag. The filter is case sensitive.

Visit the /filter endpoint to see what words and characters are blocked.

Open the challenge URL in your browser. Check /filter to see the current blocklist.

bash
curl http://mercury.picoctf.net:<PORT_FROM_INSTANCE>/filter
  1. Step 1Inspect the filter
    Visit /filter to read the blocklist. Common entries: OR, AND, UNION, SELECT, WHERE, --. The filter is case-sensitive, so case-flipping or string concatenation are the obvious bypass routes.
    bash
    curl http://mercury.picoctf.net:<PORT_FROM_INSTANCE>/filter
    Learn more

    Assumed query. Web Gauntlet servers run a SQLite-backed login that builds the query by string interpolation, roughly:

    SELECT * FROM users WHERE username='${u}' AND password='${p}'

    With OR blocked you can't use the classic ' OR '1'='1. SQLite has another trick: the || operator concatenates strings, and it isn't a keyword. See SQL injection for CTF for the broader bypass library.

  2. Step 2Concatenate the username with ||
    SQLite's || joins two string literals: 'adm' || 'in' evaluates to 'admin'. The split keeps the literal word 'admin' out of your input and bypasses simple word filters.
    Learn more

    Operator precedence. || is the SQL string-concatenation operator (in SQLite, PostgreSQL, Oracle). It binds tighter than the comparison =, so:

    username='adm'||'in'   <==>   username = ('adm' || 'in')   <==>   username = 'admin'

    With this idiom you can build any string out of allowed substrings: 'a'||'d'||'m'||'i'||'n', or pull from a SELECT subquery. None of the joined fragments contain the blocked keywords.

    If quotes survive but -- is filtered. Submit the password as anything and rely on the password column being NULL for the admin row, or use another || for the password too.

  3. Step 3Submit the bypass and read the flag
    POST username=adm'||'in (and any password). On success the server renders the authenticated page with the flag.
    bash
    curl -X POST http://mercury.picoctf.net:<PORT_FROM_INSTANCE>/login \
      -d "username=adm'||'in&password=x"
    Learn more

    Lesson. Keyword blocklists are unfixable: there are too many ways to spell every reserved word, and SQL dialects have escape hatches like ||, CHAR(), and hex blob literals. Parameterized queries are the only correct mitigation.

Flag

picoCTF{...}

SQLite's || string concatenation operator splits a username across quote boundaries and bypasses word-based SQL injection filters. Parameterized queries are the only real defense.

Want more picoCTF 2021 writeups?

Useful tools for Web Exploitation

Related reading

What to try next