[Dshield] Jail and Harden DNS

Jon R. Kibler Jon.Kibler at aset.com
Sat Mar 27 21:24:43 GMT 2004

Hello all,

I have recently had the opportunity to examine several *nix systems not under our administrative control. One problem that I universally found was that no one was running a chroot-ed named and no one had hardened named against attack.

Although I am not aware of any current BIND 9.2.2 (or later) exploits -- other than DOS -- there are several reasons to harden and chroot jail named. Ones that immediately come to mind include:
   1) Running named as a non-root user means that any buffer overflow attacks will not automatically run with root privilege.
   2) Running named in a chroot jail means that any compromise of named will only give the exploit access to DNS related files and not the entire system.
   3) Running a hardened named will make it more difficult to successfully DOS named.

Probably the two excuses I have heard most for not jailing and hardening named were: 
   1) I didn't know anything about it... the O/S install instructions didn't say anything about doing it.
   2) I tried to do chroot named, but I could never get it to work.

Thus, to mitigate both of those excuses, I have put together the following "cookbook" for making named more secure. The steps outlined below are NOT the complete set of steps required to fully secure named. Use at your own risk. Usual disclaimers apply. 

(BTW, for all the non-*nix folks out there, "named" is pronounced "name dee" and not like the past tense of "name".)

Feedback, corrections, mods for other O/Ses, and general comments welcome.

Jon Kibler
Jon R. Kibler
Chief Technical Officer
A.S.E.T., Inc.
Charleston, SC  USA
(843) 849-8214

These instructions have been tested on Solaris 9 and RedHat Enterprise 2.1. Exact procedures for other O/Ses may slightly vary.

   1) named's configuration file is currently /etc/named.conf
   2) named is running as root
   3) named's zone files are in /var/named
   4) rndc's key file is currently /etc/rndc.key
   5) you are running ISC BIND 9.2.2 or later

If these assumptions do not apply to your configuration, you will have to make minor changes to the instructions below to adjust for the differing locations, etc. If you choose locations or names that are different from those used in the instructions below, you will have to adjust the instructions to accommodate your naming conventions.

These changes can be successfully implemented on a production system without noticeable interruption of operations.

1) Create a user and group for named only, such as 'domain' (UID should be < 100 and MUST be unique)

2) Copy named.conf from /etc to /var/named (i.e., new file is: /var/named/named.conf)

3) Make the following changes to the named.conf file in /var/named (changes to other options and controls may be required):
   a) In the options section:
      -- remove any 'directory' entry
      -- add a 'pid-file' entry such as in the example below (do NOT use a pathname -- only a filename)
   b) If you are NOT using IPv6, disable the IPv6 controls interface, as per the example below (assumes localhost administration)

options {
// directory not needed with -u & -t options on startup
//   directory "/var/named";
   pid-file "named.pid";        // required because of -t and -u

// required because we are not running IPV6
controls {
   inet allow { localhost; } keys { rndc-key; };

4) Copy /etc/rndc.key to /var/named/rndc.key and delete any
        include "/etc/rndc.key";
or similar line from /var/named/named.conf file

For named to log properly using syslog, it needs timezone information. Where this information is located is O/S dependent. This information must be present in the chroot-ed directory using the same pathnames where normally found -- thus, files normally found in /etc must be copied to /var/named/etc -- and likewise for other directories and paths.

5) Create a directory /var/named/etc and copy /etc/localtime into that directory

6) Create a directory /var/named/usr/share and copy (cp -R) /usr/share/zoneinfo into that directory

5) Create a directory /var/named/etc and copy /etc/TIMEZONE into that directory

6) Create a directory /var/named/usr/share/lib and copy (cp -R) /usr/share/lib/zoneinfo into that directory


(If anyone has a better solution, PLEASE let me know!)
7) Create a dir /var/named/var/named (this is NOT a typo!) and hard link rndc.key to it:
        ln /var/named/rndc.key /var/named/var/named/rndc.key 

8) Create a file /var/named/var/README to document why this redundant pathname is necessary, and enter the following lines into that file:
This dir path (/var/named/var/named) is necessary to get named to find the rndc.key file. 
  -- rndc wants to find the file in /var/named relative to the real root (/) directory
  -- named wants to find the file in /var/named relative to its root directory (/var/named), thus the redundant path
Stupid. Stupid. Stupid.

For REDHAT, you will probably need to make this change to /etc/init.d/named
For SOLARIS, you will probably need to make this change to /etc/init.d/inetsvc
Also, how BIND was complied will effect this script!

9) Change the startup script for named to be something about like this, only use the appropriate O/S file locations and scripting syntax:

if [ -f /var/named/named.conf ] && [ -f /usr/local/sbin/named ]
        echo 'starting internet domain name server.'
#  named complied with openssl needs to be able to find the openssl libs
        export LD_LIBRARY_PATH
#  start a chroot-ed named
        /usr/local/sbin/named -c named.conf -u domain -t /var/named &

If you save the script in step 10d as /var/named/fix-perms.sh, it will make all the required changes for you by typing:
Don't forget to make the script executable. Also, the script assumes that all scripts in the /var/named path have file names that end in '.sh' so that it can set the appropriate execute permissions

10a) Make everything in /var/named owned by 'domain'
        chown -R domain:domain /var/named
10b) Change all file perms to 444, dir perms to 751
        find /var/named -type f -exec chmod 444 {} \;
        find /var/named -type d -exec chmod 751 {} \;

10c) Change the permissions on rndc.key:
        chmod 400 /var/named/rndc.key

10d) The following script will also make these changes for you (name it as shown):
# Copyright (c) 2002 by Advanced Systems Engineering Technology. All Rights Reserved.
# /var/named/fix-perms.sh -- make all directory and file permissions in the /var/named path correct
chown -R domain:domain /var/named
chmod 751 /var/named
find /var/named -type f -exec chmod 444 {} \;
find /var/named -type d -exec chmod 751 {} \;
find /var/named -name '*.sh' -exec chmod 750 {} \;
chmod 400 /var/named/var/named/rndc.key

11) If you have zone files that have not been updated to meet the requirements of newer versions of BIND, you need to edit all of your zone files to make them conform with the requirement that all zones explicitly specify a default time-to-live (TTL) for all resource records (RR). This default TTL is specified by using the $TTL directive. It should appear as the first line of each zone file. An entry such as the following is usually appropriate:

$TTL 86400		; default TTL for RRs is 1 day

If you do not have a default TTL set, named will whine and set the TTL to the minimum default -- which is probably much lower than you really want.

12a) Stop and restart named. 

     If your O/S has an /etc/init.d/named file, you can simply:
         /etc/init.d/named stop;/etc/init.d/named start

     If your O/S has a 'pkill' command, you can:
         pkill -TERM named
         export LD_LIBRARY_PATH
         /usr/local/sbin/named -c named.conf -u domain -t /var/named &

     For other O/Ses
       -- use 'ps -ef' or 'ps -aux' to find the named process id
       -- send it a SIGTERM using the 'kill' command (kill -TERM named_pid)
       -- restart it as shown in the 'pkill' example

12b) Verify it works (using host, dig, or nslookup) and check the appropriate log file for errors:
     -- REDHAT: /var/log/messages
     -- SOLARIS: /var/adm/messages

12c) Verify rndc still works. Try:
         rndc reload
     and check your log files to ensure it worked!

13) When you are sure everything is working, delete named.conf and rndc.key from the /etc directory.

14) After creating new zone files or doing any other edits that may change the owner, group, or permissions on any file or directory in /var/named, be sure to rerun the fix-perms.sh script to set correct permissions.

15) After any O/S upgrade:
    -- make sure that the named startup files still chroot jail named
    -- copy new timezone information into the appropriate /var/named subdirectories


These instructions have been tested on Solaris 9 and RedHat Enterprise 2.1. Exact procedures for other O/Ses may slightly vary.

   1) you are running ISC BIND 9.2.2 or later
   2) you are running a chroot jailed named

If these assumptions do not apply to your configuration, you will have to make minor changes to the instructions below to adjust for your specific environment.

These changes can be successfully implemented on a production system without noticeable interruption of operations.

Note: The suggestions herein are steps that should be taken to reduce the susceptibility of BIND to a DOS attack. They are NOT a complete list of everything necessary to make named secure.

1) Limit The IP Addresses On Which named Listens.

When named starts, it tries to listen on all available interfaces. In general, this is not desirable, because the more open IPs on which named listens, the more paths available for an attacker. You will probably want to limit the IPs on which named listens to those assigned as name server IPs, and localhost.

For example, if your name servers are on IPs and, then you would probably want to add the following entry to your named.conf file:

acl thishost { ; 
} ;
acl ournameservers { ; ; 
} ;

options {
   // ... other options ...
   listen-on { 
      ournameservers ; 
      thishost ; 
   } ;
} ;

If your resolver configuration (/etc/resolv.conf) specifies other name server IP addresses, you would need to add these to the above listen-on options list.

Note: If after the above change, systems from outside your network can query your nameservers successfully, but you start to experience failures on your local network, you probably have systems that are trying to use unofficial name server addresses in their resolvers (/etc/resolv.conf for *nix, DNS setup in TCP/IP or AD for Windows).

2) Do Not Attempt To Process DNS Requests That Originate From Bogus IP Addresses.

DOS attacks usually used forged IP addresses. These IPs are usually from bogus networks. The current list of bogus IP networks can be found at: 
which also contains several templates for securing stuff, including BIND.

If you are using any of the RFC1918 netblocks, be sure you do not blackhole yourself!

acl bogus {;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 
} ;

options {
   // ... other options ...
   blackhole { 
      bogus ; 
   } ;
} ;

3) Ban Zone Transfers

(This should probably be step 1. However, almost everyone already has zone transfer bans in place, so this is included just for completeness.)

In general, unless you are running slave nameservers on remote hosts, you should NEVER allow zone transfers. For greatest security, ban transfers except for the zones that are acting as master servers.

// this part of the example bans all zone transfers
acl allowed-xfers {
    none ;
} ;

options {
   // ... other options ...
   allow-transfer {
      allowed-xfers ;
   } ;
} ;

// this part of the example allows specific hosts to transfer a specific zone
acl blah-slaves { ; ;
} ;
zone "blah.whatever" {
   // ... other zone controls ...
   allow-transfer {
      blah-slaves ;
   } ;
} ;

4) Restrict Name Server Queries

Ideally, the authoritative names servers for an organization should be completely separate servers from the name servers used to resolve local queries. However, in most medium and small organizations, this is seldom the case. Thus, this example will present how to properly restrict name server access on a server that both handles local queries and is the authoritative name server for the organization's domain(s).

There are really two issues here:
   1) Preventing DOS attacks via foreign recursive queries
   2) Preventing cache poisoning

Name servers handle two types of queries:
   1) Cache queries
   2) Recursive queries

A cache query is where a name server simply returns information it already knows -- that is, information stored in the name server's cache. This usually means that the name server is being queried for information for which it is authoritative. For a cache query, the name server never consults anything except for its cache to determine the answer.

A recursive query is where a name server is expected to search the DNS hierarchy to find information for which it is not authoritative. This usually means that the name server is going to query other name servers to determine the answer, if the answer is not already stored in the name server's cache. By default, BIND allows for anyone to submit recursive queries to any name server.

Name servers that support recursive queries are subject to cache poisoning attacks, which can result in a denial of service. This occurs when a compromised name server provides bogus answers to a recursive request.

The general approach to properly controlling who can query a name server that serves both your local network's recursive queries and is authoritative for your domain, is as follows:
   1) At the name server level, permit only your local network to query the name server.
   2) At the zone level, permit only cache queries on authoritative zones by anyone. 

// this part of the example permits local systems to recursively query the name server
acl our-networks { ; ; ;
} ;

options {
   // ... other options ...
   allow-query {
      our-networks ;
   } ;
   allow-recursion {
      our-networks ;
   } ;
} ;

// this part of the example allows anyone to query a cached authoritative zone
acl the-world {
   any ;
} ;
zone "blah.whatever" {
   // ... other zone controls ...
   allow-query {
      the-world ;
   } ;
} ;

5) Other Security Considerations

The above examples cover what I currently consider to be the major BIND security issues. There are several other issues that everyone running BIND probably needs to consider. Also, any given environment may have have specific issues that require special consideration. Some of these issues are outlined below.

5a) Remote Slaves

Anyone running remote slaves should consider further restrictions on how the slaves can be updated and by whom. Slaves that are updated from sources over the Internet should consider using TSIG to authenticate and verify zone update data.

5b) Logging

Like anything else, reviewing named log data is critical to ensuring named security. BIND 9.x provides for finely controlled named logging. Use it. 

When asked if they regularly review named's log, the standard response is usually "Oh it's nothing but 'lame server' entries." If that's your excuse, redirect the 'lame server' entries to a different log file than the one used by other named log entries. It is quite simple to do using the named logging controls. RTM.

5c) Make A Firewall Your First Line Of Defense

Put even your authoritative name servers behind a firewall. Be sure you accept traffic that originates from UDP port 53!

Restrict incoming port 53 traffic to the legitimate IP addresses of your name servers.

5d) DHCP Considerations

If you are using DHCP, closely control who can perform dynamic updates and what RR types can be updated.

5e) BIND Version Probe Countermeasures

Consider implementing countermeasures against BIND version probes. Popular countermeasures include:
   -- setting a bogus BIND version (this may invite more robust probes!)
   -- creating a db.bind zone file to force the logging of version queries

5f) Use Separate Authoritative Name Servers

As mentioned earlier, ideally the authoritative name servers should be separate from the name servers that perform recursive queries for local networks.

5g) Use Multiple Name Servers

For both security and redundancy, use multiple name servers where possible. Ideally, you should have at least two authoritative name servers, each on separate networks served by different backbone providers, and preferably in remotely different physical locations. You should also have at least two recursive name servers on your internal networks to provide for redundancy.

5h) Use BIND 9.x Views

Where segregation of authoritative and recursive name servers is not possible, consider using BIND 9's "view" control to further regulate the types of allowed queries and updates.

5i) Use BIND For All Authoritative Zones

If you are using something other than BIND as your authoritative name server, you really should consider investing in a cheap *nix box (you can get a Sun Blade for < $1K) and and setting up a secure BIND server to serve as your authoritative name server. 

6) Summary

The above list of BIND hardening recommendations should NOT be considered complete, necessarily correct, current, or applicable to any given environment. Use at your own risk. The usual disclaimers apply.


Feedback welcome!

Filtered by: TRUSTEM.COM's Email Filtering Service
No Spam. No Viruses. Just Good Clean Email.

More information about the list mailing list