Securing BIND DNS server

  Security, System
 

The DNS is a critical service often exploited by hackers for gathering information about the company attacked or for distributed deny of service (DDOS).

It’s possible to be protected from these attacks configuring opportunely the service. The actions to implement are very easy and it will be explained in this article.

The laboratory implemented is described in the following picture.

secure bind

As showed above, we imagine that the dns service is reachable from internet for resolving the names of the example.com domain and queried from a inside network for internal resolution.

This architecture is enough  to synthesize the greater part of possible requirements.

Let’s start with the bind installation.

DNS Bind Installation

For improving the security the bind-chroot will be installed with selinux enabled.

Selinux is a layer security that must be always used. A lot of administrators prefer to disable it because they think that it difficult to manage: it’s not true and in internet it’s possible to find a lot of useful forum for resolving problems.

With chroot-bind, even if the bind server is exploited (this scenario is always possible, in the 2016 a lot of vulnerabilties have been discovered on it) the attacker has privilige limited (selinux) in a reduced file system (chroot) for exploiting the server.

Following the commands for installation chroot-bind and configure selinux (the server is a Centos 7.2):

[root@bind-server chroot]# sestatus|grep enabled
SELinux status: enabled
[root@bind-server chroot]# yum install bind-chroot
[root@bind-server chroot]# /usr/libexec/setup-named-chroot.sh /var/named/chroot on
[root@bind-server chroot]# systemctl enable named-chroot
[root@bind-server chroot]# systemctl start named-chroot

By default, named is not allowed by the SELinux policy to write, create or delete any files except in these directories:

/var/named/chroot/var/named/slaves
/var/named/chroot/var/named/data
/var/named/chroot/var/tmp

From the moment that the zone example.com will be signed using DNSSEC it’s necessary to create it in a place where named daemon has write permissions and data directory it’s ok.

Following is showed the context of data directory and the domain named_t of daemon bind that has write permission on it (default selinux configuration):

[root@bind-server name]# ps -afeZ |grep named
system_u:system_r:named_t:s0 named 15464 1 0 14:26 ? 00:00:00 /usr/sbin/named -u named -t /var/named/chroot
[root@bind-server named]# ls -ltrZ |grep data
drwxrwx—. named named system_u:object_r:named_cache_t:s0 data
[root@bind-server named]# sesearch –allow –source named_t –target named_cache_t –class file
Found 1 semantic av rules:
allow named_t named_cache_t : file { ioctl read write create getattr setattr lock append unlink link rename open } ;

No change on selinux was necessary: as I told it’s easy to work with it.

Note that the named daemon is running with named user privileges as chrooting a process running as root doesn’t enhance security because it’s possible to escape a chroot jail.

[root@bind-server ~]# ps -afe |grep named
named 19865 1 0 Jan03 ? 00:00:00 /usr/sbin/named -u named -t /var/named/chroot

Now the bind server is up&running: let’s start to configure it

DNS Bind Configuration

The configuration file of bind server is /etc/named.conf (this file is mounted with –bind in /var/named/chroot/etc/named.conf).

The default configuration has the dnssec resolution enabled. The configuration that enables it is:

root@bind-server etc]# more named.conf |grep dnssec
dnssec-enable yes;
dnssec-validation yes;

The dnssec is a protocol that adds a layer of security by answers digital signature into DNS data. Each DNS response can be verified for integrity. You can find a lot of information about it in https://users.isc.org/~jreed/dnssec-guide/dnssec-guide.html.

With DNSSEC the answers received contain digital signature for message integrity and authentication: the bind server is protected against cache poisoning or forged anwsers.

With the configuration above, the resolver of the bind verifies automatically the integrity of answers received. The flags ‘ad‘ received confirms that the validation process has been completed correctly (below the domain www.isc.org is signed, the same query against a domain not signed will not produce any data signed and any ad flags):

root@bind-serer chroot]# dig @192.168.0.2 www.isc.org. A +dnssec +multiline
; <<>> DiG 9.9.4-RedHat-9.9.4-38.el7_3 <<>> @192.168.0.2 www.isc.org. A +dnssec +multiline
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 56353
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 5, ADDITIONAL: 13
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;www.isc.org. IN A
;; ANSWER SECTION:
www.isc.org. 60 IN A 149.20.64.69
www.isc.org. 60 IN RRSIG A 5 3 60 (
20170201234103 20170102234103 13953 isc.org.
VdASEfm2i00N18nTAa8/gJsaATgeggxckCLieWrsUfKJ
ih0Eet+FIZ3oU4HK5Ag9PAh5CPFzk3a7yXxe804PgGGX
SP2+B7WY3EVW5Vr7Qq66OkZ+y85lHkPVni60G+F7GiFT
cTTd0sC+mowXck2l5FE2waS78UW7scHUv1/I99k= )

In this way the internal network is protected against attempts to forge the dns answers. Of course the domain queried must be signed.

This picture describe the scenario with the role of dnssec protection:

DNSSEC Protection

DNSSEC doesn’t protect completely the client because the SO and the browser are not dnssec aware. If a malicious user forges the dns aswers, the browsers doesn’t check the validity signature as resolvers does. If all the world (domain signed, SO, browser and resolvers) was dnssec aware, would be impossible main in the middle attacks in the dns service: unfortunately it’s not so.

If it’s possible, I suggest to sign the public zone: in this way you will protect other resolvers against attempts to forge your dns answers improving the security in internet.

Below I will explain how to do for signing the public view of the example.com zone.

First: create the keys useful for signing the zone. The keys created are two: one is user for signing the records, the other is used for signing the public key released to resolvers

[root@bind-server named]# mkdir -p /var/named/chroot/var/named/keys/example.com
[root@bind-server named]# chown -R named:named /var/named/chroot/var/named/keys
[root@bind-server named]# cd /var/named/chroot/var/named/keys/example.com
[root@bind-server named]# dnssec-keygen -a RSASHA256 -b 1024 example.com
Generating key pair….++++++ ….++++++
Kexample.com.+008+27006
[root@bind-server named]# dnssec-keygen -a RSASHA256 -b 2048 -f KSK example.com
Generating key pair………+++ ..+++

Next step: For completing the signing zone is necessary to call the parent zone for completing the chain of trust (for this step see https://users.isc.org/~jreed/dnssec-guide/dnssec-guide.html#working-with-parent-zone).

Let’s start now to create a internal view for serving all the dns request from inside network. This network generally has the recursive functionality enabled and other custom configuration: the public server, for example, can be resolved with its private ip address instead of public.

The final bind configuration becomes:

[root@bind-server named]# vi /etc/named.conf
options {
listen-on port 53 { 192.168.0.2; };
listen-on-v6 port 53 { ::1; };
directory “/var/named”;
dump-file “/var/named/data/cache_dump.db”;
statistics-file “/var/named/data/named_stats.txt”;
memstatistics-file “/var/named/data/named_mem_stats.txt”;
dnssec-enable yes;
dnssec-validation auto;
/* Path to ISC DLV key */
bindkeys-file “/etc/named.iscdlv.key”;
managed-keys-directory “/var/named/dynamic”;
pid-file “/run/named/named.pid”;
session-keyfile “/run/named/session.key”;
};
acl inside-networks {
192.168.0.0/24;
127.0.0.1;
};
view “internal” {
match-clients { inside-networks; };
allow-query { any; };
recursion yes;
allow-transfer { none;};
zone “example.com” IN {
type master;
file “data/internal.example.com.db”;
};
zone “.” IN {
type hint;
file “named.ca”;
};
include “/etc/named.rfc1912.zones”;
include “/etc/named.root.key”;
};
view “public” {
match-clients { any; };
allow-query { any; };
recursion no;
allow-transfer { none;};
zone “example.com” IN {
type master;
file “data/public.example.com.db”;
key-directory “keys/example.com”;
inline-signing yes;
auto-dnssec maintain;
};
};
[root@bind-server named]#systemctl reload named

If everything is ok, the dig command from internet must return the records signed:

[root@docker-test-02 ~]# dig -t A www.example.com +dnssec +multiline @164.132.193.215
; <<>> DiG 9.9.4-RedHat-9.9.4-29.el7_2.3 <<>> -t A www.example.com +dnssec +multiline @164.132.193.215
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 51435
;; flags: qr aa rd; QUERY: 1, ANSWER: 2, AUTHORITY: 2, ADDITIONAL: 3
;; WARNING: recursion requested but not available
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;www.example.com. IN A
;; ANSWER SECTION:
www.example.com. 3600 IN A 164.132.193.215
www.example.com. 3600 IN RRSIG A 8 3 3600 (
20170202104548 20170103103948 60903 example.com.
qjysInYFO5awajcpWj5iGuvX+2S4txvkh46oYIWVwIZW
DKc+iRKjNNUGe1dlfNiAnSNxCZ8U5eYgK6fQ0PZNSm7b
3QCXlQurRobJzRZyCugJDHcCyj7Ap9Vx3qsiDcZLEsMY
B8wDW35N4y8IuJlw3GLj/rqwCg+VF2AQ1WKwltA= )
;; AUTHORITY SECTION:
example.com. 3600 IN NS ns1.example.com.
example.com. 3600 IN RRSIG NS 8 2 3600 (
20170202104548 20170103103948 60903 example.com.
a0+ddvuRZ/a28lmfppUsTXNGHnY9tKCFn4ObP9EEdqaK
yQY4pNvZinTA2tqPTLjiSMtQtHUo/HvG5jwVwxQSoeqC
sfqoGaWOkJdTZBtTBY2Q6Puik5SYBkrpoSW7s4zvNBp8
ia00syW5J9ZetBPQcS/5WSsTjtvWDjmkurcDwDA= )
;; ADDITIONAL SECTION:
ns1.example.com. 3600 IN A 164.132.193.215
ns1.example.com. 3600 IN RRSIG A 8 3 3600 (
20170202104548 20170103103948 60903 example.com.
Pu5uHlw7hoqabYQPYcEO4jIAiTKUkYVRdqRPbRRXcZsF
zyQH5ibyIWveP6NSeLHqmNV4SQoaUJIv2Netp4VtrY1Y
+o95CVQWpdnI3BgrZT/UTqpsQqzJWinZ8/DmPw0mG777
SZjoklgEs53RrlO1qOp/TXauynkc07mFA4K1U7Q= )

Security final considerations:

  1. Two view have been created. In the public view the recursive is disabled. If you want to be a recursive dns for internet, you can be used for DDOS attack. In this case I suggest to limit the query served configuring the iptables of the server with a rule like that:”ACCEPT     udp  —  anywhere             anywhere             udp dpt:domain limit: up to x/min burst y mode src” .This rule limit the dns query to x/min with a burst of y (y> x).
  2. Allow transfer zone has been disabled in both view. If it is enabled, a malicious user can transfer the zone information from the server. This should contain the ip address of bind slave in case of a bind master-slave configuration. In this case the bind-slave can ask to master to download the zone.
  3. I configured dnssec-validation to auto as suggested by ISC :DNSSEC validation is enabled, and a default trust anchor (included as part of BIND) for the DNS root zone is used automatically. Read paragraph 3.3.1 (https://users.isc.org/~jreed/dnssec-guide/dnssec-guide.html)
  4. With the “auto-dnssec maintain” option enabled, BIND will periodically check to see if new keys are available, or old keys need to be retired, and automatically add or remove the appropriate DNSKEY records from the zone.
  5. Allow query is any for both the view because any client can query the dns service.
  6. Before putting live the service, don’t forget to run some penetration testing with some dns scanner like dnsmap or dnsenum. The results are good in this case:

root@kali:~# dnsmap example.com
dnsmap 0.30 – DNS Network Mapper by pagvac (gnucitizen.org)
[+] searching (sub)domains for example.com using built-in wordlist
[+] using maximum random delay of 10 millisecond(s) between requests
ns1.example.com
IP address #1: 164.132.193.215
www.example.com
IP address #1: 164.132.193.215
[+] 2 (sub)domains and 2 IP address(es) found
[+] completion time: 171 second(s)
root@kali:~# dnsenum example.com
—– example.com —–
Host’s addresses:_______________
Name Servers:__________
ns1.example.com. 3600 IN A 164.132.193.215
Mail (MX) Servers:_______________
Trying Zone Transfers and getting Bind Versions:_____________________________________________
Trying Zone Transfer for example.com on ns1.example.com …
AXFR record query failed: connection failed

Conclusions

In this article I showed how to secure bind dns server using dnssec, selinux and a view configuration (public and internal).

Another suggestion is to always have system operation and bind upgraded to last version available: as I told on bind server this year a lot of vulnerabilties was found and the only way to protect is upgrade the software.

The last suggestion is to monitor the exploits about bind on exploit-db in order to verify if there is some exploits for the bind server and test it if possible:

Let me know for any question or suggestion.

Best Regards

LEAVE A COMMENT