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.
Setup
Open the challenge URL in your browser. Check /filter to see the current blocklist.
curl http://mercury.picoctf.net:<PORT_FROM_INSTANCE>/filterSolution
Walk me through it- Step 1Inspect the filterVisit /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>/filterLearn 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
ORblocked 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. - 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 theadminrow, or use another||for the password too. - Step 3Submit the bypass and read the flagPOST 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.