boran.com/security/sp/bind_hardening8.html
boran.com/dns
Sean Boran
March 07, 2001 - This paper presents the risks posed by an insecure DNS server and walks through compiling, installing, configuring and optionally, chroot'ing BIND 8. The test environment is Solaris 2.5, 2.6, 7 and 8. Many configuration and troubleshooting tips are provided, along with up-to-date references on BIND and alternatives for NT, Linux and Solaris.
Italian readers: please note that this article has also been translated into Italian [9].
Update: Mar. 30, 2001
NOTE that Bind9 is discussed in another paper bind9_20010430.html. |
|||
Your Domain Name Service is the road sign to your systems on the Internet. No matter how secure and robust your Web, mail and other servers are, compromised and corrupted DNS systems can prevent customers and legitimate users from ever reaching you. DNS, like many of the older protocols, was developed at a time when the Internet was a kinder, gentler place and was meant to provide a simple and unlimited way to provide information about what computers you have to anyone else. Obviously, the model of the Internet has changed, and changes to BIND (Berkeley Internet Name Domain software, the most common implementation of DNS), along with widely accepted configuration guidelines, have improved our ability to lock down DNS.
BIND [1] is the most frequently used DNS server and maintained by the ISC. It is also known as "named", since this is the name of the actual daemon itself. BIND has a long history, is a core tool for most Internet sites. As with many applications exposed to the increasingly hostile Internet environment, security weaknesses have been discovered in BIND. There are three major versions:
So what, you say? Yet another program with security problems? There are so many problems in so many applications these days, it's just not possible to keep up with all these advisories and patches. Do we really have to worry about DNS too? Well, a compromised DNS server can pose some interesting risks:
BIND weakness may be addressed with several prevention measures, but detection and reaction shouldn't be forgotten either:
The procedure in this paper concentrates only on measures 4), 5) and 6), which should help to protect a server against possible future weakness in BIND. This procedure has been tested on several production systems: a secondary on Solaris 2.5 + 2.8, a primary on Solaris 2.6 + 2.7.
It is assumed that Solaris is up and running and appropriately hardened and that the BIND delivered with Solaris is disabled. If you have not yet hardened Solaris, check out the YASSP tool first [7]. This section runs through:
Download the distribution [1], and extract it to a subdirectory and compile. This can be done as any user.
Note: It is recommended that "GNU make" be installed first, so that the installation to a temporary directory below works correctly.cd src;
make clean;
make depend && make;Now change to the root account, install to a temporary directory, and create a tarball:
su - root
# allow group, but not world access
umask 027
make install DESTDIR=/tmp
cd /tmp/usr/local
tar cf - * | compress > bind_dist.tar.Z
Create a user and group account for BIND:
echo "named:x:20000:20000:BIND DNS daemon:/tmp:/bin/false" >> /etc/passwd
echo "named:NP:6445::::::" >> /etc/shadow
echo "named::20000:" >> /etc/groupDon't allow the BIND account to use ftp:
echo "named" >> /etc/ftpusers
Copy bind_dist.tar.Z to /usr/local on the DNS server and extract into /usr/local:
zcat bind_dist.tar.Z | tar xvf -
Set up file permissions:
cd /var; mkdir named
chown -R root:named named
chmod 770 named
touch /var/run/named.pid;
chown named:named /var/run/named.pid;
chmod 755 /usr/local /usr/local/bin /usr/local/sbin /usr/local/etc
chown root:named /usr/local/bin/{dig,dnsquery,nslookup,nsupdate,host};chmod 755 /usr/local/bin/ /usr/local/bin/{dig,dnsquery,nslookup,nsupdate,host};
chown root:named /usr/local/sbin/{dnskeygen,irpd,named,named-bootconf,named-xfer,ndc};chmod 755 /usr/local/sbin/{dnskeygen, irpd,named,named-bootconf,named-xfer,ndc};
Optionally, you can rename the default DNS binaries installed on the system, so that they are not used by accident, and leave a reminder.
cd /usr/sbin;
mv nslookup nslookup.old
mv nsupdate nsupdate.old
mv in.named in.named.old
mv named-bootconf named-bootconf.old
mv named-xfer named-xfer.old
touch NAMED_NOW_IN_USR_SBINAdd /usr/local/sbin to the root PATH in /.cshrc or /.profile.
cd /usr/local/etc
vi named.conf
chown root:named named.conf
chmod 640 named.conf
So what do you put in named.conf? Have a look at the examples provided in [2]. The file consists of options, logging, ACL, server and Zone sections. Some of the directives are:
After setting up named.conf, the files containing the DNS records have to be set up on primaries (in /var/named in our example); these are automatically downloaded by secondaries.
Check the console and syslog (daemonlog) for errors, e.g.
tail -f local0log | grep "named"
Start BIND:
/usr/local/sbin/named -u named
Configure automatic starting on boot
In /etc/init.d/inetsvc, change the DNS startup lines to:# Start the BIND DNS server:
if [ -f /usr/local/sbin/named -a -f /usr/local/etc/named.conf ]; then
echo "Starting BIND domain name server."
/usr/local/sbin/named -u named;
Before moving on to the next stage, BIND should be working well, with no errors in the logs. See also the troubleshooting section.
This process has three steps: create a general chroot jail, install BIND into the jail, start and test the chroot'ed BIND.
BIND is now up and running, but we want to tighten security further by forcing it to run in a chroot environment (also called a jail or padded cell: Basically, restrict the files visible to BIND to a subdirectory within the file system). See also footnote [2] for a discussion of chroot environments.
We will now walk through the steps for setting up the chroot environment, copying over the BIND files, starting BIND and troubleshooting. These steps chroot the entire BIND program, not just using BIND's "-t" feature (see Note 1).
The following steps assume use of the C-Shell. We start by setting a variable for the chroot environment (jail) location, and setting umask so that all files copied can be read by both groups and world. These commands are designed to be copied and pasted.
1. Set source and destination directories
csh
set jail='/home/dns';
umask 022;
2. Set up empty directories and links:
mkdir $jail;
cd $jail;
mkdir -p {dev,opt,usr,var,etc};
mkdir -p var/{run,log,named} usr/{local,lib};
mkdir -p usr/share/lib/zoneinfo;
3. Setup /etc
cp /etc/{syslog.conf,netconfig,nsswitch.conf,resolv.conf,TIMEZONE} $jail/etc
4. Create a user and group account within chroot and for the whole system. BIND will run under this account.
echo "named:x:20000:20000:BIND DNS daemon:/tmp:/bin/false" >> /etc/passwd
echo "named:x:20000:20000:BIND DNS daemon:/tmp:/bin/false" > $jail/etc/passwdecho "named:NP:6445::::::" >> /etc/shadow
echo "named:NP:6445::::::" > $jail/etc/shadowecho "named::20000:" >> /etc/group
echo "named::20000:" > $jail/etc/group
5. Set up libraries:
Use ldd to see what shared object libraries named and named-xfer rely on:
ldd /usr/local/sbin/named /usr/local/sbin/named-xfer
Copy the files listed by ldd, for example for Solaris 2.6/7:
cp -p /usr/lib/libnsl.so.1 \
/usr/lib/libsocket.so.1 /usr/lib/libc.so.1 \
/usr/lib/libdl.so.1 /usr/lib/libmp.so.2 $jail/usr/lib
On Solaris 2.5:
cp -p /usr/lib/libnsl.so.1\
/usr/lib/libsocket.so.1 /usr/lib/libc.so.1\
/usr/lib/libdl.so.1 /usr/lib/libmp.so.1 /usr/lib/libw.so.1\
/usr/lib/libintl.so.1 $jail/usr/lib
Experience has shown the following are also needed for Solaris 2.5/6/7:
cp /usr/lib/ld.so.1 /usr/lib/nss_files.so.1 $jail/usr/lib
And with v8.2.3 on Solaris 8:
cp /usr/lib/libl.so.1 $jail/usr/lib
("Experience" means that first attempts didn't work, but by running BIND with truss, one could see what libraries were being sought after.)
6. Copy over Timezone files (I use MET, here in Europe):
mkdir -p $jail/usr/share/lib/zoneinfo;
cp -p /usr/share/lib/zoneinfo/MET $jail/usr/share/lib/zoneinfo/MET
7. Set up devices for communication, console, syslog, etc.
cd $jail/dev
mknod tcp c 11 42
mknod udp c 11 41
mknod log c 21 5
mknod null c 13 2
mknod zero c 13 12
chgrp sys null zero
chmod 666 null
mknod conslog c 21 0
mknod syscon c 0 0
chmod 620 syscon
chgrp tty syscon
chgrp sys conslog
We assume bind was already in /usr/local, so copy the BIND files over from there:
cd $jail;
mkdir -p usr/local/{bin,lib,sbin,bind,etc}
cd $jail/usr/local/sbin;
(cd /usr/local/sbin; tar cf - dnskeygen named* irpd ndc ) |tar xvf -
cd $jail/usr/local/bin;
(cd /usr/local/bin; tar cf - dnsquery dig host nslookup nsupdate) |tar xvf -
cd $jail/usr/local;
cp /usr/local/etc/named.conf etc;
(cd /usr/local; tar cf - bind) |tar xvf -
Your DNS data can be located in several directories; here we present two examples. The location is specified in named.conf.
1. Data in /etc/named
mkdir -p $jail/etc/named; cd $jail/etc/named;
chgrp named $jail/etc/named;
(cd /etc/named; tar cf - * ) | tar xvf -For secondaries, allow named to create data files:
chmod 770 $jail/etc/named;
2. or DNS data in /var/named (my preference)
mkdir -p $jail/var/named; cd $jail/var/named;
chgrp named $jail/var/named;
(cd /var/named; tar cf - * ) | tar xvf -
Next, set permissions on files, so that root owns files and named can read all files and write some files. And, disable any SUID/SGID files.
The PID file is put in /var/run and not /usr/local, because we don't want the named user to be able to write to /usr/local/etc (and hence named.conf). The location of the PID file is specified in named.conf.jail=/home/dns
cd $jail# remove group write from var
chmod -R g-w var;
# remove all write access to opt and usr
chmod -R a-w opt usr# For secondaries, allow named to create data files:
chown -R root:named $jail/var/named;
chmod 770 $jail/var/named;# For primaries, allow named to read, but not write data files:
chown -R root:named $jail/var/named;
chmod 750 $jail/var/named;
chmod -R go-w $jail/var/named;# Create empty log and pid files:
touch var/log/all.log var/run/named.pid;
chown named:named var/log/all.log var/run/named.pid;# Allow named user/group to write logs and pid files:
chgrp -R named $jail/var/log $jail/var/run;
chmod 770 $jail/var/run $jail/var/log
chmod -R o-rwx $jail/var/run $jail/var/log# Allow named to access BIND config file:
chgrp named $jail/usr/local/etc;
chown root:named $jail/usr/local/etc/named.conf;
chmod 640 $jail/usr/local/etc/named.conf;
chmod 750 $jail/usr/local/etc;# Remove SUID or SGID bits, if any exist:
find . -type f -exec chmod ug-s {} \;See footnote [8] for an example of an "ls -alR" on a production DNS primary.
Edit DNS config file: if the PID or data location has changed from your original installation, then $jail/usr/local/etc/named.conf needs to be adapted (see also the section BIND Configuration Notes).
The chroot environment is set up and BIND is installed, so the current (non-chroot'ed) BIND can be stopped and the new one started.
if [ -f
/home/dns/usr/local/sbin/named -a -f /home/dns/usr/local/etc/named.conf ]; then
/usr/sbin/chroot /home/dns /usr/local/sbin/named -u named;
echo "Started chroot'ed BIND domain name server."
fi
If you have a problem, a few tips:
cd
/var/named;
/usr/local/sbin/named-xfer -z DOMAIN.NAME -f test.results -d 3 -l test.log PRIMARY_NAME
Then look at "test.*" in /var/named. To test a chroot'ed BIND, try -
/usr/sbin/chroot /home/dns /usr/local/sbin/named-xfer -z DOMAIN.NAME -f test.results -d 3 -l test.log PRIMARY_NAME
and check /home/dns/test.results and test.log.*
rather than:
/usr/sbin/chroot /home/dns /usr/local/sbin/named -u named
One reader (J. S. Townsley) had similar problems, so he replaced ndc with a script:
#!/bin/sh case "$1" in start) /etc/rc.d/init.d/named start; ;; stop) /etc/rc.d/init.d/named stop; ;; restart) /etc/rc.d/init.d/named restart; ;; *) /usr/sbin/chroot /chroot/named /usr/sbin/ndc $1 esac
BIND 8 had its own chroot function, which works by giving named an option "-t" which points to the chroot jail, for example "named -t /home/dns." When BIND starts up, it chroot's to the jail, after processing command line options and before it starts to answer queries. By compiling BIND and installing directly into the jail, all the bind programs will be correctly in place. Since BIND chroot's after reading user/group information, it doesn't need the other /etc and /usr/lib files noted above.
If BIND is set up as described above, it can still be started using this method, for example,
/home/dns/usr/local/sbin/named -t /home/dns -u namedThis method is simpler than the general chroot method below, but it does have the disadvantage that we rely on the BIND code to be executed before the chroot is bug-free. Also, a general chroot can be used to "jail" other programs too.
For the moment, I'll continue using the general chroot method described below, and update this article as problems are found/solved. See also the Known Problems section.
The following is an example named.conf with many comments to explain individual features. The file consists of an options section, ACL and server definitions, and Zone data.
acl "trusted-nameservers" {
localhost;
193.A.B.C; // my secondary
193.A.B.D; // another secondary
X.A.A.A; // ISP
X.Y.Z.X; // NIC for your country
};
options {
directory "/var/named";
/* /etc/named is also common */
//forward only;
// for Internal DNS servers, forward all unknown queries to external servers:
//forwarders { 193.a.b.c; 193.a.b.d; };
/* If there is a firewall between you and nameservers you want
* to talk to, you might need to uncomment the query-source
* directive below. Previous versions of BIND always asked
* questions using port 53, but BIND 8.1 uses an unprivileged
* port by default.
*/
query-source address * port 53;
pid-file "/var/run/named.pid";
check-names master warn;
/* default. */
datasize 20M;
stacksize 30M;
statistics-interval 1440; // stats once per day is enough
transfer-format many-answers; // faster transfers
version "DNS server"; // hide BIND version
// The following will restrict transfers for all zones, if enabled:
// allow-transfer { trusted-nameservers; };
recursion yes; // default
//allow-query { 193.a.b.c/24; };
};
controls { unix "/var/run/ndc" perm 0600 owner 20000 group 20000; };
logging {
channel syslog_errors {
// Syslog logging: typically daemon, if we choose local1,
// some message still go to daemon (bug), so we leave daemon for now .
syslog daemon;
//syslog local1; severity info;
};
channel file_log {
file "/var/named/debug.log" versions 3 size 10m; // limit
size + count
severity dynamic; // catch debug messages
print-category no; // Category unneeded in debug file?
print-severity yes; print-time yes;
}
category default {
syslog_errors;
// you can log to as many
channels
//default_syslog; //
by default goes to daemon in syslog
};
// ignore all "lame server" errors (only do this if none of the lame
// servers belong to you; otherwise, fix them)
category lame-servers{ null; };
//category statistics { null; }; // We don't need stats for this server
// enable for testing/debugging:
//category default { file_log; syslog_errors; };
//category panic { file_log; };
//category packet { file_log; };
//category eventlib { file_log; };
//other categories; queries, cname, config, load, notify, parser,
//response-checks, security, statistics, update, xfer-in, xfer-out
};
// Example definition of a Primary
zone "mytestdomain.com" {
type master;
file "mytestdomain.com";
allow-query { any; }; // no
restriction on queries
allow-update { none; }; // don't allow dynamic updates
allow-transfer { trusted-nameservers; }; // restrict zone transfers
};
// Example definition of a secondary
zone "mytestdomain2.com" {
type slave;
file "mytestdomain2.com";
masters { A.B.C-D }; // IP
address of the primary
allow-query { any; };
allow-update { none; };
allow-transfer { trusted-nameservers; };
};
// if you get servers giving bad data, ignore them with:
//server 10.0.0.2 { bogus yes; };
// this is the main file for the domain name server. Each line gives
// the file where is stored the name table for a particular domain.
// named.root can be downloaded from ftp.rs.internic.net/domain
zone "." {
type hint;
file "named.root";
};
zone "0.0.127.in-addr.arpa" {
type master;
file "db.127.0.0";
};
BIND provides some new security features in its latest release. Here we examine one: the use of TSIG (transaction signatures) to authenticate zone transfers.
Zone transfers are usually limited to a list of IP addresses (via the ACL mechanism) which correspond to specific DNS servers for a zone. Since only IP addresses are used, this mechanism is open to IP spoofing. BIND 8.2 and later allow authentication and verification of zone data. A key is configured on primary and secondary name servers and used to sign messages exchanged between the servers. It's important that the server times are synchronized. If the transfer is not authenticated with the correct key, no zone transfer may take place.
Let's look at an example where we use TSIG to restrict the zone transfers between a DNS primary "prim" (IP address 10.1.1.2) and DNS slave secondary "sec1" (IP address 10.1.2.2).
a) Generate an MD5 key, which will be used as a shared secret between the DNS servers. The "dnskeygen" tool is used. The key is written to a file.
# /usr/local/sbin/dnskeygen -H 128 -h -n prim-sec1.
Generating 128 bit HMAC-MD5 Key for prim-sec1.
Generated 128 bit Key for prim-sec1. id=0 alg=157 flags=513# cat Kprim-sec1.+157+00000.private Private-key-format: v1.2 Algorithm: 157 (HMAC) Key: bFs2bXnLTYTI7r0WJv7HMA==b) Create an identical key entry on both servers in named.conf:
key prim-sec1 { algorithm hmac-md5; secret "bFs2bXnLTYTI7r0WJv7HMA=="; };c) Add an ACL on both servers to limit transfers to specific hosts, for example:
acl "my-nameservers" { localhost; 10.1.1.2; 10.1.2.2; };d) For each host in the ACL, tell the BIND which key to use (do this for each server), for example on the primary:
server 10.1.2.2 { transfer-format many-answers; keys { prim-sec1 ; }; }; zone "mytestdomain.com" { type master; file "mytestdomain.hosts"; allow-query { any; }; allow-update { none; }; allow-transfer { my-nameservers; }; }d) Restart both named servers (send a HUP signal), then check the (syslog) logs for errors.
Testing if it works:
So it's really not difficult to significantly increase the security of your zone transfers. It is important that the file permissions on named.conf be restrictive so that it cannot be read by everyone on a system. The secret string used in the key must remain secret.
query-source * port 53;
allow-recursion { 193.a.b.c/24; };
To stop recursion completely (e.g. on a deligate server), set the option:
recursion no;
In the same vein, bind can be prevented from automatically resolving name server names in NS or RDATA records by setting the option:
fetch-glue no;
Solaris
- Chroot BIND 8 on Solaris - http://www.securityfocus.com/focus/sun/articles/bind-inst.html
Similar to this paper, but it didn't work for me.- Chroot BIND 4.9.x on Solaris - http://www.homeport.org/~adam/dns.html
- Rendering BIND 8.2.3 ultra secure - http://www.pgci.ca/p_bind.html
I found this 1.Feb.01. Looks interesting and is similar to the Chroot section of this paper.Linux:
- Chroot-BIND HOWTO for Linux - http://www.losurs.org/docs/howto/Chroot-BIND.html
A Linux equivalent of this article. Access to the Website can be sporadic and slow. It concentrates on the chroot aspects and assumes you know how to configure BIND.- Linux users may also be interested in Stackguard (a compiler for improved resistance to "stack smashing" attacks) or Immunix OS (RH Linux rebuilt with Stackguard). See Immunix.org. Note that Stackguard v1.2 had security flaws - use v1.21 or later.
- Linux: Dual chroot'ed BIND/DNS Servers - http://www.etherboy.com/dns/chrootdns.html
- DNS HOWTO, Nicolai Langfeldt
http://www.linuxdoc.org/HOWTO/DNS-HOWTO.html- Setting up v8.2.3 in a chroot environment (in German)
http://www.pl-berichte.de/t_netzwerk/dnssecure.htmlOther BIND articles
- Using BIND: Don't Get Spoofed Again - http://www.sunworld.com/swol-11-1997/swol-11-bind.html
- DNS Security, by Jeff Holland - http://www.sans.org/infosecFAQ/DNS_sec.htm
Concise but useful; good diagrams.- BIND FAQ - http://www.nominum.com/resources/bind-faq.html
General DNS articles
- LADON, A Distributed Authentication System for SSH using DNSSEC http://www.cs.jhu.edu/~smang/sshproject.html
- DNS related RFCs: http://www.dns.net/dnsrd/rfc
- DNS Resources Directory http://www.dns.net/dnsrd
- DRAFT: "RIPE Guide To Setting Up a DNS Server," Peter Koch, Universitaet Bielefeld. http://www.ripe.net/ripe/mail-archives/dns-wg/19990101-19990401/msg00001.html
Some interesting ideas, especially the idea of a "hidden primary," which may be useful to prevent against DoS attacks.- Foiling DNS Attacks: http://securityportal.com/cover/coverstory20001113.html
- http://www.isc.org/products/BIND/bind9.html.
It is a complete rewrite. v9.1 is available and recommended by the ISC, rather than v8.
- Paul Vixie and David Conrad on BINDv9 and Internet Security
http://www.linuxsecurity.com/feature_stories/conrad_vixie-1.html
In this interview, Paul Vixie and David Conrad talk about the Internet Software Consoritum, the changes in the latest major version of bind, the security features designed into it, and the future of Internet security.- Fingerprinting Bind 9 (discussion)
http://archives.neohapsis.com/archives/bugtraq/2001-01/0491.htmlBind for NT links:
- AN NT port of BIND is available from ISC - http://www.isc.org/products/BIND
- Microsoft also bundles a DNS with NT Server.
Dents, an alternative DNS server, still in alpha - http://www.dents.org
djbdns is a collection of Domain Name System tools, http://cr.yp.to/djbdns.html, that includes several components:
- The DNScache program is a local DNS cache. It accepts recursive DNS queries from local clients such as Web browsers. It collects responses from remote DNS servers.
- The tinydns program is a fast, UDP-only DNS server. It makes local DNS information available to the Internet.
- The pickdns program is a load-balancing DNS server. It points clients to a dynamic selection of IP addresses.
- The walldns program is a reverse DNS wall. It provides matching reverse and forward records while hiding local host information.
- The rbldns program is an IP-address-listing DNS server. It uses DNS to publish a list of IP addresses, such as RBL or DUL.
- The DNS library handles outgoing and incoming DNS packets. It can be used by clients such as Web browsers to look up host addresses, host names, MX records, etc. It supports asynchronous resolution.
- The dnsfilter program is a parallel IP-address-to-host-name converter.
- The dnsip, dnsipq, dnsname, dnstxt, and dnsmx programs are simple command-line interfaces to DNS.
- The dnsq and dnstrace programs are DNS debugging tools.
Useful tips were also provided by FOCUS-SUN@SECURITYFOCUS.COM members, including C.M. Wong, Eric Jon Rostetter, J. S. Townsley, Wyman Eric Miles, and Colin Stefani. Fabrice Bacchella pointed out how to use BIND's inbuilt chroot function. See also the archive of Focus-Sun messages. Thanks also to Stephane Grundschober, Kurt Seifried, Matthias Andree and Jason Chan.
Seán Boran is an IT security consultant based in Switzerland and the author of the online IT Security Cookbook. He has over 4 years experience managing DNS servers.
02.Jul.00 sb Chroot BIND 8 and publish in
the Solaris Digest
10.Sep.00 sb TSIG tested and publish in the Solaris Digest
29.Sep.00 sb Complete rewrite to general Installing & hardening BIND
document. Published.
06.Oct.00 sb Minor formatting, note on dig vs. nslookup, link to Bindv9 interview,
delete sentance on Bind9 root exploit, it is not true.
13.Nov.00 sb Add note on hiding version information.
14.Dec.00 sb Improvements after feedback and secondary problems. Publish.
08.Jan'00 sb Add link to ripe Guide. Reorganise references. See changes in Green in
www.boran.com/security/sp/changelog/bind_hardening_01feb2001.html
08.Mar'01 sb Note on GNU make, Set Jail permissions
30.Mar'01 Add into note on different BIND versions.
04.May.'01 Refer to new BIND9 article
07.Aug'01 Change /usr/ucb/chown to /usr/bin/chown