DNS Tunneling: DNS Tunneling using powershell to download and execute a payload
What is DNS Tunneling?
DNS tunneling is a technique that has been around for a long time and is used by a variety of attackers. At a basic level, it involves using the DNS protocol as a means for data infiltration/exfiltration or as a C2 communications channel. There are many blog posts you can reference for more information on this topic.
Because this is such an old and well-known technique, many organizations have detection methods in place to try and prevent it.
The DNS record type of choice for DNS tunneling has historically been TXT. This is because TXT records can hold more data than other records and they are also case-sensitive, something that the other records are not which can have an impact when we start talking about encoding.
Using DNS to infiltrate a payload can be an attractive option in highly restrictive environments where normal methods involving HTTP/S and or more conventional methods may not be viable. In such an environment the next hurdle is likely to be actually executing your payload- bypassing Application Whitelisting is a topic I will likely spend some time diving into in the future.
Automation
I started out by combining the python scripts that turned our executable into hex and then created a zonefile. Next, I went through and removed all static references to domain names that will populate the zonefile; these are now passed in via command line args. Thirdly I added functionality to make a copy of our payload and then modify the magic bytes; this modified copy is what is turned into MX records within our zonefile, eliminating the need for VIM. Finally the python script prints out the powershell one-liner with the correct number of iterations to run nslookup (dependent on the length of payload) and the domain to run nslookup against. This python script has been uploaded as “createzonefile.py”.
Reliability
In order to increase the reliability of the attack, I spent some time working with how the python script creates MX records. The major problem point was the last MX record; this contains the remainder of the payload, as every other record is filled with 200 characters. Depending on how much data is left for this record, we might end up with one, two, three, or four octets partially or completely filled. I found that nslookup wouldn’t pull records if there were too many trailing “.”‘s, as was the case with our simple python script earlier if less than four octets were being used by the last MX record (e.g. record might be “0000000000000000000000.000000..”). New logic was implemented and tested to ensure that regardless of the payload size or the amount of data in the last MX record it would be formatted properly and function as expected.
The implementation of the powershell one-liner in the python script is another step towards reliability, as it ensures you are provided with the correct number of iterations of nslookup as well as the same domain name specified in the zonefile.
Efficiency
This last point mainly revolves around the powershell one-liner. I wanted to try and reduce the length of the command as much as possible should one need to hand type it on a target machine. Before factoring in the added script to replace the magic bytes, I was able to cut it down by around 30%.
These savings come from a few places:
- Shorten variables. $results is now $o. $num is now $a.
- Aliases. Select-substring becomes sls. Set-content becomes sc.
- Use shortened parameters when possible. The -Allmatches parameter of select-substring can be abbreviated -a because there are no other parameters beginning with a.
- Improve regex, loop logic, and array initialization. Every character counts!