Protecting Users with DNS Malware Blacklisting
Blacklisting domains that are known to host malware is a simple way to discovery and stall malware on your organisations network. You can use it to prevent users, or at least warn them severely, from installing it in the first place and discover malware making dubious DNS lookups on your network too. As a good network administrator is one that maximises laziness, we want to avoid the issues of false positives; mainly as then this increases the amount of contact with have with the users and that is just asking for trouble. The instructions here not only cover how to blacklist domains, but also to keep your list automatically up to date, and add the functionality so that users themselves can bypass what they consider to be a false positive listing.
Blacklists where malware lives is hard to come by, as searching online really only gives you hits for DNS mail based blacklisting to be used on MTAs. The only ones I have found are:
http://www.malware.com.br/lists.shtml - seems very unreliable, uptime wise
https://zeustracker.abuse.ch/ - malwaredomains's list includes this
http://hosts-file.net/ - honkingly large but encompasses much more than just malware
For now I have focused on malwaredomain's list, since we (4000 students and 600 staff) started using this system back in July 2008-ish I have had no problems, and more importantly no contact with the users in regards to it.
If you have any problems, queries, or suggestions for improvement then do please contact me.
Requirements
You need to have a already functioning installation of Unbound running as your organisation's recursive DNS server. You might prefer to use BIND9, MaraDNS or some other resolver however to do so you will need to adapt my shell script and instructions accordingly, although the Apache bit should remain the same. How to do this all is beyond the scope of this article.
In addition to this you will need a seperate server with a the Apache webserver installed on it that is able to make recursive DNS queries all by it's self. In addition, you will need the following installed and configured on the box:
- apache2
- mod_apreq (libapreq2 too)
- mod_setenvif
- mod_proxy (mod_proxy_http too)
mod_perl - plus the modules Apache2::Request (libapache2-request-perl), Net::DNS (libnet-dns-perl), Template Toolkit (libtemplate-perl) and I18N::AcceptLanguage (libi18n-acceptlanguage-perl)
- [optional] cronolog
Configuring the Infrastructure
The Update Script
The script is intelligent enough to check the 'last-modified' timestamp in the HTTP header for the 'domains.txt' file and to only download and process it when it changes. This considerably lowers the load for the 'Malware Domains' owner and helps to avoid un-necessary restarts of Unbound.
Download the malwaredomains2unbound script, make it executable and place it in '/usr/local/sbin/'. You will need to make a few minor amendments at the top to match your setup:
TYPE=redirect # or 'redirect' or 'refuse, consult 'man unbound.conf' DST_HOST=ids.example.com. #DST_MAIL=localhost.
These should be the only lines you need to amend. If you simply want to prevent the DNS lookups working (and not to have a 'self-help' whitelisting service as detailed below functioning) then set 'TYPE' to 'refuse'. Otherwise you will need to enter in a FQDN (it is crucial that you terminate it with a '.', unless you know what you are doing) to say where you want the DNS lookups to go instead. You also get the option to redirect the MX records (if you do not, then none will exist and you will get NXDOMAIN) by populating 'DST_MAIL' with a FQDN.
Once configured, you should be able to give it a test run by typing as root (this will take some time so be patient):
# malwaredomains2unbound
Once it runs you should see that a 'domains.txt' file exists in '/var/tmp/' and an updated 'local-dnshijack' file is present lurking in '/etc/unbound/'. If you re-run the script again, it should do nothing as the timestamp of the remote 'domain.txt' file should match your local one (ie. it's unchanged).
The DNS Componment
To configure Unbound is dead easy, you just add the line at the end of the main "server:" section (before the 'python' and 'remote' sections start) to say:
include: "/etc/unbound/local-dnshijack"
If you now restart unbound you should find it now works.
Scheduling the Updates
If you create a file '/etc/cron.d/local-unbound' with the following contents:
#MAILTO=hostmaster PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin # I hope you use DNSSEC....right? 17 2 7 * * root /usr/local/sbin/update-itar.sh && unbound-checkconf && /etc/init.d/unbound restart # Every two hours check for updates # N.B. for each DNS server you should put a different minutely setting of about five minutes # as when unbound restarts you will find for about ten seconds you will not get any DNS # lookups functioning. Spreading the updates means only one DNS server is down at a time 15 0-23/2 * * * root /usr/local/sbin/malwaredomains2unbound && unbound-checkconf && /etc/init.d/unbound restart
This will check for updates every two hours at fifteen minutes past the hour. As the note in the above chunk states, you should choose different minutely intervals for each of your DNS servers to avoid downtime; as obviously Unbound will not service DNS queries whilst being restarted which can take some time.
If the 'domains.txt' file has not been updated or there was a problem running the 'malwaredomains2unbound' script, or the config file becomes broken, then no restart of Unbound will take place. You should, if you have configured cron correctly, receive an email stating what went horribly wrong if the script failed to run.
The Webserver Componment
The element that makes this bit cook are:
Apache 'dnshijack' VirtualHost snippet, place in '/etc/apache2/sites-available/' and then create a softlink from there to '/etc/apache2/sites-enabled/
'/var/local/dnshijack/' contents, extract to '/var/local/', it should create a directory called 'dnshijack'
To get the dnshijack'ing code working you will need to only edit the Apache VirtualHost file, '/etc/apache2/sites-available/dnshijack'. You need to:
amend the IP ranges listed in the '<Proxy>' section. These are the IP addresses of your client workstation (and will be the ranges your webserver will be happy to service and proxy for). Failure to set these properly can result in your webserver becoming an open proxy!
tweak the 'NameVirtualHost 1.2.3.4' and '<VirtualHost 1.2.3.4:80>' bits to match the IP address of ids.example.com that you used in the 'malwaredomains2unbound' script above
You will also need to tweak the section listing details about your installation in that file too:
PerlSetEnv dnshijackNS "1.1.1.1" PerlSetEnv dnshijackREALM "example.com" PerlSetEnv dnshijackCONTACT_NAME "Firstname Surname" ServerAdmin "me@example.com" PerlSetEnv dnshijackKEY "TYPE SOME RANDOM SECRET HERE SO MASH KEYBOARD OR SOMETHING" PerlSetEnv dnshijackDEFAULT_LANGUAGE "en"
You need to amend it as follows:
'dnshijackNS': points to your organisation's regular DNS server(s) - If you need to enter more than one nameserver then seperate them with spaces
- 'example.com' is your organisations domain, if you do not have one use 'localnet'
you need to give your full name ('dnshijackCONTACT_NAME') and email address ('ServerAdmin') so the users know who to contact when things go wrong
'dnshijackKEY': you need to set this to something random. This is a server side secret cookie so that people are not able to trick the webserver into proxying websites for them unless it is actually permitted
the default language ('dnshijackDEFAULT_LANGUAGE') you might want to amend if your primary language is not english, it's a i18n abrieviation
You need to configure your webserver to run it's own recursive DNS server that functions completely independently from your organisations one so you should tweak your '/etc/resolv.conf' file to use the nameserver at '127.0.0.1'. Without this, your webserver when proxying requests would simply find it's-self talking back to it's-self in a nasty loop when someone tries to go to a blacklisted domain. This you obviously do not want to happen.
All you need to do is restart Apache and you should have a fully functional DNS blacklisting system active. When you try to access a blacklisted domain with your web browser you will be redirected to a 'blacklisted' page giving a simple explaination of why the site has been disabled. If it is considered a false positive then a simple button "accept responsibility" will enable the user to get through to the site they want.
How It Works
It should be pretty obvious why the user sees the disabled page 1, the whitelisting system might need some explaination.
When a user wishes to access a system, a client side session cookie is set that enables them to pass through the Apache server. The cookie is presented to the blacklist script, 'DNShijack.pm', and if it checks out to be valid the requst is passed to mod_proxy and handled approiately, the cookie is stripped out on it's way though so the destination webserver never sees it. This is where the server side KEY is considered, so malicious users cannot amend the cookie to whitelist alternative domains too. Now, when that cookie is set Apache will not log requests made to it that are blacklisted so privacy concerns should also be a non-issue. The only things in the log you should see is the initial request where a user hits the page, and an entry in the error.log stating that the user has accepted the 'risk' in going to the site.
N.B. bear in mind that this system is ineffective against anything that directly accesses the IP address of a blacklisted domain, no DNS lookup, no blacklisting. This sort of thing probably should be handled by your firewall. So if the hosts file is tweaked on the workstation it's-self, then the user will not benefit from this type of system. Alternatively you might want to look into my Unsavoury IP Route Blackholing page to solve this.
Interesting Projects
To customise the webpages the user sees all you need to do is amend '/var/local/dnshijack/templates/en/' (copy the directory and name it to the i18n language you use if you want to regionise the system) and edit the file to your hearts content; no need to restart Apache after changing this.
If you packet sniff on the network interface of the webserver and filter ports 53 and 80:
# tcpdump -i bond0 -n -p host ids.example.com and not port 53 and not port 80
You will be able to catch all the 'strange' requests being made to the blacklisted domain, probably finding malware your AV is unable to.
as instead of the real IP address being returned for a blacklisted the webserver one is returned (1)