DNS Knows. So Why Not Ask?

DNS is like the town gossip of the network infrastructure. Computers and apps ask DNS questions and you can ask DNS who has been asking to resolve malware domains. When internal trusted systems are using DNS to resolve the names of known malware sites, this can be an Indicator of Compromise and a warning to clean the potentially infected systems and block traffic to the domain.

Blacklisting the known malware domains using local RPZs, firewalls, Cisco IronPort Web Security Appliance (WSA), or Cloud Web Security (CWS) is a great way to add an extra level of security in organizations. But what if you are just getting started in the process of cleaning systems and just need some situational awareness? Or, how can you manually check to see if these devices are working as expected? How can you determine independently of security devices, and at any point in time, that client systems are not reaching out to malicious domains? You can use dig but this post focuses on a Python example. Let’s first take a look at some DNS mechanics.

DNS Recursion Primer

DNS requests can either be recursive or non-recursive. Client applications, such as Internet browsers and malware, typically request that the DNS server perform recursion by setting a Recursion Desired (RD) flag in the DNS request packet. If the DNS server cannot answer the request either from its cache or zone information, the server will request assistance from other DNS servers. When the name is finally resolved and offered to the client, the resolution will stay in the DNS cache for a period of time. One hour is the default time period in Microsoft DNS servers.

Enter the Non-Recursive Flag

If we request name resolution from the internal DNS server and unset the recurse flag in our request, then the internal DNS server will only check the local zone records and cache. Thus, we can tell if a client has already requested the resolution. In the following Python example, we compare DNS cache with a malware DNS domain list.

The Script

You will need to install Python, the dnspython module, and grab a malware list.

#!/usr/bin/python
# This script will query a name server nonrecursively
# RFC 1912 recommends that the $TTL value on the name server
# be set to 1 day or longer
# -*- coding: utf-8 -*-

import sys
import dns
from dns.exception import DNSException
from dns.rdataclass import *
from dns.rdatatype import *
from dns.message import *
from dns.query import *

if len(sys.argv) == 3:
script, malwareFile, nameServer = sys.argv
else:
print '''
This script needs three arguments
Usage: python dnsNonRcv.py malwarefile nameserverIP
'''
sys.exit (1)

malwareFile = sys.argv[1]
nameserver = sys.argv[2]
domainFile = open(malwareFile)

for line in domainFile.readlines():
domain = line.split()[0]
response = None
# create the query
query = dns.message.make_query(domain, dns.rdatatype.A, dns.rdataclass.IN)
# unset the recurse flag
query.flags ^= dns.flags.RD

try:
response = dns.query.udp(query, nameserver)
except DNSException:
response = []
if response.rcode() == dns.rcode.REFUSED: #
print '''
The name server answered, but refuses to
perform the specified operation.
Contact your DNS administrator.
''' # This can be for any policy reason
# including because we unset the recurse flag.
sys.exit (1)
if len(response.answer) > 0:
print '%s ======> Found Record!' % domain
else:
print '%s [*] No Record.' % domain
continue

The script reads the malware file line by line expecting that each line contains a domain name. Then that name is checked for name resolution with the DNS server. If an IP address is found, the script output will show as much. If the server responds but for policy reasons does not want to provide a yes/no answer, then the script output will show that as well.

mac:~\ python dns2.py malwarelist.txt 8.8.8.8
00398d0.netsolhost.com [*] No Record.
021tf.com [*] No Record.
05sun.com ======> Found Record!
0858dgw.com [*] No Record.
0koryu0.easter.ne.jp [*] No Record.
1-abc.net ======> Found Record!
1-ace-search-engine-submission-software.com [*] No Record.
1-vinstaller.com ======> Found Record!
1.michaelwilsonmusic.com ======> Found Record!

The output clearly indicates some names on the list are found. If the DNS server responds, but the policy of the server is to not answer queries where the RD flag is not set, then the following will be displayed:

mac:~\ python dns2.py malwarelist.txt 208.67.220.220

The name server answered, but refuses to
perform the specified operation.
Try a different name server.
mac:~\

I hope this post is helpful with gathering some real-time intelligence on what exists in DNS cache and how to use this to your advantage in the identification of malware use in your environment. For additional information, see the following:

DNS Best Practices

Microsoft DNS

BIND

Blocking Malicious DNS Requests with RPZ