Skip to main content

Injection Points

While most SQLi occurs in WHERE clauses, vulnerabilities can appear anywhere in a query:

Attack Types

  • Retrieving hidden data — modify a query to return additional results
  • Subverting application logic — alter query behavior to bypass checks
  • UNION attacks — pull data from other tables
  • Blind SQLi — exploit queries whose results aren’t directly returned

Example: Retrieving Hidden Data

Original request and query:
Attack 1 — comment out the rest:
Attack 2 — return all rows:
OR 1=1 makes the WHERE clause always true; -- discards the trailing conditions. Result: all products returned, including unreleased ones.

Subverting Application Logic

A typical login query:
By submitting administrator'-- as the username (with a blank password), the query becomes:
-- comments out the password check entirely, so the attacker logs in as administrator with no password required.

Retrieving Data from Other Tables

Using the UNION keyword, an attacker can append a second SELECT to an existing query and pull data from entirely different tables. Original query:
Injecting ' UNION SELECT username, password FROM users-- produces:
The response now includes all usernames and passwords alongside the normal product results.

Blind SQL Injection

With blind SQLi, the application doesn’t return query results or error details — but the vulnerability can still be exploited. Techniques include:
  • Boolean-based — inject a condition that changes the app’s response depending on whether it’s true or false (e.g. injecting into Boolean logic or triggering a divide-by-zero error)
  • Time-based — conditionally trigger a time delay; infer truth from how long the app takes to respond
  • Out-of-band (OAST) — trigger an external network interaction (e.g. a DNS lookup to a domain you control) to exfiltrate data directly; useful when other techniques fail

Second-Order SQL Injection

First-order SQLi is straightforward — user input from an HTTP request is immediately incorporated into a SQL query unsafely. Second-order (aka stored) SQLi is more subtle: the application stores the user input safely at first, but later retrieves it and incorporates it into a query unsafely. The vulnerability isn’t at the point of storage — it triggers on a completely different HTTP request down the line. Second-order SQL injection diagram

Examining the Database

SQL behaves differently across platforms — techniques that work on MySQL may not work on Oracle. Key differences include syntax for string concatenation, comments, batched queries, platform-specific APIs, and error messages. Once a vulnerability is confirmed, fingerprinting the database helps tailor the attack. Two useful starting points: Version detection (result reveals DB type):
List all tables:

SQL Injection in Different Contexts

SQLi isn’t limited to query strings — any input processed as SQL is a potential vector, including JSON and XML bodies. These formats can also help bypass WAFs: filters that block keywords like SELECT can often be evaded by encoding or escaping characters. For example, encoding the S in SELECT as an XML escape sequence:
The server decodes S back to S before passing it to the SQL interpreter — bypassing the filter while executing normally.

How to Prevent SQL Injection

The fix for most SQLi is parameterized queries (aka prepared statements) — never concatenate user input directly into a query. Vulnerable:
Safe:
Parameterized queries work for WHERE, INSERT, and UPDATE values — but can’t handle table/column names or ORDER BY clauses. For those, use:
  • Whitelisting permitted input values
  • Different logic to deliver the required behavior
One critical rule: the query string must always be a hard-coded constant — never mix in variable data of any origin, even if you think it’s safe. It’s easy to misjudge the origin of data, or for future code changes to introduce tainted input into what was once a trusted path.

Examining the Database

Querying Version & Type

Inject provider-specific version queries to fingerprint the database: Using a UNION attack:
A response like the below confirms Microsoft SQL Server and reveals the exact version:

Listing Database Contents

Query information_schema.tables to list all tables:
Then drill into a specific table with information_schema.columns:
Oracle doesn’t have information_schema — use these equivalents instead: