The Challenge
A search endpoint runs user input through a SQL query. A keyword blacklist strips commonly known SQL injection strings before the query executes. SELECT, FROM, WHERE, UNION and their variants are filtered.
Approach
If the WAF removes the literal string OFFSET from the input before passing it to the database, injecting OFFSET inside a forbidden keyword exploits that removal to reconstruct the original keyword:
|
|
The sanitiser runs once, the resulting string goes directly to the database without re-checking.
Solution
|
|
inject() splits every reserved keyword at the third character and inserts OFFSET — the WAF removes the literal OFFSET substring from the output and the original keyword is reassembled. Three queries: enumerate tables → enumerate columns → dump flag.
What I Learned
Input sanitisation via substring stripping is fragile. Filters must be applied in a loop until no change occurs (idempotent), or ideally replaced with parameterised queries entirely. Injecting the filter’s own removal target inside the forbidden string is a classic bypass demonstrated in almost every SQLi filter challenge.