Running Secure DNS Servers Jay Beale Lead Developer, Bastille Linux Security Team Director, MandrakeSoft Running Secure DNS Servers " " " " " Installing and configuring Unix BIND DNS server Simulating attacks.

Download Report

Transcript Running Secure DNS Servers Jay Beale Lead Developer, Bastille Linux Security Team Director, MandrakeSoft Running Secure DNS Servers " " " " " Installing and configuring Unix BIND DNS server Simulating attacks.

Running Secure DNS
Servers
Jay Beale
Lead Developer, Bastille Linux
Security Team Director,
MandrakeSoft
Running Secure DNS Servers
"
"
"
"
"
Installing and configuring Unix BIND DNS server
Simulating attacks and information probes for
security assurance
Implementing security "best practices" for DNS
configuration
Advanced Methods: Chroot the Daemon, Run as
Non-superuser
Split Horizon?
How Does DNS Work?
•
•
•
DNS provides mapping between machine names
and IP addresses.
Name servers answer queries they have
information for and often hunt for the rest in a
recursive query.
Root Servers are the starting point in a recursive
query.
Installing Unix BIND DNS server
–
Grab source for BIND at:
ftp://ftp.isc.org/isc/bind/src/cur/bind-8/bind-src.tar.gz
Building BIND
"
On Solaris:
# tar -xzvf bind-src.tar.gz
# cd src
# vi port/solaris/Makefile.set
Onto configuring build process...
Configuring BIND Makefile.set
(Solaris)
–
Append DESTINC and DESTLIB lines:
'DESTINC=/usr/local/include'
'DESTLIB=/usr/local/lib'
to get the following:
Solaris Makefile.set
'CC=gcc'
'CDEBUG=-g -O2'
'DESTBIN=/usr/local/bin'
'DESTSBIN=/usr/local/sbin'
'DESTEXEC=/usr/local/sbin'
'DESTMAN=/usr/local/share/man'
'DESTHELP=/usr/local/lib'
'DESTETC=/usr/local/etc'
'DESTRUN=/usr/local/etc'
'LDS=:'
'AR=/usr/ccs/bin/ar cru'
'LEX=/usr/ccs/bin/lex'
'YACC=/usr/ccs/bin/yacc -d'
'SYSLIBS=-ll -lnsl -lsocket'
'INSTALL=/usr/ucb/install'
'MANDIR=man'
'MANROFF=man'
'CATEXT=$$N'
'PS=ps -p'
'RANLIB=/usr/ccs/bin/ranlib'
'DESTINC=/usr/local/include'
'DESTLIB=/usr/local/lib'
Compiling BIND (Solaris)
# make depend
# make
# make install
Installing BIND on Linux
"
Find the location for your Linux distribution's most recent
BIND package.
# rpm -ivh http://path_to_package/bind-8.2.2_P7-x.rpm
Configuring BIND
"
BIND 8 and 9, unlike BIND4, use named.conf.
Syntax has changed, but you can use namedbootconf to convert your old named.boot to the
new format.
" Zone (data) files have not changed syntax.
"
Sample named.conf File 1/3
acl internal { 192.168.1.0/24 ; };
options {
directory "/var/run/named";
listen-on {192.168.1.2 ; };
allow-recursion { internal ; };
allow-query { internal ; };
};
Sample named.conf File 2/3
zone "." {
type hint;
file "db.cache";
};
// bastille-linux.org maps to the 192.168.1.0/24 network
zone "bastille-linux.org" {
type master;
file "db.bastille-linux.org";
allow-query { any ; };
};
Sample named.conf File 3/3
zone "1.168.192.in-addr.arpa" {
type master;
file "db.192.168.1";
allow-query { any; };
};
zone "0.0.127.in-addr.arpa" {
type master;
file "db.127.0.0";
allow-query { 127.0.0.1 ; };
};
Best Practice: Logging
"
BIND 8 adds the capability for enhanced logging.
–
Channel:
a method (syslog priority, file, stderr or bit bucket)
for logging data
- Category:
a type of data to log, based on hard-coded names in
the BIND 8 program
BIND 8 Logging Channels 1/2
( For syslog, format is: syslog facility; severity severity; )
"
channel info_syslog {
syslog daemon;
severity info;
};
"
channel some_file {
file "your_file";
severity error;
};
BIND 8 Logging Channels 2/2
"
channel stderr_fd {
file "<stderr>";
severity critical;
};
"
channel null_gone {
null;
};
BIND 8 Logging Categories 1/3
Quoted from DNS and BIND book:
"
"
"
"
"
"
"
default - wildcard, maps to ALL
cname - CNAME errors
config - configuration file errors
db - database operations
eventlib - system events
insist - internal consistency check failures
lame-servers - Detection of bad delegation
BIND 8 Logging Categories 2/3
Quoted from DNS and BIND book:
"
"
"
"
"
"
"
load - zone loading messages
maintenance - Maintenance events (e.g. system queries)
ncache - Negative caching events
notify - Asynchronous change notifications
os - problems with the operating system
packet - decodes of packets received and sent
panic - problems that cause the shutdown of the server
BIND 8 Logging Categories 3/3
Quoted from DNS and BIND book:
"
"
"
"
"
"
"
parser - Parsing of the configuration file.
queries - Analogous to BIND 4's query logging
response-checks - Malformed responses, unrelated addt'l
information,...
security - approved / unapproved requests
statistics - periodic reports of activities
update - dynamic update events
xfer-in / xfer-out - Zone transfers from remote/local
nameserver to local/remote nameserver
Additional Logging
BIND 8 has strong default logging, but we can add a security
log for certain important categories. Append to named.conf:
logging {
channel security {
file "/var/adm/bind-security" versions 4 size 10m;
print-time yes;
};
category insist {security;};
category os { security; };
category panic {security;};
category security {security;};
category xfer-out { security; };
category update {security; };
};
Interesting Part of the Talk
"
Take the role of an attacker!
–
DNS gives out a whole lot of useful information
"
"
Most syadmins don't think from the attacker's point
of view!
Bad habits from when the Internet was a more
exclusive neighborhood.
Interesting Part of the Talk
"
Take the role of an attacker!
–
DNS servers have traditionally made good cracking
targets!
"
"
BIND has had a number of security vulnerabilities
BIND runs as root by default
"Profiling the Target"
"
Find out the target's primary nameservers:
[jay@max jay]$ nslookup
Default Server: ns.my.isp
Address: 10.0.0.1
> set q=ns
> dumb.target.jay
Server: ns.my.isp
Address: 10.0.0.1
Non-authoritative answer:
dumb.target.jay nameserver = dumb.target.jay
dumb.target.jay nameserver = ns2.dumb.target.jay
Authoritative answers can be found from:
dumb.target.jay internet address = 192.168.1.85
Zone Transfer of their Zone 1/2
[jay@max zone]# dig @192.168.1.85 dumb.target.jay axfr
; <<>> DiG 8.2 <<>> @192.168.1.85 dumb.target.jay axfr
; (1 server found)
$ORIGIN dumb.target.jay.
@
20H IN SOA
ns1 hostmaster.dumb.target.jay (
2000111001
; serial
5H
; refresh
1H
; retry
4d4h
; expire
1D )
; minimum
1H IN NS
20H IN NS
20H IN NS
20H IN A
1D IN HINFO
1D IN MX
dumb.target.jay.
ns.dumb.target.jay.
ns.dumbs.isp.
192.168.1.85
"Pentium 133" "Red Hat 6.1"
10 mail
Zone Transfer of their Zone 2/2
mail
really
rather
serious
extra
ns
r_g
roblimo
tahara
1D
1D
1D
1D
1D
1D
1D
1D
1D
1D
1D
1D
1D
IN
IN
IN
IN
IN
IN
IN
IN
IN
IN
IN
IN
IN
A
A
TXT
HINFO
A
HINFO
CNAME
A
A
A
MX
A
A
192.168.1.2
192.168.1.20
"Admin's Trusted Workstation"
"Athlon 850" "Red Hat 6.1"
192.168.1.15
"Pentium 266" "Mandrake 7.1"
extra
192.168.1.80
192.168.1.30
192.168.1.68
10 r_g
192.168.1.44
192.168.1.27
Reactions?
Two commands and we have a full dump of their
zone data!
Hey, check out that TXT record!
Which host appears to be the SysAdmin's
workstation?
Will other machines potentially trust this one more?
Maybe they all trust it for rsh-based backups
even?!!!!
Reactions? 2/2
Check out the HINFO records!
I note the SysAdmin's trusted box, running Red Hat 6.1.
I have a small kit of Red Hat 6.1 exploits -- which machine
should I try them on?
Defense to Zone Transfers
Should I really let everyone have this much
information?
Directives:
–
–
–
allow-transfer { };
allow-recursion { };
allow-query { };
Defense to Zone Transfers 2/2
Let's look at the named.conf file from before, this
time with a few additions!
named.conf.restricted_axfr 1/3
acl internal { 192.168.1.0/24 ; };
acl secondaries { 192.168.1.3 ; 192.168.2.3 ; };
options {
directory "/var/named/";
listen-on {192.168.1.2 ; };
allow-recursion { internal ; };
allow-query { internal ; };
allow-transfer { none; };
};
named.conf.restricted_axfr 2/3
zone "." {
type hint;
file "db.cache";
};
// bastille-linux.org maps to the 192.168.1.0/24 network
zone "bastille-linux.org" {
type master;
file "db.bastille-linux.org";
allow-query { any ; };
allow-transfer { secondaries; };
};
named.conf.restricted_axfr 3/3
zone "1.168.192.in-addr.arpa" {
type master;
file "db.192.168.1";
allow-query { any; };
allow-transfer { secondaries; };
};
zone "0.0.127.in-addr.arpa" {
type master;
file "db.127.0.0";
allow-query { 127.0.0.1 ; };
// Note: no one needs to get zone transfers of this one!
};
Additional Data Mining Defense
Notice those allow-query lines?
Those stop outside attackers from mining us
for data! They also fight cache poisoning.
We set default deny on queries, by specifying
this in our options block.
Additional Data Mining Defense
What about the allow-recursion lines?
These prevent outsiders from using our
nameservers to query for zones that we don't
run. Again, a defense for cache poisioning.
Cache Poisoning?
By taking over an authoritative nameserver, an
attacker obtains the ability to put data into our
nameserver's cache. He accomplish this, if he can
get us to ask his nameserver for information!
Remember that DNS is a distributed database.
The steps we're taking here attempt to minimize this
possibility.
Safe From Data Mining Yet?
[jay@max jay]$ dig @localhost dumb.target.jay hinfo
; <<>> DiG 8.2 <<>> @localhost dumb.target.jay hinfo
; (1 server found)
;; res options: init recurs defnam dnsrch
;; got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 6
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0,
ADDITIONAL: 0
;; QUERY SECTION:
;;
dumb.target.jay, type = HINFO, class = IN
(continued)
Nope.
;; ANSWER SECTION:
dumb.target.jay. 1D IN HINFO "Pentium 166" "Red Hat 6.1"
;; Total query time: 1 msec
;; FROM: max.fictional.attacker to
SERVER: localhost 127.0.0.1
;; WHEN: Sun Nov 12 00:17:08 2000
;; MSG SIZE sent: 33 rcvd 69
The Simple Solution?
Simple.
Don't give away so much information!
But how do we reconcile this with the need to
keep easy online data about hosts?
Two Choices
1) Remove all HINFO and TXT records.
Consider choosing less informative machine
names than sysadmin, printspool, and
intranet.
2) Implement Split Horizon DNS.
Basically, you maintain two separate DNS
servers, with two separate sets of data.
Split Horizon DNS 1/3
This is an overview:
Two DNS servers, generally separated via
a firewall/packet filter.
– Possibly both DNS servers are on the
same machine, which restricts external
hosts to the external BIND process.
– Possibly both DNS servers sit on your
firewall.
–
Split Horizon DNS 2/3
Internal DNS Server:
Only accepts requests from internal hosts.
– Possesses a richer zone database.
– Forwards all requests for external data to
the external DNS server.
– No zone transfers, unless we have other
internal DNS servers.
–
Split Horizon DNS 3/3
External DNS Server:
–Only does recursion for internal hosts, usually
only for internal DNS server.
–Possesses a sparser zone database.
" Potentially much sparse, if used w/ NAT.
–Zone transfers allowed from this host, but only
to the slave servers.
Playing the Attacker Some More
Cracking the DNS Server...
–BIND 8.2.0 and 8.2.1 was vulnerable to a
Remote Root exploit!
–Huge numbers of exploitable systems, when this
exploit was released. Red Hat 6.0, among many
others, shipped with one of these versions.
Cracking the DNS Server
The Cracker HOW-TO is available here:
http://www.enteract.com/~lspitz/NXT-Howto.txtBut
how does an attacker find vulnerable machines?
Finding Vulnerable DNS Servers
Try this command against one of your DNS servers:
dig @your_ns your_ns txt chaos version.bind
Here's the output against my test system:
Grabbing the BIND Version Number
; <<>> DiG 8.2 <<>> @dumb.target.jay dumb.target.jay
txt chaos version.bind
; (1 server found)
;; res options: init recurs defnam dnsrch
;; got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 6
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1,
AUTHORITY: 0, ADDITIONAL: 0
;; QUERY SECTION:
;; version.bind, type = TXT, class = CHAOS
;; ANSWER SECTION:
VERSION.BIND. 0S CHAOS TXT "8.2.2"
(truncated)
Security through Obscurity?
Security through Obscurity can be helpful,
though it should never be your only defense.
Against Script Kiddies, it can be extremely
effective, because of their Modus Operandi.
( see http://www.securityportal.com/topnews/tighten20000720.html)
We can obscure the version number through
the version directive in the options section
of named.conf.
named.conf Revisited
We'll just add one directive to the options block:
options {
directory "/var/named";
listen-on {192.168.1.2 ; };
allow-recursion { internal ; };
allow-query { internal ; };
allow-transfer { none; };
version "Go away!";
};
Go Away?
This is a judgment call. The script kiddies generally
use scanners that pattern-match. Your goal is to
not get matched.
At the same time, you may want to "blend in".
Suggestions:
version "9.0.0";
– version "4.9.7";
– version "8.3.0";
–
Other Defenses Against Cracking
Well, suppose a script kiddie gets lucky and tries an
attack, even though a scanner didn't pick you out?
Or, worse, suppose a more capable cracker comes
after you?
What defenses do you have?
Patch the Server!
As boring as this is, it's wholly necessary!
The BIND DNS server has had a number of security
problems. We believe it will have more. You must
continually patch/upgrade the server.
Follow the security announcements to know when it
is necessary.
Remote Root Vulnerability
Remember how we talked about a "remote root"
vulnerability?
You can't remove the "remote" part, but you can
remove the "root" part in a very simple way:
Don't run named as root!
The attacker will get access as an ordinary user
instead of superuser access!
Run as a Non-Root User 1/3
named -u dns_user -g dns_group
Create a separate user for the DNS server, with shell
equal to /bin/false.
# vipw /etc/passwd
dns:x:53:53:dns:/var/named:/bin/false
# vipw /etc/shadow
dns:NP:6445::::::
Run as a Non-Root User 2/3
named -u dns_user -g dns_group
Create a separate group for the DNS server, with
shell equal to /bin/false.
# echo "dns::53:dns" >> /etc/group
Run as a Non-Root User 3/3
Modify the named init script to use:
named -u dns -g dns
Major changes:
This forces the DNS server to drop root
privileges after binding to port 53.
DNS server won't be able to rebind to port 53,
when you send it a SIGHUP. When you make
config file changes, restart named.
–
–
What Did This Defense Do?
When the attacker uses that sort of exploit, he still
gets shell access on the machine. In this case,
though, he isn't root!
But wait, he has a great deal of access to walk the
filesystem, as much as an ordinary user. He might
be able to escalate privilege.
Reference:
http://www.securityportal.com/cover/coverstory20000626.html
Additional Defense
He'd escalate privilege by finding a Set-UID
program, or other program running as root, and
try to exploit it. If there was a vulnerable one on
the system that an ordinary user can run, he could
get root.
We can stop this by doing a Set-UID audit, but also
by cutting off his access to most of the filesystem.
Chroot the named process, and thus the attacker!
Chroot?
Short for "Change Root", where we change the root of the
process's filesystem. As an ordinary user, it shouldn't be
able to read files outside this root.
This can be difficult, unless you have someone
telling you how to do it ahead of time.
Chrooting BIND under Solaris
We have to build a functional subset of the
filesystem, with every program, library and data
file that named needs.
We'll choose very restrictive permissions, so that if
an attacker compromises named and gets user dns
access, he won't be able to change much.
(Note that the DESTLIB and DESTINC lines that we appended to the
Makefile.set file during our build make this slightly less hairy.)
Creating the Chroot Prison 1/6
Set up directories and permissions:
mkdir -p /chroot/named
chmod 111 /chroot
chmod 511 /chroot/named
cd /chroot/named
mkdir -p dev var/run/named var/tmp maps/master usr/lib \
/usr/local/etc usr/local/sbin usr/share/lib/zoneinfo/US
chmod -R 111 dev var maps usr
chmod 1711 var/tmp
/usr/ucb/chown -R root.root /chroot
Creating the Chroot Prison 2/6
Copy over binaries:
cp /usr/local/sbin/named{,-xfer} /chroot/named/usr/local/sbin
chmod 111 /usr/local/sbin/named{,-xfer}
/usr/ucb/chown root.root /usr/local/sbin/named{,-xfer}
Copy over Timezone files:
cp /usr/share/lib/zoneinfo/US/Eastern \
/chroot/named/usr/share/lib/zoneinfo/US
/usr/ucb/chown root.root /usr/share/lib/zoneinfo/US/Eastern
chmod 444 /usr/share/lib/zoneinfo/US/Eastern
Creating the Chroot Prison 3/6
Create devices:
cd /chroot/named/dev
mknod tcp c 11 42
mknod udp c 11 41
mknod conslog c 21 0
mknod log c 21 5
mknod null c 13 2
mknod zero c 13 12
/usr/ucb/chown root.root *
chgrp sys conslog null zero
chmod 666 tcp udp conslog log null zero
Creating the Chroot Prison 4/6
Determine necessary libraries:
# ldd /usr/local/sbin/named{,-xfer}
/usr/local/sbin/named:
libl.so.1 => /usr/lib/libl.so.1
libnsl.so.1 => /usr/lib/libnsl.so.1
libsocket.so.1 =>
/usr/lib/libsocket.so.1
libc.so.1 => /usr/lib/libc.so.1
libdl.so.1 => /usr/lib/libdl.so.1
libmp.so.2 => /usr/lib/libmp.so.2
/usr/platform/SUNW,Ultra-5_10/lib/libc_psr.so.1
/usr/local/sbin/named-xfer:
libl.so.1 => /usr/lib/libl.so.1
libnsl.so.1 => /usr/lib/libnsl.so.1
libsocket.so.1 =>
/usr/lib/libsocket.so.1
libc.so.1 => /usr/lib/libc.so.1
libdl.so.1 => /usr/lib/libdl.so.1
libmp.so.2 => /usr/lib/libmp.so.2
/usr/platform/SUNW,Ultra-5_10/lib/libc_psr.so.1 (example on Sol 2.7)
Creating the Chroot Prison 5/6
Copy over necessary libraries:
cp /usr/lib/libl.so.1 /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 \
/chroot/named/usr/lib
Additionally the following is necessary:
cp /usr/lib/ld.so.1 /usr/lib/nss_files.so.1 /chroot/named/usr/lib
And fix the permissions:
/usr/ucb/chown root.root /chroot/named/usr/lib/*
chmod 555 /chroot/named/usr/lib/*
Creating the Chroot Prison 6/6
Copy in the data files:
(Configuration File)
cp /usr/local/etc/named.conf /chroot/named/usr/local/etc/named.conf
/usr/ucb/chown root.root /chroot/named/usr/local/etc/named.conf
chmod 444 /chroot/named/usr/local/etc/named.conf
(Zone Files)
cp /var/run/named/db* /chroot/named/var/run/named/
/usr/ucb/chown root.root /chroot/named/var/run/named/db*
chmod 444 /chroot/named/var/run/named/db*
Running named chroot-ed
Try this:
chroot /chroot/named /usr/local/sbin/named -u dns -g dns
Alternatively:
/chroot/named/usr/local/sbin/named -u dns -g dns -t /chroot/named
Wrapping Up Chroot
Now, go modify your init script to work with the
new command line!
To harden the system slightly more, you might go
delete or "chmod 000 foo" the named executable.
Going Further
From here, you can look toward Split Horizon
DNS. If you combine this with chroot'd named,
we'd suggest the following:
"Run
each instance of named in it's own chroot'd environment.
"Run
each instance of named as a separate user.
"Use
NAT to have your internal hosts appear as a single host. This allows
serious sparsity in your external DNS tables.
Going Even Further
Go read the DNS and BIND O'Reilly book, by Paul
Albitz and Cricket Liu. While this talk covers best
practices and puts you way ahead of the game,
there is nothing that compares with a deep
understanding of the Basics.
Off the Beaten Path...
Not for the timid:
djbdns
Daniel Bernstein's DNS server, made to compete
with BIND.
Much safer design than BIND -- break out
functions into small programs with less privilege.
Less Privilege?
Instead of a central program, we have several
smaller ones:
dnscache
Local site caching-nameserver, but answers no
queries for authoritative zones
Less Privilege? 2/2
tinydns
Authoritative nameserver to answer queries about
our specific machines
axfrdns / axfrget
Responsible for serving and getting zone transfers
Setting up djbdns
Kuro5hin.org has an automated setup script in a
great article:
http://www.kuro5hin.org/?op=displaystory;sid=200
1/4/9/17053/40631
Security?
djbdns does much of what we do here very easily:
1) All servers run by default as a non-root user
2) All servers run chrooted, by default, in their own
directories
3) djbdns hasn't had a security hole and promises a
$500 prize to the finder of the first one
Security 2/3?
djbdns does much of what we do here very easily:
4) walldns -- generates generic forward/reverse
information to feed to outside servers, like this:
1.2.3.4 --rev--> 4.3.2.1.in-addr.arpa
4.3.2.1.in-addr-arpa --> 1.2.3.4
Security 3/3?
djbdns does much of what we do here very easily:
5) Queries for other people's domains are
automatically restricted, since tinydns won't answer
them -- this is the internal dnscache's job
6) It's darn easy, by design, to go split horizon with
djbdns.
Should You Use It?
PRO: Much better security history than BIND
PRO: Much better architecture for security
CON: Can you sell your boss on the switch?
PRO: Relatively easy to set up split-horizon DNS
CON: Relatively difficult to configure and use, as
few people have the experience or training
OTOH: http://cr.yp.to/djbdns/ad/easeofuse.html
Do I like it? Heck yeah!
Wrap Up
Go learn more about this stuff!
DNS Servers are extremely important in
maintaining the security of your organization.
THINK about this one for a minute.
BIND vulnerabilities are coming out too quickly...
Speaker Bio
Jay Beale is the Lead Developer of Bastille Linux
and the Security Team Director for Linux
Mandrake. He writes a column for
SecurityPortal.com and is currently working on a
book on Securing Linux and Unix for Addison
Wesley. Read more of his articles on:
http://www.bastille-linux.org/jay