Firewall DNS

Posted: April 19, 2010 in security
Tags: , , , , ,

So I’m trying to setup a really tight server and one of the things left to secure was DNS. How do I make sure that if the server gets rooted the backdoor will not be able to connect through DNS to it’s C&C? I decided to write a custom “firewall dns”, which would only allow DNS requests if they matched a certain host. You might now be yelling things like “YOU RETARD, never code something if there is an existing and probably working alternative”, true; thing is I’ve never really done anything with DNS on a coding level so it seemed like this was my opportunity.

Let’s spoil the fun, here is the boring output from my “fw-dns” like I like to call it:

Starting fw-dns
Listening on localhost 127.0.0.1
Connected to remote DNS server (‘192.168.5.1’, 53)
matches, forward
Drop packet

For now it’s in the alpha stage but it seems to work exactly like I want(or at least with the tests I’ve run). So if you try to resolve a domain which is allowed, it will forward the query and relay the response. If you try a disallowed domain it will do nothing. The best thing about writing this, was the dpkt library which made writing it a breeze(agreed that I have yet to sort out a lot of DNS stuff before it’s actually reliable). For example parsing the dns packet is as easy as modifying the original example src a little bit, you literally put your brain in ‘no-brainer’ mode and it will just work:

Just receive the request:

data, addr = udps.recvfrom(4096)

and parse it to retrieve the domain name:

dns = dpkt.dns.DNS(data)
if dns.qr != dpkt.dns.DNS_Q:
return None
if dns.opcode != dpkt.dns.DNS_QUERY:
return None
if len(dns.qd) != 1:
return None
if len(dns.an) != 0:
return None
if len(dns.ns) != 0:
return None
if dns.qd[0].cls != dpkt.dns.DNS_IN:
return None
if dns.qd[0].type != dpkt.dns.DNS_A:
return None

return dns.qd[0].name

the relaying is just a simple send and receive:

def relay(data):
global fudps
fudps.sendto(data,DNS_SERVER)#send original approved request
d, a = fudps.recvfrom(4096)#receive answer
return d #only return data section

Don’t you just love it when things are this easy?

You can download the software using bittorrent here.

The following resources where used for this quick hack:

http://jon.oberheide.org/blog/2008/12/20/dpkt-tutorial-3-dns-spoofing/
http://jon.oberheide.org/blog/2008/08/25/dpkt-tutorial-1-icmp-echo/
http://code.activestate.com/recipes/491264-mini-fake-dns-server/
http://docs.python.org/library/socket.html

Advertisements
Comments
  1. diablohorn says:

    This was meant more to prevent DNS backdoors to actually access the outside world. Only changes for my personal use have been the adding of a configuration file and the possibility to reload the config file without restarting fw-dns, also dropping privileges after starting.

    note:

    if you plan to use this kind of setup for a large throughput environment I suggest to either optimize the code or use powerdns with a ‘preresolve’ lua script hook.

  2. nice work man, keep us up to date on its progress, and what other things did you do to secure the DNS server?

  3. […] Firewall DNS « DiabloHorn […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s