UPDATE: There’s a new version, with 25% less bugs! Use this instead.
As some of you may know, I wear an Incident Response hat within my organization. As I like to be proactive and actively search for issues rather then just be an IDS alert monkey, I love pages like the Malware Domain List, the ZeuS Tracker, and malwareurl.com. While these are great resources, it is a bit difficult attempting to take the lists and apply them to the environment; most of their usefulness comes from when you have a questionable URL and need to see if someone else has reported it as a bad site. A great service, but not proactive.
While staring at the ZeuS Tracker Domain Block list and trying my usual method of snipe hunting manually entering domains to query the firewalls, a moment of inspiration hit: I don’t care about all the domains, just the domains that people visit. Who knows what domains people visit? The DNS servers! Now it was just a question of trying to coax the information out of the DNS servers. Thankfully, PaulDotCom Security Weekly came to the rescue: They have been talking about getting information out of DNS servers during penetration tests and a simple non-recursive DNS lookup on the local DNS server can tell you if someone queried for the host recently. A couple of quick experiments to verify this fact on my work’s main DNS servers confirmed this fact, and I set to work.
My first attempt was a simple script to take a pre-chewed version of the ZeuS Domain list, feed it through dig and pipe the output through grep. It worked, but I wanted something a touch more automated. Over the next couple of nights on the train, I whipped up a tool to automate the process a little more. The resulting tool is the ZeuS DNS Scraper. It’s a simple script written in Perl and should work straight out of the box with the default modules included in a Perl distribution.
Running the Script
Running the tool is fairly simple, there are only 4 options: –server, specifying which server(s) to query, –file, specifying where to put the downloaded ZeuS Tracker block list (defaulting to /tmp/ztbl.txt) , –download/–nodownload which specifies whether or not the script should attempt to download the block list, and –debug, which specifies the verbosity of the script.
A typical command line would be:
perl zeusdnsscraper.pl --server 192.168.1.2 --server 192.168.1.3
Which would download the block list, and then proceed to query 192.168.1.2 and 192.168.1.3 for each entry in the block list. You can specify as many as many servers as you like, however, the block list often hovers around a thousand entries, so each additional server adds another thousand or so queries.
Alternatively, once the list is downloaded, the script will download the block list only if the local copy is older then 60 minutes, (don’t worry it doesn’t update that frequently). You can also specify that the script doesn’t download the list again with the –nodownload option:
perl zeusdnsscraper.pl --server 192.168.1.2 --server 192.168.1.3 --nodownload
You can also turn on debugging with the debug option, which will display every step in the process:
perl zeusdnsscraper.pl --server 192.168.1.2 --server 192.168.1.3 --debug
When the script is run in default mode, a ‘.’ will appear after each query, while in debug mode it will display the result of the query and whether or not it found an entry.
What You Want To See
Completed! NNNN queries made, 0 entries found! Hooray!
In this example, NNNN would be the number of queries sent, remember this increases which each additional server you need to query, and it has found 0 entries, indicating that the DNS servers queried have no cached entries for any of the domains. Congratulations, pat yourself on the back and grab yourself a nice frosty beverage from the refrigerator.
What You Do Not Want To See
NNNN queries made, 4 entries found. Uh Oh. W.X.Y.Z has an entry in it's cache for www.example.net: 10.1.2.3 W.X.Y.Z has an entry in it's cache for www.example.net: 10.1.2.4 W.X.Y.Z has an entry in it's cache for www.example.com: 10.4.5.6 W.X.Y.Z has an entry in it's cache for www.example.org: 10.7.8.9
Well, crap. This time the beverage you need is probably kept in your attrition.org flask. NNNN is the number of queries the script made and the “4″ in this example is number of results found. In this example, “www.example.net” was cached with two separate addresses, while “www.example.com” and “www.example.org” both have one apiece. The W.X.Y.Z in the above example is the DNS server that responded, and the 10.X.X.X addresses are the IP addresses that the DNS server responded with. These IP addresses are what you are interested in.
My DNS Servers Have Cached Entries! Now What?
This is where some good old detective work comes in. The presence of the cached entries on your DNS server only means that one of the clients on your network asked for the entry in question. Normally, it’s time to start plugging IP addresses in your firewall logs to see who’s been visiting them. Then it’s time to start cleaning.
Now, obviously, this sends a boat load of queries in a very rapid fashion to DNS servers. Make sure that your DNS server and your connection can handle the load and don’t run it against DNS servers that you do not have permission to do so. Also, some of the DNS entries have small enough TTLs that they may expire quickly, meaning that even if the script comes back clean, there could still be infected hosts.
I’d just like to say a big thanks to the folks over at abuse.ch for hosting the ZeuS Tracker. It’s a handy tool and it’s invaluable if you’re running even a moderately sized network.