Categories
SecOps

How to protect Samba DNS server against DNS zone transfer

Debian Bullseye currently provides Samba 4.13.5. Using BIND as Samba Active Directory DNS backend opens it to the DNS zone transfer.

This issue is fixed in Samba 4.15.0 and can be configured using Samba configuration option dns zone transfer clients allow, which default behavior is to deny such requests, but it is not packaged at this moment.

The issue

Operating system.

$ lsb_release -a
No LSB modules are available.
Distributor ID: Debian
Description:    Debian GNU/Linux 11 (bullseye)
Release:        11
Codename:       bullseye

Samba version.

$ samba --version
Version 4.13.5-Debian

Issue can be easily verified using dig utility from remote server.

$ dig AXFR octocat.lab
; <<>> DiG 9.16.15-Debian <<>> AXFR octocat.lab                                                                                                                                                                                                                 
;; global options: +cmd                                                                                                                                                                                                                                         
octocat.lab.            3600    IN      SOA     ad.octocat.lab. hostmaster.octocat.lab. 3 900 600 86400 3600                                                                                                                                                    
octocat.lab.            900     IN      NS      ad.octocat.lab.                                                                                                                                                                                                 
octocat.lab.            900     IN      A       10.10.10.10                                                                                                                                                                                                     
voyager.octocat.lab.    3600    IN      A       10.10.1.18                                                                                                                                                                                                      
_kerberos._udp.octocat.lab. 900 IN      SRV     0 100 88 ad.octocat.lab.                                                                                                                                                                                        
_ldap._tcp.Default-First-Site-Name._sites.DomainDnsZones.octocat.lab. 900 IN SRV 0 100 389 ad.octocat.lab.                                                                                                                                                      
ad.octocat.lab.         3600    IN      A       10.10.10.10                                                                                                                                                                                                     
ForestDnsZones.octocat.lab. 900 IN      A       10.10.10.10                                                                                                                                                                                                     
_ldap._tcp.Default-First-Site-Name._sites.ForestDnsZones.octocat.lab. 900 IN SRV 0 100 389 ad.octocat.lab.                                                                                                                                                      
_msdcs.octocat.lab.     900     IN      NS      ad.octocat.lab.                                                                                                                                                                                                 
_ldap._tcp.ForestDnsZones.octocat.lab. 900 IN SRV 0 100 389 ad.octocat.lab.                                                                                                                                                                                     
DomainDnsZones.octocat.lab. 900 IN      A       10.10.10.10                                                                                                                                                                                                     
_kpasswd._udp.octocat.lab. 900  IN      SRV     0 100 464 ad.octocat.lab.                                                                                                                                                                                       
_ldap._tcp.Default-First-Site-Name._sites.octocat.lab. 900 IN SRV 0 100 389 ad.octocat.lab.                                                                                                                                                                     
_kpasswd._tcp.octocat.lab. 900  IN      SRV     0 100 464 ad.octocat.lab.                                                                                                                                                                                       
_gc._tcp.Default-First-Site-Name._sites.octocat.lab. 900 IN SRV 0 100 3268 ad.octocat.lab.                                                                                                                                                                      
_gc._tcp.octocat.lab.   900     IN      SRV     0 100 3268 ad.octocat.lab.                                                                                                                                                                                      
_kerberos._tcp.octocat.lab. 900 IN      SRV     0 100 88 ad.octocat.lab.                                                                                                                                                                                        
_ldap._tcp.DomainDnsZones.octocat.lab. 900 IN SRV 0 100 389 ad.octocat.lab.                                                                                                                                                                                     
_ldap._tcp.octocat.lab. 900     IN      SRV     0 100 389 ad.octocat.lab.                                                                                                                                                                                       
_kerberos._tcp.Default-First-Site-Name._sites.octocat.lab. 900 IN SRV 0 100 88 ad.octocat.lab.                                                                                                                                                                  
octocat.lab.            3600    IN      SOA     ad.octocat.lab. hostmaster.octocat.lab. 3 900 600 86400 3600                                                                                                                                                    
;; Query time: 0 msec                                                                                                                                                                                                                                           
;; SERVER: 10.10.10.10#53(10.10.10.10)                                                                                                                                                                                                                          
;; WHEN: Sun Oct 03 20:09:59 CEST 2021
;; XFR size: 22 records (messages 1, bytes 1106)
$ dig AXFR 10.10.in-addr.arpa
; <<>> DiG 9.16.15-Debian <<>> AXFR 10.10.in-addr.arpa
;; global options: +cmd
10.10.in-addr.arpa.     3600    IN      SOA     ad.octocat.lab. hostmaster.octocat.lab. 3 900 600 86400 3600
10.10.in-addr.arpa.     3600    IN      NS      ad.octocat.lab.
10.10.10.10.in-addr.arpa. 3600  IN      PTR     ad.octocat.lab.
18.1.10.10.in-addr.arpa. 3600   IN      PTR     voyager.octocat.lab.
10.10.in-addr.arpa.     3600    IN      SOA     ad.octocat.lab. hostmaster.octocat.lab. 3 900 600 86400 3600
;; Query time: 0 msec
;; SERVER: 10.10.10.10#53(10.10.10.10)
;; WHEN: Sun Oct 03 18:31:08 CEST 2021
;; XFR size: 5 records (messages 1, bytes 269)

There is no easy way to block this as the configuration is provided by the dynamically loadable zones.

The solution

The solution is to use a DNS load balancing utility to inspect passing queries.

$ apt info dnsdist
Package: dnsdist
Version: 1.5.1-3
Priority: optional
Section: net
Maintainer: dnsdist packagers 
Installed-Size: 6,833 kB
Pre-Depends: init-system-helpers (>= 1.54~)
Depends: adduser, libc6 (>= 2.25), libcap2 (>= 1:2.10), libcdb1, libedit2 (>= 2.11-20080614-0), libfstrm0 (>= 0.4.0), libgcc-s1 (>= 3.0), libh2o-evloop0.13 (>= 2.2.5+dfsg2), liblmdb0 (>= 0.9.7), libluajit-5.1-2 (>= 2.0.4+dfsg), libprotobuf23 (>= 3.12.3), libre2-9 (>= 20131024+dfsg), libsnmp40 (>= 5.9+dfsg), libsodium23 (>= 1.0.12), libssl1.1 (>= 1.1.1), libstdc++6 (>= 9), libsystemd0
Homepage: https://dnsdist.org
Tag: uitoolkit::ncurses
Download-Size: 1,671 kB
APT-Manual-Installed: yes
APT-Sources: http://ftp.task.gda.pl/debian bullseye/main amd64 Packages
Description: DNS loadbalancer
 Highly DoS- and abuse-aware load balancing tool for DNS traffic,
 with Lua scripting and configuration capability.
 Can be configured to use various sets of rules to classify, route
 and reject traffic.

Install DNS load balancer.

$ sudo apt install dnsdist

Disable it immediately, as there is a BIND running.

$ sudo systemctl disable --now dnsdist

Update BIND configuration to listen on 127.0.0.1 port 54.

$ cat  /etc/bind/named.conf.options
options {
        directory "/var/cache/bind";

        // If there is a firewall between you and nameservers you want
        // to talk to, you may need to fix the firewall to allow multiple
        // ports to talk.  See http://www.kb.cert.org/vuls/id/800113

        // If your ISP provided one or more IP addresses for stable 
        // nameservers, you probably want to use them as forwarders.  
        // Uncomment the following block, and insert the addresses replacing 
        // the all-0's placeholder.

        // forwarders {
        //      0.0.0.0;
        // };

        //========================================================================
        // If BIND logs error messages about the root key being expired,
        // you will need to update your keys.  See https://www.isc.org/bind-keys
        //========================================================================
        dnssec-validation auto;

        listen-on port 54 { 127.0.0.1; };

        tkey-gssapi-keytab "/var/lib/samba/bind-dns/dns.keytab";
};

Create a simple configuration to block AXFR and IXFR DNS queries.

$ cat /etc/dnsdist/dnsdist.conf
-- dnsdist configuration file

-- disable security status polling via DNS
setSecurityPollSuffix("")

-- listen address
addLocal('10.10.10.10:53')

-- allow queries from
setACL({'10.10.0.0/16'})

-- backend server
newServer("127.0.0.1:54")

-- log every query type AXFR, IXFR
addAction(OrRule({QTypeRule(DNSQType.AXFR), QTypeRule(DNSQType.IXFR)}), LogAction("",false,false,true,false,false))

-- drop every qurty type AXFR, IXFR
addAction(OrRule({QTypeRule(DNSQType.AXFR), QTypeRule(DNSQType.IXFR)}), RCodeAction(DNSRCode.REFUSED))

Alternatively, drop these packets with an exception of trusted servers.

$ cat /etc/dnsdist/dnsdist.conf
-- dnsdist configuration file

-- disable security status polling via DNS
setSecurityPollSuffix("")

-- listen address
addLocal('10.10.10.10:53')

-- allow queries from
setACL({'10.10.0.0/16'})

-- backend server
newServer("127.0.0.1:54")

-- log every query type AXFR, IXFR
addAction(OrRule({QTypeRule(DNSQType.AXFR), QTypeRule(DNSQType.IXFR)}), LogAction("",false,false,true,false,false))

-- drop every query type SOA, AXFR, IXFR with exception of trusted servers
trusted_servers = newNMG()
trusted_servers:addMask("10.10.10.254/32")
addAction(
  AndRule({
    NotRule(NetmaskGroupRule(trusted_servers)),
    OrRule({QTypeRule(DNSQType.AXFR), QTypeRule(DNSQType.IXFR)})
  }), 
  DropAction()
)

Check configuration.

$ dnsdist --check-config
Configuration '/etc/dnsdist/dnsdist.conf' OK!

Restart BIND service.

$ sudo systemctl restart named

Start and enable DNS load balancer.

$ systemctl enable --now dnsdist

Inspect logs.

$ sudo journalctl -u dnsdist -f
-- Journal begins at Mon 2021-09-27 01:18:13 CEST. --
Oct 03 21:23:32 ad.octocat.lab systemd[1]: Starting DNS Loadbalancer...
Oct 03 21:23:32 ad.octocat.lab dnsdist[4623]: Configuration '/etc/dnsdist/dnsdist.conf' OK!
Oct 03 21:23:32 ad.octocat.lab dnsdist[4623]: Configuration '/etc/dnsdist/dnsdist.conf' OK!
Oct 03 21:23:32 ad.octocat.lab dnsdist[4624]: Added downstream server 127.0.0.1:54
Oct 03 21:23:32 ad.octocat.lab dnsdist[4624]: Listening on 10.10.10.10:53
Oct 03 21:23:32 ad.octocat.lab dnsdist[4624]: dnsdist 1.5.1 comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it according to the terms of the GPL version 2
Oct 03 21:23:32 ad.octocat.lab dnsdist[4624]: ACL allowing queries from: 10.10.0.0/16
Oct 03 21:23:32 ad.octocat.lab dnsdist[4624]: Console ACL allowing connections from: 127.0.0.0/8, ::1/128
Oct 03 21:23:32 ad.octocat.lab dnsdist[4624]: Marking downstream 127.0.0.1:54 as 'up'
Oct 03 21:23:32 ad.octocat.lab systemd[1]: Started DNS Loadbalancer.
Oct 03 21:24:18 ad.octocat.lab dnsdist[4624]: Packet from 10.10.1.18:40479 for octocat.lab. AXFR with id 44288
Oct 03 21:24:18 ad.octocat.lab dnsdist[4624]: Packet from 10.10.1.18:59475 for octocat.lab. AXFR with id 53945
[...]

Sample drop action from client perspective.

$ dig AXFR octocat.lab
;; communications error to 10.10.10.10#53: end of file

;; communications error to 10.10.10.10#53: end of file

Sample refused action from client perspective.

$ dig AXFR octocat.lab
; <<>> DiG 9.16.15-Debian <<>> AXFR octocat.lab
;; global options: +cmd
; Transfer failed.

dnsdist is so cool!