Quantcast
Channel: Weberblog.net
Viewing all 338 articles
Browse latest View live

Palo Alto DNS Proxy Rule for Reverse DNS

$
0
0
Palo Alto DNS Proxy Rule featured image

I am using the DNS Proxy on a Palo Alto Networks firewall for some user subnets. Beside the default/primary DNS server it can be configured with proxy rules (sometimes called conditional forwarding) which I am using for reverse DNS lookups, i.e., PTR records, that are answered by a BIND DNS server. While it is easy and well-known to configure the legacy IP (IPv4) reverse records, the IPv6 ones are slightly more difficult. Fortunately there are some good tools on the Internet to help reversing IPv6 addresses.

I am using a PA-200 with PAN-OS 7.1.2. The BIND server runs on a Ubuntu 12.04.5 LTS with BIND version 9.8.1-P1. For some general information about DNS reverse lookups, use this Wikipedia article. Similar for the notation of IPv6 address in the DNS.

DNS Proxy Rule

This is the configuration of my DNS Proxy with one proxy rule for the reverse lookups. Note that the connections from the Palo Alto to the DNS servers are established via IPv6 though the bulk of DNS lookups is still IPv4 (A records).

Palo Alto DNS Proxy Rule 01

These are the four “domain names” I configured. The first three are the well-known legacy IP reverse zones (RFC1918) while the last one is my /48 global unicast IPv6 subnet.

*.168.192.in-addr.arpa
*.16.172.in-addr.arpa
*.10.in-addr.arpa
*.2.1.0.6.1.5.0.0.3.0.0.2.ip6.arpa

Now all DNS queries are primarily sent to DNS server at 2003:51:6012:120::a08:53, while the reverse DNS (rDNS) lookups are sent to 2003:51:6012:120::11.

BIND Zone

I am using a BIND server for my reverse zones. I am using this tool to generate the IPv6 zone file as well as this for further IPv6 PTR records. These are two of the four zones configured within the “named.conf.local” configuration file:

zone "168.192.in-addr.arpa" {
  type master;
  file "/etc/bind/db.168.192";
};

zone "2.1.0.6.1.5.0.0.3.0.0.2.ip6.arpa" {
  type master;
  file "/etc/bind/db.2.1.0.6.1.5.0.0.3.0.0.2";
};

And this is part of my /48 zone for IPv6 PTR records, generated with the tool just mentioned:

weberjoh@jw-vm10:/etc/bind$ cat db.2.1.0.6.1.5.0.0.3.0.0.2
;
; 2003:51:6012::/48
;
; Zone file built with the IPv6 Reverse DNS zone builder
; http://rdns6.com/
;
$TTL 1h ; Default TTL
@       IN      SOA     jw-vm10.webernetz.net.  webmaster.webernetz.net. (
        2016061401      ; serial
        1h              ; slave refresh interval
        15m             ; slave retry interval
        1w              ; slave copy expire time
        1h              ; NXDOMAIN cache time
        )

;
; domain name servers
;
@       IN      NS      jw-vm10.webernetz.net.


; IPv6 PTR entries
; 110
1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.1.0.2.1.0.6.1.5.0.0.3.0.0.2.ip6.arpa. IN PTR fd-wv-fw01-dmz.webernetz.net.
9.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.1.0.2.1.0.6.1.5.0.0.3.0.0.2.ip6.arpa. IN PTR jw-nb12-lx.webernetz.net.
2.1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.1.0.2.1.0.6.1.5.0.0.3.0.0.2.ip6.arpa. IN PTR jw-vm06-planes.webernetz.net.
5.1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.1.0.2.1.0.6.1.5.0.0.3.0.0.2.ip6.arpa. IN PTR jw-esa.webernetz.net.
7.1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.1.0.2.1.0.6.1.5.0.0.3.0.0.2.ip6.arpa. IN PTR f5-external.webernetz.net.
0.2.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.1.0.2.1.0.6.1.5.0.0.3.0.0.2.ip6.arpa. IN PTR jw-ts01-perle.webernetz.net.
2.2.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.1.0.2.1.0.6.1.5.0.0.3.0.0.2.ip6.arpa. IN PTR jw-vm16-ns1.weberdns.de.
2.d.3.5.3.0.e.f.f.f.7.7.3.1.2.0.0.1.1.0.2.1.0.6.1.5.0.0.3.0.0.2.ip6.arpa. IN PTR jw-nb04-ftp-adsb.webernetz.net.

Test ‘n Wireshark

This is a basic test from a Windows 7 client behind one of the user subnets on the Palo Alto. It uses the IPv4 address of the Palo Alto layer 3 interface (192.168.125.1) for DNS queries. I tested a normal DNS name

blog.webernetz.net
  as well as a private/RFC1918 IPv4 address
192.168.100.0
 . (Yes, in this case the *.0 IPv4 address is not the network address but a real address.)
C:\Users\weberjoh>nslookup
Standardserver:  pa-user.webernetz.net
Address:  192.168.125.1

> blog.webernetz.net
Server:  pa-user.webernetz.net
Address:  192.168.125.1

Nicht autorisierende Antwort:
Name:    blog.webernetz.net
Addresses:  2a01:488:42:1000:50ed:8588:8a:c570
          80.237.133.136

>
>
> 192.168.100.0
Server:  pa-user.webernetz.net
Address:  192.168.125.1

Name:    nc-client-0.webernetz.net
Address:  192.168.100.0

>
>

Captured on the Palo Alto (Monitor -> Packet Capture), these are two screenshots from Wireshark that show the connections to the different DNS servers for the different use cases. In any case, the queries from the Palo Alto are made from the appropriate layer 3 interfaces with the corresponding IPv6 addresses, in my case 2003:51:6012:125::1, etc.:

DNS queries from the DNS Proxy to the primary DNS server. Queries to the reverse DNS server with only certain PTR records.

Some Notes

For more information about the DNS proxy use this Palo Alto Networks article: How to Configure DNS Proxy on a Palo Alto Networks Firewall.

Also note that during some configuration changes (commits) on the Palo Alto, the DNS proxy was not working anymore at all! The only way to bring it back to life was to restart the process from the CLI on the Palo:

debug software restart process dnsproxy

Cheers.


Basic BIND Installation

$
0
0
Basic BIND Installation - featured image

This is a basic tutorial on how to install BIND, the Berkeley Internet Name Domain server, on a Ubuntu server in order to run it as an authoritative DNS server. It differs from other tutorials because I am using three servers (one as a hidden primary and two slaves as the public accessible ones), as well as some security such as denying recursive lookups and public zone transfers, as well as using TSIG for authenticating internal zone transfers. That is, this post is not an absolute beginner’s guide.

The basic environment looks like that. Note that I am showing my real IP addresses. Don’t be confused about that and change them to your IPs accordingly:

BIND weberdns.de Servers Master and Slaves

Some notes about the installation of the servers:

  • My domain for these test servers is weberdns.de.
  • The main motivation for the hidden primary approach comes from DNSSEC (will be published later), in which I am managing the keys only on the hidden primary but not on the slaves. No single access is possible from the public Internet to this server.
  • I am using only the private IPv4 or global IPv6 addresses through site-to-site VPN tunnels in order to transfer the zones between the DNS servers. This brings encryption when traversing the Internet, as well as appropriate security policies on the intermediate firewalls.
  • By default, each server sends notifications to all other NS servers in case of a zone change. In my case, the notifications are set to “explicit” to only notify the private IPv4 addresses specified in the zone configuration “also-notify { };” and not the public ones.
  • TSIG is used in order to authenticate the zone transfers (even though not really mandatory since I am using VPN tunnels anyway). For each slave, I am using an unique key.
  • Public zone transfers (AXFR) are disabled globally. Only servers that authenticated with their key within the “allow-transfer { };” statement are allowed to transfer the zone.
  • Per-zone statistics are enabled on all servers.
  • I am using Ubuntu servers version 14.04 LTS either on VMs or on hardware. Of course they have static (NATted) IPv4 and IPv6 addresses. The bind9 package from Ubuntu at the time of writing is version 9.9.5-3ubuntu0.8-Ubuntu (June 2016).

BIND Installation

To install the BIND package simply use the following two statements:

sudo apt-get update
sudo apt-get install bind9

All configuration files are stored in the folder

/etc/bind/
 .

The started process is called “named“. It listens on udp and tcp port 53, each for IPv4 and IPv6:

weberjoh@jw-vm07-ns1:~$ sudo netstat -tulpen | grep named
tcp        0      0 192.168.110.25:53       0.0.0.0:*               LISTEN      106        480821      4703/named
tcp        0      0 127.0.0.1:53            0.0.0.0:*               LISTEN      106        480819      4703/named
tcp        0      0 127.0.0.1:953           0.0.0.0:*               LISTEN      106        480822      4703/named
tcp6       0      0 :::53                   :::*                    LISTEN      106        480814      4703/named
tcp6       0      0 ::1:953                 :::*                    LISTEN      106        480823      4703/named
udp        0      0 192.168.110.25:53       0.0.0.0:*                           106        480820      4703/named
udp        0      0 127.0.0.1:53            0.0.0.0:*                           106        480818      4703/named
udp6       0      0 :::53                   :::*                                106        480813      4703/named

To view syslog messages, grep for the “named” process:

tail -f /var/log/syslog | grep named

 

Master

The master server is the one on which the zone files are maintained. At first, some options are set to secure the authoritative server. These are set within the named.conf.options file (in the /etc/bind/ folder).

sudo nano named.conf.options

Add the following options:

// per zone statistics
	zone-statistics yes;

	// no recursion at all
	recursion no;

	// no transfer afxr by default
	allow-transfer { "none"; };

	// no notify to other NS RRs
	// notify only to also-notify IPs
	notify explicit;

Then, add a zone statement inside the named.conf.local file:

sudo nano named.conf.local

In my case a zone weberdns.de of type master. The allow-transfer statement lists the two slave servers that should be able to transfer the zone. Similarly the also-notify statement lists the slaves, too, in order to notify them in case of a zone update.

zone "weberdns.de" {
        type master;
        file "/etc/bind/db.weberdns.de";
        allow-transfer { 2003:51:6012:110::a07:53; 192.168.90.10; };
        also-notify { 2003:51:6012:110::a07:53; 192.168.90.10; };
};

Finally, the zone file must be created. I am using the template from Hetzner. All relevant statements are already explained there, so I won’t repeat them here.

sudo nano db.weberdns.de

This is my basic zone file. The SOA record starts with “ns1.weberdns.de”. There are two NS records (ns1. and ns2.) for this domain, as well as an MX record. Some examples of A, AAAA, CNAME, and TXT records are also shown. And remember to increment the serial number after each modification of the zone file! 😉

;
; BIND data file for weberdns.de
;
$TTL    1h
@       IN      SOA     ns1.weberdns.de. webmaster.weberdns.de. (
                     2016051804         ; Serial
                             1h         ; Refresh
                            15m         ; Retry
                             4w         ; Expire
                             3m )       ; Negative Cache TTL
;
@       IN      NS      ns1.weberdns.de.
@       IN      NS      ns2.weberdns.de.
@       IN      MX 10   mail.weberdns.de.

fg              IN      A       80.154.108.233
                IN      AAAA    2003:51:6012::4
ip              IN      CNAME   ip.webernetz.net.
mail            IN      A       80.154.108.237
                IN      AAAA    2003:51:6012:110::15
ns1             IN      A       80.154.108.230
                IN      AAAA    2003:51:6012:110::a07:53
ns2             IN      A       213.61.29.182
pa              IN      A       80.154.108.228
                IN      AAAA    2003:51:6012::2
txt             IN      TXT     "This is a text."
www             IN      CNAME   blog.webernetz.net.

After these steps, the BIND server must be restarted for all changes to work:

sudo service bind9 restart

A check of the configuration can be done with 

named-checkconf -z
  . If no errors occur, everything works fine.

For updates of the zone file, a reload of BIND fits. No restart is required. The reload can be triggered by either one of these two commands:

sudo service bind9 reload
sudo rndc reload

A basic test can be done with the dig tool, such as:

weberjoh@jw-vm16-ns0:/etc/bind$ dig @localhost fg.weberdns.de

; <<>> DiG 9.9.5-3ubuntu0.8-Ubuntu <<>> @localhost fg.weberdns.de
; (2 servers found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 44847
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 2, ADDITIONAL: 4
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;fg.weberdns.de.                        IN      A

;; ANSWER SECTION:
fg.weberdns.de.         3600    IN      A       80.154.108.233

;; AUTHORITY SECTION:
weberdns.de.            3600    IN      NS      ns2.weberdns.de.
weberdns.de.            3600    IN      NS      ns1.weberdns.de.

;; ADDITIONAL SECTION:
ns1.weberdns.de.        3600    IN      A       80.154.108.230
ns1.weberdns.de.        3600    IN      AAAA    2003:51:6012:110::a07:53
ns2.weberdns.de.        3600    IN      A       213.61.29.182

;; Query time: 3 msec
;; SERVER: ::1#53(::1)
;; WHEN: Wed May 18 16:02:11 CEST 2016
;; MSG SIZE  rcvd: 155

Note the “aa” flag in line 8 which indicates that this is an “authoritative answer”.

To view the statistics, run 

sudo rndc stats
  in order to dump the stats into the following file:
cat /var/cache/bind/named.stats
. The new statistics are always appended to this file and are listed between the following strings, while the number in brackets is the unixtime:
+++ Statistics Dump +++ (1471872885)
[...]
--- Statistics Dump --- (1471872885)

Great so far. 😉

Slave

The two slave servers are installed in the same way as the primary. The additional options should be the following (

sudo nano named.conf.options
 ):
// per zone statistics
	zone-statistics yes;

	// no recursion at all
	recursion no;

	// no transfer afxr by default
	allow-transfer { "none"; };

	// no NOTIFY to NS RRs
	notify no;

Note that it is REALLY crucial to put in these lines, at least the “allow-transfer none” one. Otherwise the zone is fully loadable through an axfr request. (A painful mistake is to only place this statement at the hidden primary but to forget it on the slave units.)

Now, the only portion to configure in order to be a slave is inside the named.conf.local file.

sudo nano named.conf.local

In my case, it only lists the following lines:

zone "weberdns.de" {
	type slave;
	file "db.weberdns.de";
	masters { 192.168.120.21; };
};

After a restart of the service (

sudo service bind9 restart
 ), everything is ready. Asking the localhost should work, e.g.:
dig @localhost mail.weberdns.de
.

The resource records are stored in the following path:

/var/cache/bind/
. Note that these files are not readable, but can be converted into a textfile with:
named-compilezone -f raw -j -F text -o ~/db.weberdns.de.txt weberdns.de /var/cache/bind/db.weberdns.de

This reads the raw database (-f raw) and includes the journal file (-j). It outputs text (-F text) into the file (-o outputfilename). With 

cat db.weberdns.de.txt
   you can see your RRs.

Parent Zone: Glue Records

To become the authoritative servers, the names and/or IP addresses of the nameservers must be configured at the parent zone, in my case the DENIC which is responsible for *.de. They offer a good online check for domain servers (Nameserver Predelegation Check Web Interface) which tests the nameservers to see if everything is accessible (firewalls with udp/tcp port 53) and configured correctly (SOA record values, …). In my case, this looks like that:

DENIC NAST Test weberdns.de

Since my NS servers for “weberdns.de” are called “ns1.weberdns.de” and “ns2.weberdns.de”, (which won’t be resolvable if only these FQDNs are known), the entries for these nameservers are stored with their glue records, i.e., the name and the IP addresses.

After this step was done, a whois for weberdns.de looks like:

weberjoh@jw-nb12:~$ whois weberdns.de

Domain: weberdns.de
Nserver: ns1.weberdns.de 2003:51:6012:110:0:0:a07:53 80.154.108.230
Nserver: ns2.weberdns.de 213.61.29.182
Status: connect
Changed: 2016-05-17T17:01:42+02:00

The Internet is now able to ask my two slave name servers for everything ending with .weberdns.de. Great again. This can easily be tested with dig +trace from any machine that has Internet access, e.g.:

dig www.weberdns.de +trace

Zone Transfers

At first, it is crucial to test that zone transfers of your servers are not available from the Internet. The Zone Transfer Online Test can be used for this purpose. This should fail because the “allow-transfer” options are already configured for both server types, master and slaves. Here is a sample of my domain:

Zone Transfer Online Test

Dig can be used to test the zone transfers, too, such as:

dig @ns1.weberdns.de weberdns.de axfr

Of course, this command will/must work if it is issued from one of the slaves and directed to the master, in my case:

dig @192.168.120.21 weberdns.de axfr

To authenticate the zone transfers, TSIG can be used. (This won’t be needed in my case, because I am already using private site-to-site VPNs for the connections between my servers. However. ;)) With TSIG, a shared secret is configured on any server pair (master to slave1, and master to slave2). Only if this “password” is present, the slave is able to transfer the zone. Note that this is not encryption (confidentiality), but only authentication.

At first, the keys must be generated. Note the last option which is the key-name, in this example case “key-ns1”:

dnssec-keygen -r /dev/urandom -a HMAC-SHA256 -b 256 -n HOST key-ns1

I am using two different keys for both slave servers. That is, I generated the following keys. Note that the key values in both files (*.key and *.private) are the same keys. (And no, these are not my actual keys, but only demos):

weberjoh@jw-nb12:~/temp$ dnssec-keygen -r /dev/urandom -a HMAC-SHA256 -b 256 -n HOST key-ns1
Kkey-ns1.+163+21468
weberjoh@jw-nb12:~/temp$ ls
Kkey-ns1.+163+21468.key  Kkey-ns1.+163+21468.private
weberjoh@jw-nb12:~/temp$ cat Kkey-ns1.+163+21468.key
key-ns1. IN KEY 512 3 163 32r25Nl7WKMw4AU0QSNC67NHsxE0ZNeJ+POe624fE2E=
weberjoh@jw-nb12:~/temp$ cat Kkey-ns1.+163+21468.private
Private-key-format: v1.3
Algorithm: 163 (HMAC_SHA256)
Key: 32r25Nl7WKMw4AU0QSNC67NHsxE0ZNeJ+POe624fE2E=
Bits: AAA=
Created: 20160519071805
Publish: 20160519071805
Activate: 20160519071805

weberjoh@jw-nb12:~/temp$ dnssec-keygen -r /dev/urandom -a HMAC-SHA256 -b 256 -n HOST key-ns2
Kkey-ns2.+163+35812
weberjoh@jw-nb12:~/temp$ cat Kkey-ns2.+163+35812.key
key-ns2. IN KEY 512 3 163 QZlvozBRA1dGQ2DlIRh90X7kryXjihuDntrl9hEjmD0=
weberjoh@jw-nb12:~/temp$ cat Kkey-ns2.+163+35812.private
Private-key-format: v1.3
Algorithm: 163 (HMAC_SHA256)
Key: QZlvozBRA1dGQ2DlIRh90X7kryXjihuDntrl9hEjmD0=
Bits: AAA=
Created: 20160519071831
Publish: 20160519071831
Activate: 20160519071831

On the master server, open the named.conf file and add both keys one for each slave, such as:

key key-ns1 {
        algorithm hmac-sha256;
        secret "32r25Nl7WKMw4AU0QSNC67NHsxE0ZNeJ+POe624fE2E=";
};

key key-ns2 {
        algorithm hmac-sha256;
        secret "QZlvozBRA1dGQ2DlIRh90X7kryXjihuDntrl9hEjmD0=";
};

Furthermore, open the named.conf.local and change the “allow-transfer” statement to only allow connections with these keys. The IP addresses from the servers must be omitted, for example, comment them out. Otherwise, connections from this IP addresses will still be possible without the key:

//      allow-transfer { 2003:51:6012:110::a07:53; 192.168.90.10; };
        allow-transfer { key key-ns1; key key-ns2; };

Same procedure on both slaves, of course only with the single needed key, e.g., key-ns1 and key-ns2. Furthermore, the “server” statement must be configured. Open the named.conf on the first slave, ns1, and add these lines:

key key-ns1 {
        algorithm hmac-sha256;
        secret "32r25Nl7WKMw4AU0QSNC67NHsxE0ZNeJ+POe624fE2E=";
};

server 2003:51:6012:120::a16:53 {
        keys { key-ns1; };
};

And similarly on ns2:

key key-ns2 {
        algorithm hmac-sha256;
        secret "QZlvozBRA1dGQ2DlIRh90X7kryXjihuDntrl9hEjmD0=";
};

server 192.168.120.21 {
        keys { key-ns2; };
};

Now, restart all bind services 

sudo service bind9 restart
  and you’re done.

A dig test w/o the key will not work anymore:

weberjoh@jw-vm07-ns1:~$ dig @192.168.120.21 weberdns.de axfr

; <<>> DiG 9.9.5-3ubuntu0.8-Ubuntu <<>> @192.168.120.21 weberdns.de axfr
; (1 server found)
;; global options: +cmd
; Transfer failed.

But with the key (-y option), the zone transfer works again:

weberjoh@jw-vm07-ns1:~$ dig @192.168.120.21 -y hmac-sha256:key-ns1:32r25Nl7WKMw4AU0QSNC67NHsxE0ZNeJ+POe624fE2E= weberdns.de axfr

; <<>> DiG 9.9.5-3ubuntu0.8-Ubuntu <<>> @192.168.120.21 -y hmac-sha256 weberdns.de axfr
; (1 server found)
;; global options: +cmd
weberdns.de.            3600    IN      SOA     ns1.weberdns.de. webmaster.weberdns.de. 2016051804 14400 1800 604800 180
weberdns.de.            3600    IN      NS      ns1.weberdns.de.
weberdns.de.            3600    IN      NS      ns2.weberdns.de.
weberdns.de.            3600    IN      MX      10 mail.weberdns.de.
[...]

Note the different syslog messages (captured on the slave) for the following three scenarios:

### Syslog Messages notify + zone transfer (w/o TSIG)
weberjoh@jw-nb13-ns2:~$ tail -100 /var/log/syslog | grep named
May 18 10:15:50 jw-nb13 named[2436]: client 192.168.120.21#55706: received notify for zone 'weberdns.de'
May 18 10:15:50 jw-nb13 named[2436]: zone weberdns.de/IN: Transfer started.
May 18 10:15:50 jw-nb13 named[2436]: transfer of 'weberdns.de/IN' from 192.168.120.21#53: connected using 192.168.90.10#58932
May 18 10:15:50 jw-nb13 named[2436]: zone weberdns.de/IN: transferred serial 2016051801
May 18 10:15:50 jw-nb13 named[2436]: transfer of 'weberdns.de/IN' from 192.168.120.21#53: Transfer completed: 1 messages, 14 records, 1408 bytes, 0.128 secs (11000 bytes/sec)

### Syslog with TSIG on the master but currently not on the slave
May 18 11:14:48 jw-nb13 named[2436]: client 192.168.120.21#22030: request has invalid signature: TSIG key-ns2: tsig verify failure (BADKEY)

### Syslog with TSIG correctly on both, master and slave. Note the "TSIG 'key-ns2'" statements:
May 18 11:30:39 jw-nb13 named[2928]: client 192.168.120.21#40015/key key-ns2: received notify for zone 'weberdns.de': TSIG 'key-ns2'
May 18 11:30:39 jw-nb13 named[2928]: zone weberdns.de/IN: Transfer started.
May 18 11:30:39 jw-nb13 named[2928]: transfer of 'weberdns.de/IN' from 192.168.120.21#53: connected using 192.168.90.10#34207
May 18 11:30:39 jw-nb13 named[2928]: zone weberdns.de/IN: transferred serial 2016051803: TSIG 'key-ns2'
May 18 11:30:39 jw-nb13 named[2928]: transfer of 'weberdns.de/IN' from 192.168.120.21#53: Transfer completed: 1 messages, 14 records, 1420 bytes, 0.141 secs (10070 bytes/sec)

Finally, here are some Wireshark screenshots for different notifies and zone transfers, with and without TSIG. See the descriptions beneath them for more details:

Zone Change Notification from the master to the slave. And the incremental zone transfer IXFR without TSIG. A complete zone transfer (tested with dig axfr) requires lots of messages. A zone transfer initiated from the slave with TSIG. Note the additional key record at the end.

That’s it. Hope this helps.

Links

Other BIND tutorials are here or here [DE]. The following links are more specific ones:

BIND DNSSEC Validation

$
0
0
dnssec-validation auto - featured image

If you are searching for a DNSSEC validating DNS server, you can use BIND to do that. In fact, with a current version of BIND, e.g. version 9.10, the dnssec-validation is enabled by default. If you are already using BIND as a recursive or forwarding/caching server, you’re almost done. If not, this is a very basic installation guide for BIND with DNSSEC validation enabled and some notes on how to test it.

I am using a fresh Ubuntu 16.04 LTS installation with BIND 9.10.3-P4, that is:

sudo apt-get update
sudo apt-get install bind9
sudo service bind9 start

The configuration files are stored in “/etc/bind/“. To allow DNS queries for the local clients, edit the options (

sudo nano named.conf.options
 ), add your subnets, e.g.:
allow-recursion { localhost; 192.168.0.0/16; 2003:51:6012:100::/56; };

and restart the server:

sudo service bind9 restart
.

DNSSEC by Default

The interesting part is that the DNSSEC validation is enabled by default. 😉 The “dnssec-validation auto;” option is already present and the “dnssec-enable yes;” option is not needed, because its default is already “yes”. (See here: DNS BIND Security Statements.)

Furthermore, the directory option is already present, too:

directory "/var/cache/bind";

That is, the managed keys are stored here:

/var/cache/bind/managed-keys.bind
.

Test with Dig

A basic test with dig against a DNSSEC secured domain will show the “ad” flag (authenticated data, see DNS Header Flags), in the header:

weberjoh@jw-nb12:~$ dig weberdns.de

; <<>> DiG 9.9.5-3ubuntu0.8-Ubuntu <<>> weberdns.de
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 34885
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;weberdns.de.                   IN      A

;; AUTHORITY SECTION:
weberdns.de.            180     IN      SOA     ns1.weberdns.de. webmaster.weberdns.de. 2016051901 14400 1800 604800 180

;; Query time: 19 msec
;; SERVER: 192.168.120.22#53(192.168.120.22)
;; WHEN: Thu May 19 14:03:59 CEST 2016
;; MSG SIZE  rcvd: 90

More relevant, a failure in a DNSSEC secured domain will result in a SERVERFAIL without an answer:

weberjoh@jw-nb12:~$ dig sigfail.verteiltesysteme.net

; <<>> DiG 9.9.5-3ubuntu0.8-Ubuntu <<>> sigfail.verteiltesysteme.net
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 64793
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;sigfail.verteiltesysteme.net.  IN      A

;; Query time: 58 msec
;; SERVER: 192.168.120.22#53(192.168.120.22)
;; WHEN: Thu May 19 14:04:38 CEST 2016
;; MSG SIZE  rcvd: 57

To test (!) the failure, the cd flag (check disabled) can be sent with dig, which reveals the answer, but of course with the cd flag again and not with the ad flag in the answer:

weberjoh@jw-nb12:~$ dig sigfail.verteiltesysteme.net +cd

; <<>> DiG 9.9.5-3ubuntu0.8-Ubuntu <<>> sigfail.verteiltesysteme.net +cd
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 39420
;; flags: qr rd ra cd; QUERY: 1, ANSWER: 1, AUTHORITY: 2, ADDITIONAL: 5

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;sigfail.verteiltesysteme.net.  IN      A

;; ANSWER SECTION:
sigfail.verteiltesysteme.net. 60 IN     A       134.91.78.139

;; Query time: 20 msec
;; SERVER: 192.168.120.22#53(192.168.120.22)
;; WHEN: Thu May 19 14:04:45 CEST 2016
;; MSG SIZE  rcvd: 197

 

Online Test for Clients

More interesting for the clients is an online test whether DNSSEC validation works or not. I am using the one at http://dnssec.vs.uni-due.de. If a client uses the just configured BIND server, the test looks like that:

DNSSEC Resolver Test ok

Congrats! You are now validating domain names.

Stats ‘n Cache

To view some statistics of BIND, execute the following shell command:

sudo rndc stats

This appends the statistics into this file:

/var/cache/bind/named.stats
. Note the “+++ Statistics Dump +++ (1471872885)” beginning of each new dump, while the number in brackets is the unixtime. In my case, for example, this looks like that:
+++ Statistics Dump +++ (1471872885)
++ Incoming Requests ++
              611719 QUERY
++ Incoming Queries ++
               64716 A
                   1 NS
                 131 SOA
              484641 PTR
                  22 MX
                  40 TXT
               61880 AAAA
                 279 SRV
                   9 ANY
++ Outgoing Queries ++
[View: default]
              140942 A
                  53 NS
                 110 CNAME
                 154 SOA
              143244 PTR
                  23 MX
                   2 TXT
              134638 AAAA
                 206 SRV
              104142 DS
               17265 DNSKEY
                   2 ANY
[View: _bind]
++ Name Server Statistics ++
              416710 IPv4 requests received
              195009 IPv6 requests received
                 328 requests with EDNS(0) received
                  33 TCP requests received
              609642 responses sent
                  46 truncated responses sent
                 328 responses with EDNS(0) sent
              479303 queries resulted in successful answer
               89521 queries resulted in authoritative answer
              509101 queries resulted in non authoritative answer
               29451 queries resulted in nxrrset
               11020 queries resulted in SERVFAIL
               89868 queries resulted in NXDOMAIN
              152697 queries caused recursion
                1881 duplicate queries received
                 196 queries dropped
              611686 UDP queries received
                  33 TCP queries received
++ Zone Maintenance Statistics ++
++ Resolver Statistics ++
[Common]
[View: default]
              363641 IPv4 queries sent
              177140 IPv6 queries sent
              346942 IPv4 responses received
              168436 IPv6 responses received
               24977 NXDOMAIN received
                4212 SERVFAIL received
                  32 FORMERR received
                 118 EDNS(0) query failures
               34758 truncated responses received
                2516 lame delegations received
               87670 query retries
               26471 query timeouts
               69897 IPv4 NS address fetches
               72415 IPv6 NS address fetches
                 870 IPv4 NS address fetch failed
               41590 IPv6 NS address fetch failed
              249786 DNSSEC validation attempted
              123250 DNSSEC validation succeeded
              125845 DNSSEC NX validation succeeded
                 177 DNSSEC validation failed
              180114 queries with RTT < 10ms
              223124 queries with RTT 10-100ms
              104360 queries with RTT 100-500ms
                5988 queries with RTT 500-800ms
                1457 queries with RTT 800-1600ms
                  83 queries with RTT > 1600ms
                  31 bucket size
                7363 REFUSED received
[View: _bind]
                  31 bucket size
++ Cache Statistics ++
[View: default]
             5706174 cache hits
                3570 cache misses
              996705 cache hits (from query)
              933523 cache misses (from query)
                   0 cache records deleted due to memory exhaustion
              414200 cache records deleted due to TTL expiration
               18385 cache database nodes
                8319 cache database hash buckets
            11143805 cache tree memory total
             7815275 cache tree memory in use
             8389020 cache tree highest memory in use
              655360 cache heap memory total
              263168 cache heap memory in use
              271360 cache heap highest memory in use
[View: _bind (Cache: _bind)]
                   0 cache hits
                   0 cache misses
                   0 cache hits (from query)
                   0 cache misses (from query)
                   0 cache records deleted due to memory exhaustion
                   0 cache records deleted due to TTL expiration
                   0 cache database nodes
                  64 cache database hash buckets
              287392 cache tree memory total
               29608 cache tree memory in use
               29608 cache tree highest memory in use
              262144 cache heap memory total
                1024 cache heap memory in use
                1024 cache heap highest memory in use
++ Cache DB RRsets ++
[View: default]
                4045 A
                5685 NS
                 102 CNAME
                3751 PTR
                1300 AAAA
                 455 DS
                3380 RRSIG
                1963 NSEC
                 301 DNSKEY
                   4 !A
                 214 !AAAA
                1135 !DS
                 240 NXDOMAIN
[View: _bind (Cache: _bind)]
++ ADB stats ++
[View: default]
                1021 Address hash table size
                4710 Addresses in hash table
                1021 Name hash table size
                3925 Names in hash table
[View: _bind]
                1021 Address hash table size
                1021 Name hash table size
++ Socket I/O Statistics ++
              341815 UDP/IPv4 sockets opened
              164252 UDP/IPv6 sockets opened
               21867 TCP/IPv4 sockets opened
               12897 TCP/IPv6 sockets opened
                   1 Raw sockets opened
              341813 UDP/IPv4 sockets closed
              164251 UDP/IPv6 sockets closed
               21866 TCP/IPv4 sockets closed
               12928 TCP/IPv6 sockets closed
                  36 UDP/IPv4 socket bind failures
                   6 UDP/IPv6 socket bind failures
                  21 TCP/IPv6 socket connect failures
              341777 UDP/IPv4 connections established
              164245 UDP/IPv6 connections established
               21699 TCP/IPv4 connections established
               12822 TCP/IPv6 connections established
                   3 TCP/IPv4 connections accepted
                  33 TCP/IPv6 connections accepted
                 252 UDP/IPv4 recv errors
                   1 TCP/IPv6 recv errors
                   2 UDP/IPv4 sockets active
                   1 UDP/IPv6 sockets active
                   6 TCP/IPv4 sockets active
                  35 TCP/IPv6 sockets active
                   1 Raw sockets active
++ Per Zone Query Statistics ++
--- Statistics Dump --- (1471872885)

To view the current cache of BIND, run the following command:

sudo rndc dumpdb -cache

This dumps the whole cache into this file:

/var/cache/bind/named_dump.db
.

It can be listed/grepped as normal, e.g.:

weberjoh@jw-vm08-int-dns:/var/cache/bind$ cat named_dump.db | grep ubuntu
ubuntu.com.             172675  NS      ns1.p27.dynect.net.
de.archive.ubuntu.com.  492     CNAME   ubuntu.mirror.tudos.de.
ntp.ubuntu.com.         475     A       91.189.89.198
security.ubuntu.com.    492     A       91.189.88.149
ubuntu.mirror.tudos.de. 10692   \-AAAA  ;-$NXRRSET
0.ubuntu.pool.ntp.org.  1371    \-AAAA  ;-$NXRRSET
1.ubuntu.pool.ntp.org.  1372    \-AAAA  ;-$NXRRSET
2.ubuntu.pool.ntp.org.  23      A       5.9.80.113
3.ubuntu.pool.ntp.org.  1374    \-AAAA  ;-$NXRRSET

 

Final notes: A much more detailed post about BIND as a caching server is here. And yes, I know that some security people don’t like the usage of BIND for a mere forwarding DNS server. The blog post about Unbound is coming soon. 😉 Cheers.

DNSSEC Validation with Unbound on a Raspberry

$
0
0
Unbound RPi featured image

To overcome the chicken-or-egg problem for DNSSEC (“I don’t need a DNSSEC validating resolver if there are no signed zones”), let’s install the DNS server Unbound on a Raspberry Pi for home usage. Up then, domain names are DNSSEC validated. I am listing the commands to install Unbound on a Raspberry Pi as well as some further commands to test and troubleshoot it. Finally I am showing a few Wireshark screenshots from a sample iterative DNS capture. Here we go:

It is really simple to operate an Unbound DNS resolver locally on a Raspberry Pi. Merely an installation and some config changes. That’s it. The Unbound package on a Raspbian Linux of Unbound validates DNSSEC by default. Great!

Installation

I am using an “old” Raspberry Pi 1 Model B with Raspbian GNU/Linux 7 (wheezy) and kernel 4.1.13+. The version of Unbound which comes with this OS is not the newest one (1.4.17-3+deb7u2), but it fits. The installation is really simple:

sudo apt-get update
sudo apt-get install unbound

The Unbound server starts automatically. Have look at the listening ports with:

pi@jw-pi01 ~ $ sudo netstat -tulpen | grep unbound
tcp        0      0 127.0.0.1:53            0.0.0.0:*               LISTEN      0          7312680     27897/unbound
tcp        0      0 127.0.0.1:8953          0.0.0.0:*               LISTEN      0          7312684     27897/unbound
tcp6       0      0 ::1:53                  :::*                    LISTEN      0          7312676     27897/unbound
tcp6       0      0 ::1:8953                :::*                    LISTEN      0          7312682     27897/unbound
udp        0      0 127.0.0.1:53            0.0.0.0:*                           0          7312678     27897/unbound
udp6       0      0 ::1:53                  :::*                                0          7312674     27897/unbound

Unbound works out of the box for queries from the localhost. In order to allow queries from any host, the configuration file must be edited. It is stored at

/etc/unbound/unbound.conf
 . Note that the config has already DNSSEC validation enabled!
pi@jw-pi01 /etc/unbound $ cat unbound.conf
# Unbound configuration file for Debian.
#
# See the unbound.conf(5) man page.
#
# See /usr/share/doc/unbound/examples/unbound.conf for a commented
# reference config file.

server:
    # The following line will configure unbound to perform cryptographic
    # DNSSEC validation using the root trust anchor.
    auto-trust-anchor-file: "/var/lib/unbound/root.key"

Now, to allow queries add the following lines within the “server:” paragraph:

interface: 0.0.0.0
interface: ::0
access-control: 0.0.0.0/0 allow
access-control: ::0/0 allow

check the config:

pi@jw-pi01 ~ $ unbound-checkconf
unbound-checkconf: no errors in /etc/unbound/unbound.conf

and restart the server:

pi@jw-pi01 ~ $ sudo service unbound restart
[ ok ] Restarting recursive DNS server: unbound.

That’s it! To see a list of all configuration options click here. If you only wanted to install Unbound you’re already done!

-> The following information are only for further analysis etc.

Root Hints & Root Key

Unbound uses a list of the root servers as well as the root dnskey for its DNSSEC validation. Both should be updated regularly to avoid DNS problems in case of real root server changes. To update and use the root-hints file (for the list of root-servers), download the official list:

sudo curl -o /etc/unbound/root.hints https://www.internic.net/domain/named.root

and use it within the unbound.conf configuration file:

root-hints: "/etc/unbound/root.hints"

To update the root.key, use the simple “unbound-anchor” program which downloads the root.key file into /etc/unbound/:

sudo unbound-anchor

And change the auto-trust-anchor-file within the unbound.conf from the default to:

auto-trust-anchor-file: "/etc/unbound/root.key"

Restart Unbound:

sudo service unbound restart
 .

Done. (Click here for more information about the root.hints etc.)

Tests & Status

Here’s a basic test from another Linux machine that queries the Unbound server. Note the ad flag in line 8 which indicates the DNSSEC validation:

pi@ntp1:~ $ dig @192.168.7.5 weberdns.de +noadditional +noauthority

; <<>> DiG 9.9.5-9+deb8u6-Raspbian <<>> @192.168.7.5 weberdns.de +noadditional +noauthority
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 43402
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 3, ADDITIONAL: 5

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;weberdns.de.                   IN      A

;; ANSWER SECTION:
weberdns.de.            3600    IN      A       80.154.108.230

;; Query time: 19 msec
;; SERVER: 192.168.7.5#53(192.168.7.5)
;; WHEN: Thu Jun 09 17:23:21 CEST 2016
;; MSG SIZE  rcvd: 186

Of course, a failure in DNSSEC leads to a SERVFAIL (line 7) without any answer:

pi@ntp1:~ $ dig @192.168.7.5 fail03.dnssec.works

; <<>> DiG 9.9.5-9+deb8u6-Raspbian <<>> @192.168.7.5 fail03.dnssec.works
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 42531
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;fail03.dnssec.works.           IN      A

;; Query time: 111 msec
;; SERVER: 192.168.7.5#53(192.168.7.5)
;; WHEN: Thu Jun 09 17:24:25 CEST 2016
;; MSG SIZE  rcvd: 48

Good.

In order to view the status of Unbound, use the following commands: 

unbound-control status
  and
unbound-control stats_noreset
 :
pi@jw-pi01 ~ $ sudo unbound-control status
version: 1.4.17
verbosity: 1
threads: 1
modules: 2 [ validator iterator ]
uptime: 11744 seconds
unbound (pid 28021) is running...
pi@jw-pi01 ~ $ sudo unbound-control stats_noreset
thread0.num.queries=120
thread0.num.cachehits=18
thread0.num.cachemiss=102
thread0.num.prefetch=0
thread0.num.recursivereplies=102
thread0.requestlist.avg=0.54902
thread0.requestlist.max=18
thread0.requestlist.overwritten=0
thread0.requestlist.exceeded=0
thread0.requestlist.current.all=0
thread0.requestlist.current.user=0
thread0.recursion.time.avg=0.201798
thread0.recursion.time.median=0.17367
total.num.queries=120
total.num.cachehits=18
total.num.cachemiss=102
total.num.prefetch=0
total.num.recursivereplies=102
total.requestlist.avg=0.54902
total.requestlist.max=18
total.requestlist.overwritten=0
total.requestlist.exceeded=0
total.requestlist.current.all=0
total.requestlist.current.user=0
total.recursion.time.avg=0.201798
total.recursion.time.median=0.17367
time.now=1465816919.018412
time.up=460.981236
time.elapsed=460.981236

To list the current values of options, e.g. the default values, use unbound-checkconf with the “-o parameter” option, such as:

pi@jw-pi01 ~ $ sudo unbound-checkconf -o use-syslog
yes
pi@jw-pi01 ~ $ sudo unbound-checkconf -o verbosity
1
pi@jw-pi01 ~ $ sudo unbound-checkconf -o do-ip6
yes
pi@jw-pi01 ~ $ sudo unbound-checkconf -o do-ip4
yes
pi@jw-pi01 ~ $ sudo unbound-checkconf -o do-udp
yes
pi@jw-pi01 ~ $ sudo unbound-checkconf -o do-tcp
yes

To dump the cache for further investigations, use this:

pi@jw-pi01 ~ $ sudo unbound-control dump_cache | less
pi@jw-pi01 ~ $ sudo unbound-control dump_cache | grep webernetz.net

Per default, the log messages are sent to syslog. That is, they are stored in the default /var/log/syslog file which can be followed with:

pi@jw-pi01 ~ $ tail -f /var/log/syslog | grep unbound

To increase the verbosity level, add/change the verbosity line in the unbound.conf file. The default is “1”. A level of “2” already logs every DNS request. Use it for troubleshooting but be careful with it!

verbosity: 2

All other details about the Unbound options are listed here.

DNS Server on LAN

To use this Unbound DNS server for all clients in the LAN, it must be announced via DHCP as the DNS server. In my home network I have an AVM FRITZ!Box router which connects to the Internet via FTTH. The settings are as follows. I am using the static IPv4 address as well as the link-local IPv6 address as the DNS server address:

IPv4 local DNS server. And IPv6, too.

Tested from another Raspberry Pi, this leads to the following resolv.conf entries:

pi@ntp1:~ $ cat /etc/resolv.conf
# Generated by resolvconf
domain fritz.box
nameserver 192.168.7.5
nameserver fe80::ba27:ebff:fec9:1637%eth0

This is a test from a Linux client. Once more, note the “ad” flag in line 7:

pi@ntp1:~ $ dig pa.weberdns.de +noadditional +noauthority

; <<>> DiG 9.9.5-9+deb8u6-Raspbian <<>> pa.weberdns.de +noadditional +noauthority
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 58151
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 3, ADDITIONAL: 5

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;pa.weberdns.de.                        IN      A

;; ANSWER SECTION:
pa.weberdns.de.         3592    IN      A       80.154.108.228

;; Query time: 10 msec
;; SERVER: 192.168.7.5#53(192.168.7.5)
;; WHEN: Thu Jun 09 16:45:47 CEST 2016
;; MSG SIZE  rcvd: 189

However, there are problems when querying the IPv6 address via the “-6” switch:

pi@ntp1:~ $ dig -6 dnssec.works

; <<>> DiG 9.9.5-9+deb8u6-Raspbian <<>> -6 dnssec.works
;; global options: +cmd
;; connection timed out; no servers could be reached

But it works when the link-local IPv6 address is specified (with the %eth0 interface suffix) directly:

pi@ntp1:~ $ dig @fe80::ba27:ebff:fec9:1637%eth0 dnssec.works +noadditional +noauthority

; <<>> DiG 9.9.5-9+deb8u6-Raspbian <<>> @fe80::ba27:ebff:fec9:1637%eth0 dnssec.works +noadditional +noauthority
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 48062
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 2, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;dnssec.works.                  IN      A

;; ANSWER SECTION:
dnssec.works.           3600    IN      A       5.45.109.212

;; Query time: 71 msec
;; SERVER: fe80::ba27:ebff:fec9:1637%2#53(fe80::ba27:ebff:fec9:1637%2)
;; WHEN: Thu Jun 09 16:48:44 CEST 2016
;; MSG SIZE  rcvd: 113

So maybe it’s not a good idea to use the link-local address for the DNS server. Maybe I will disable the “IPv6 DNS Server” option in my home network since the availability of a legacy IP DNS server perfectly fits for dual-stacked clients.

And a web browser GUI test to http://dnssec.vs.uni-due.de looks like that:

DNSSEC Resolver Test okGreat!

Sample Wireshark Screenshots

This is a small tcpdump capture on the Raspberry Pi, displayed with Wireshark. It shows an iterative (!) lookup of “licher.de” with its initial request from the client to the Raspberry Pi, the iterative lookup and the final answer to the client. Also note the “Statistics -> DNS” summary within Wireshark which can be used for troubleshooting, too:

Initial request from the client. Iterative query (1). Iterative query (2). Reply to the client. Wireshark DNS Statistics.

Conclusion

Now, all DNS answers are DNSSEC validated. Really all DNS answer? Well, actually, no. Only those which are DNSSEC signed. However, we solved the chicken-egg problem and are now able to validate DNSSEC answers.

DNSSEC Signing w/ BIND

$
0
0
BIND DNSSEC Signing

To solve the chicken-or-egg problem for DNSSEC from the other side, let’s use an authoritative DNS server (BIND) for signing DNS zones. This tutorial describes how to generate the keys and configure the “Berkeley Internet Name Domain” (BIND) server in order to automatically sign zones. I am not explaining many details of DNSSEC at all, but only the configuration and verification steps for a concrete BIND server.

It is really easy to tell BIND to do the inline signing. With this option enabled, the admin can still configure the static database for his zone files without any relation to DNSSEC. Everything with signing and maintaining is fully done by BIND without any user interaction. Great.

Prerequisites

I am assuming that there is a working BIND server in place which is the authoritative name server for at least one zone. The BIND server must at least run with version 9.9! I am using an Ubuntu Server 14.04.4 LTS with BIND version 9.9.5-3ubuntu0.8-Ubuntu. A few days age I published a blog post covering the secure installation of BIND. Refer to it to see how. For this tutorial, I am using my test domain weberdns.de.

Furthermore, please read some general DNSSEC information on other sites, or simply google it and read the Wikipedia, DNSSEC.net, or RFC (4033, 4034, 4035) articles. I am assuming that you are already familiar with KSK & ZSK, RRSIG, DNSKEY, DS, NSEC & NSEC3. If not, come back again in two hours. 😉 Ok, in any case, here it is: DNSSEC signes zones with a private key (ZSK and KSK), while the public key is used to verify the signature. The signature for all resource records are stored in additional records, called RRSIG. The “Next SECure record” (NSEC) is used to prove that no entry exists between two other entries (NXDOMAIN).

Design and Keys

One thing to think about is the placement of the keys. The private keys (for both, the KSK as well as for the ZSKs) should NOT be accessible from the Internet. In the best way, a hardware security module (HSM) would be used for them. However, since this is not that trivial, the concept of a hidden primary can be used. With this way, the private keys are only stored on a not-accessible server, while only the slaves (which must not store the private keys) are queried from the Internet:

BIND Servers Master and Slaves

Another consideration is the usage of NSEC or NSEC3. For small zones that only store a few well-known names such as ns, www, and mail, NSEC can be used. (Remember the zone walking.) For complex zones with many hidden domain names, the usage of NSEC3 should be considered. However, note that “security through obscurity” is not a good design at all. 😉

BIND Configuration

We will first generate the keys followed by the configuration of BIND. A great (hence: small) tutorial is also available at ISC: Inline Signing in ISC BIND 9.9.0 — Examples. Note that I am using /dev/urandom for my key generation. If you are interested in more details, read this or that. And again, note that you must have at least BIND 9.9 for these features to work.

dnssec-keygen

First, create a new directory for the keys:

sudo mkdir /etc/bind/keys

And generate both, the KSK and the ZSK, within that newly created directory. I am using the RSASHA256 algorithm and 2048 bit for the KSK, while 1024 bit for the ZSK:

sudo dnssec-keygen -r /dev/urandom -a RSASHA256 -b 2048 -K /etc/bind/keys/ -f KSK -n ZONE weberdns.de
sudo dnssec-keygen -r /dev/urandom -a RSASHA256 -b 1024 -K /etc/bind/keys/ -n ZONE weberdns.de

Since BIND must be able to read the private key, change the permissions for the group (bind) to read the *.private files:

sudo chmod g+r *.private

Now, the /keys directory should look like that. Note that the private files are NOT readable from others:

weberjoh@jw-vm16-ns0:/etc/bind/keys$ ls -ahl Kweberdns*
-rw-r--r-- 1 root bind  431 May 20 09:46 Kweberdns.de.+008+57909.key
-rw-r----- 1 root bind 1012 May 20 09:46 Kweberdns.de.+008+57909.private
-rw-r--r-- 1 root bind  605 May 20 09:46 Kweberdns.de.+008+63202.key
-rw-r----- 1 root bind 1.8K May 20 09:46 Kweberdns.de.+008+63202.private

For example, my public KSK for weberdns.de looks like that:

weberjoh@jw-vm16-ns0:/etc/bind/keys$ cat Kweberdns.de.+008+63202.key
; This is a key-signing key, keyid 63202, for weberdns.de.
; Created: 20160205194002 (Fri Feb  5 20:40:02 2016)
; Publish: 20160205194002 (Fri Feb  5 20:40:02 2016)
; Activate: 20160205194002 (Fri Feb  5 20:40:02 2016)
weberdns.de. IN DNSKEY 257 3 8 AwEAAdQXI+UfqnGbHdwJtBBStf0CM8Q8nXcriaOysrpGEDNkM//amUBD 2YMWQ3g+htca6tmzfDJMM5D0gOk5d4IdEmdywkcH+0rGLjNiNEPFnZUp wb6XsYD+ZI/WEuSlp+KCEV8vwELq7VltABrFT+9Rz5CEvokTxonzQrvn fclVHaGwO7cglgALsFqJCqBpvDZvEr2Z6dSepjDnFC9BPS6V8PGSNwAY EtzDp/lrQojkCj28xHj2OCjpr0dIQjdjGFJTHIlc9cYTAHjdPDsC8Eqf s5HcL3ruU6cbqjTn+5Lm4RdXpOWVgemVvIGDnUN+v+Tma/WgtQk7U3sa izNJ3epCv3s=

[Note that I had some problems on Ubuntu with the keys for BIND. This post helped me to solve it. But I am not fully sure whether this is the best way:

sudo nano /etc/apparmor.d/usr.sbin.named

and changing the following line to this:

/etc/bind/** rw,

and a restart of apparmor:

sudo service apparmor restart
.]

named.conf.options & named.conf.local

It is really simple to tell BIND that it should sign its zones for the proper usage of DNSSEC. The first step is to set the key-directory and to enable dnssec. (Note that dnssec-enable is “yes” per default. However, I am adding the lines anyway.) Open the named.conf.options file:

sudo nano named.conf.options
and add the following two lines within the options { } section:
dnssec-enable yes;
        key-directory "/etc/bind/keys";

The second step is to configure the concrete zone to be signed and maintained. That is: BIND will 1) use the existing zone file and sign it in the background and 2) maintains the signed file in order to update any signatures once they expire.

Open the named.conf.local file in which the zones are declared:

sudo nano named.conf.local
and add the following two lines to the zone which should be signed:
auto-dnssec maintain;
        inline-signing yes;

That’s it!!

Reload the server in order to let BIND sign the zone:

sudo service bind9 reload
. The following command checks the correct signing, e.g.:
weberjoh@jw-vm16:/etc/bind$ sudo rndc signing -list weberdns.de
Done signing with key 57909/RSASHA256
Done signing with key 63202/RSASHA256

Note that you now have two more files within the /etc/bind/ directory, namely the *.signed and *.signed.jnl files. These are the real zone files that are presented to the world, while the original zone file is the file which is still edited by the admin:

weberjoh@jw-vm16-ns0:/etc/bind$ ls -ahl db.weberdns*
-rw-r--r-- 1 root bind 8.0K Aug 23 12:41 db.weberdns.de
-rw-r--r-- 1 bind bind  34K Aug 23 12:41 db.weberdns.de.jnl
-rw-r--r-- 1 bind bind  26K Aug 23 12:53 db.weberdns.de.signed
-rw-r--r-- 1 bind bind 387K Aug 23 12:41 db.weberdns.de.signed.jnl

 

KSK/DS to Parent Zone

In order to have the full DNS tree secured by DNSSEC, you must transfer your KSK or DS record to your registrar. They will sign it with their private key. This is the main part of DNSSEC because afterwards anyone in the world will be able to validate that you really own the private key for your zone.

If the registrar wants the DS record, obtain it from the KSK keys with the tool dnssec-dsfromkey, such as:

weberjoh@jw-vm16-ns0:/etc/bind/keys$ dnssec-dsfromkey Kweberdns.de.+008+63202.
weberdns.de. IN DS 63202 8 1 45B896D0F5735832203F18A600A605072596D368
weberdns.de. IN DS 63202 8 2 2F9112FF344BCDF9C6F9A7548F04184AAE73458C7150DE8FFFA3B7D9893C5EEE

If they want the whole public KSK, simply “cat” it from the keyfile, as already shown above (cat Kweberdns.de.+008+63202.key).

After the registrar has received and signed the KSK, it can be queried within the DNS. For the German DENIC, the KSK is also present in the whois query:

whois weberdns.de

Domain: weberdns.de
Nserver: ns1.weberdns.de 2003:51:6012:110:0:0:a07:53 80.154.108.230
Nserver: ns2.weberdns.de 213.61.29.182
Dnskey: 257 3 8 AwEAAdQXI+UfqnGbHdwJtBBStf0CM8Q8nXcriaOysrpGEDNkM//amUBD2YMWQ3g+htca6tmzfDJMM5D0gOk5d4IdEmdywkcH+0rGLjNiNEPFnZUpwb6XsYD+ZI/WEuSlp+KCEV8vwELq7VltABrFT+9Rz5CEvokTxonzQrvnfclVHaGwO7cglgALsFqJCqBpvDZvEr2Z6dSepjDnFC9BPS6V8PGSNwAYEtzDp/lrQojkCj28xHj2OCjpr0dIQjdjGFJTHIlc9cYTAHjdPDsC8Eqfs5HcL3ruU6cbqjTn+5Lm4RdXpOWVgemVvIGDnUN+v+Tma/WgtQk7U3saizNJ3epCv3s=
Status: connect
Changed: 2016-05-17T17:01:42+02:00

The DS record can be queried with a normal DNS request. In the following example, I am using the +trace and +dnssec options in order to see the DS returning from the parent zone (in my case .de) and to see some RRSIG signatures for all answers:

weberjoh@jw-nb12-lx:~$ dig weberdns.de ds +multi +dnssec +trace

; <<>> DiG 9.10.3-P4-Ubuntu <<>> weberdns.de ds +multi +dnssec +trace
;; global options: +cmd
.                       451618 IN NS i.root-servers.net.
.                       451618 IN NS d.root-servers.net.
.                       451618 IN NS l.root-servers.net.
.                       451618 IN NS g.root-servers.net.
.                       451618 IN NS h.root-servers.net.
.                       451618 IN NS j.root-servers.net.
.                       451618 IN NS b.root-servers.net.
.                       451618 IN NS e.root-servers.net.
.                       451618 IN NS c.root-servers.net.
.                       451618 IN NS a.root-servers.net.
.                       451618 IN NS m.root-servers.net.
.                       451618 IN NS f.root-servers.net.
.                       451618 IN NS k.root-servers.net.
.                       518356 IN RRSIG NS 8 0 518400 (
                                20160902050000 20160823040000 46551 .
                                C2NM1S7/NzZQDbx9H1tWLl1VotgaC0+YG0LtkW6Gfy5l
                                91WCLoK7RZJfl2joYyU4KnB/4/jRJhV4tbfvB4+GA7pp
                                c0V/v00KLipbCB+i39RFP5WVy9nlBgyXbqy8AqzJKnPH
                                BePme3m4q36RESbBxl3fENeoPPUWtO4/iSbxgsg= )
;; Received 397 bytes from 192.168.120.22#53(192.168.120.22) in 1 ms

de.                     172800 IN NS a.nic.de.
de.                     172800 IN NS f.nic.de.
de.                     172800 IN NS l.de.net.
de.                     172800 IN NS n.de.net.
de.                     172800 IN NS s.de.net.
de.                     172800 IN NS z.nic.de.
de.                     86400 IN DS 24220 8 2 (
                                FFE926ACA67ED94089390250F1F294AC84A6D84F9121
                                DF73A79E439F42E820C2 )
de.                     86400 IN DS 39227 8 2 (
                                AAB73083B9EF70E4A5E94769A418AC12E887FC3C0875
                                EF206C3451DC40B6C4FA )
de.                     86400 IN RRSIG DS 8 1 86400 (
                                20160901170000 20160822160000 46551 .
                                YNFLS/92zyUl+kiulpePRyyqc33LqbAO2PSCQvzBup+Q
                                5HfhS4KpoXPf7nuLB4BuVMGyjg0pmeFhqpk+yY7Ny8b1
                                UYoy3jTZ82z0Kx8pxTdkU/25cLBn7HHxGIakOupcd0cF
                                LpalPqLFzmvmWATy6G2CBRKj73mfCBFK4JEr9b0= )
;; Received 609 bytes from 2001:503:c27::2:30#53(j.root-servers.net) in 165 ms

weberdns.de.            86400 IN DS 63202 8 2 (
                                2F9112FF344BCDF9C6F9A7548F04184AAE73458C7150
                                DE8FFFA3B7D9893C5EEE )
weberdns.de.            86400 IN RRSIG DS 8 2 86400 (
                                20160830060000 20160823060000 56953 de.
                                pwtHpsI4NLVHDPP43PvQNJqZ0idkAMt0PACex8+d3et7
                                f2laUbWydCkQwlFymWl+UGelXBk249vENMPUdyb5p0Je
                                9juE0n+ruvf83YNXNjFoNjMloOwc7qDA0VB/tJr0o/kX
                                56dkBHzPM4Vba4fvOBXdp4IbM16u7PWXYeMxW50= )
;; Received 250 bytes from 194.246.96.1#53(z.nic.de) in 9 ms

In the same way, the dnskeys (KSK and ZSK) can be queried:

weberjoh@jw-nb12-lx:~$ dig weberdns.de dnskey +multi

; <<>> DiG 9.10.3-P4-Ubuntu <<>> weberdns.de dnskey +multi
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 44554
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;weberdns.de.           IN DNSKEY

;; ANSWER SECTION:
weberdns.de.            448 IN DNSKEY 256 3 8 (
                                AwEAAc1G9dfFSBL+/NxRd7//80J8Hx8hjUyaQ7oaJV0t
                                OErEc1+To0BGp3FOB7fQFQ6dJIHzfRD4YO0KoJjaH4P7
                                fWO6Qs+05U6dnf2BGPy91m/4LHqM+6jzFMMf566GHxuZ
                                YB/8OkKcyRU7IS+vubtYL8jT7hqzqg+XXpQbDRlbtNgP
                                ) ; ZSK; alg = RSASHA256; key id = 57909
weberdns.de.            448 IN DNSKEY 257 3 8 (
                                AwEAAdQXI+UfqnGbHdwJtBBStf0CM8Q8nXcriaOysrpG
                                EDNkM//amUBD2YMWQ3g+htca6tmzfDJMM5D0gOk5d4Id
                                EmdywkcH+0rGLjNiNEPFnZUpwb6XsYD+ZI/WEuSlp+KC
                                EV8vwELq7VltABrFT+9Rz5CEvokTxonzQrvnfclVHaGw
                                O7cglgALsFqJCqBpvDZvEr2Z6dSepjDnFC9BPS6V8PGS
                                NwAYEtzDp/lrQojkCj28xHj2OCjpr0dIQjdjGFJTHIlc
                                9cYTAHjdPDsC8Eqfs5HcL3ruU6cbqjTn+5Lm4RdXpOWV
                                gemVvIGDnUN+v+Tma/WgtQk7U3saizNJ3epCv3s=
                                ) ; KSK; alg = RSASHA256; key id = 63202

;; Query time: 1 msec
;; SERVER: 192.168.120.22#53(192.168.120.22)
;; WHEN: Tue Aug 23 10:27:18 CEST 2016
;; MSG SIZE  rcvd: 464

Tests (AD & RRSIG)

Now, lets check the correct signing of the DNSSEC secured zone. You must use a DNSSEC validating name server, such as BIND or Unbound, as I showed in the past two blog posts. If you do not have a validating server yourself, you can use the Google public DNS server at 2001:4860:4860::8888 or 8.8.8.8 because it already does validating DNSSEC answers. (Note that your authoritative server won’t ever reply with the “ad” flag, but only with the “aa” flag. This is by design. The authoritative server must not prove his own records, because he has direct access to the source and trusts it.)

The main part when using dig is the “ad” flag within the DNS answer. This indicates the “Authentic Data” being transferred. (Ref: IANA, DNS Header Flags.)

weberjoh@jw-nb12-lx:~$ dig mail.weberdns.de

; <<>> DiG 9.10.3-P4-Ubuntu <<>> mail.weberdns.de
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 48243
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;mail.weberdns.de.              IN      A

;; ANSWER SECTION:
mail.weberdns.de.       3529    IN      A       80.154.108.237

;; Query time: 1 msec
;; SERVER: 192.168.120.22#53(192.168.120.22)
;; WHEN: Tue Aug 23 10:43:33 CEST 2016
;; MSG SIZE  rcvd: 61

In order to see the signatures (RRSIG), use dig with the +dnssec and +multi options. Now, the DNSSEC related information are displayed, as well as listed within multiple lines with some explanatory notes. Note that my domain name “mail.weberdns.de” has an A and an AAAA record. Therefore this example shows two answers along with two signatures:

weberjoh@jw-nb12-lx:~$ dig mail.weberdns.de any +dnssec +multi

; <<>> DiG 9.10.3-P4-Ubuntu <<>> mail.weberdns.de any +dnssec +multi
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 53578
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 4, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;mail.weberdns.de.      IN ANY

;; ANSWER SECTION:
mail.weberdns.de.       3505 IN RRSIG AAAA 8 3 3600 (
                                20160915070035 20160816062828 57909 weberdns.de.
                                UQCnmReXJ0jqU7u0frFR9Nj+vTPxlXB/k2h2yc9pNZht
                                GvhNYbRzvslI9P/XH1cBXphqs1YNSntMGcl/GDpR5ZK6
                                Mn0PN5LGJ+Q/SI/mVgZSSRrnFRaZn1/w0muAcintv8kq
                                Mkhh47WT2QJ2JAiaUcB8P3P/w2X57oeTr1hrawg= )
mail.weberdns.de.       3505 IN AAAA 2003:51:6012:110::15
mail.weberdns.de.       3451 IN RRSIG A 8 3 3600 (
                                20160915070035 20160816062828 57909 weberdns.de.
                                aOublailZ4XyYZEO5Wq1ucexwYrIs6LDjiwbav2wBRq1
                                ALNT4+0w6BqZ+so5xvYpH0bW9bHcXH+oJx7yUZEZi0Ka
                                IlrU96PvMKJGluqpZiuzS8jGhVQgKAfwLqKJOQzBB+4M
                                s21YkDAOu/oDiso42yP9GuFakK1JzZPhE5Z5t6Y= )
mail.weberdns.de.       3451 IN A 80.154.108.237

;; Query time: 1 msec
;; SERVER: 192.168.120.22#53(192.168.120.22)
;; WHEN: Tue Aug 23 10:44:51 CEST 2016
;; MSG SIZE  rcvd: 431

In both cases, note the AD flag.

Congratulations. You’re done. You have correctly secured your DNS zone!

Tools

There are some great online tools to verify the DNSSEC signatures. Have a look at DNSViz. It reveals and visualizes any DNS name, for example for mail.weberdns.de. Another tool is the DNSSEC Analyzer for iPhone. Here are two screenshots of these tools:

DNSViz. Great online visualizer for DNSSEC. DNSSEC Analyzer for iPhone from Verisign.

Further Reading

One key word that was not mentioned until now is: key rollover. I have only generated a single ZSK without any further expiration dates or following keys. In an upcoming blogpost I will show how to rollover the ZSK.

Furthermore, there are some cool things to come with DNSSEC: DANE and SSHFP, which I will cover in upcoming posts, too.

And keep in mind that you MUST have accurate date and time settings on your DNSSEC servers. If you’re drifting too much, all signatures will become invalid. Consider the usage of an own NTP server with different sources.

Some more links:

How to use DANE/TLSA

$
0
0
DANE featured image

DNS-based Authentication of Named Entities (DANE) is a great feature that uses the advantages of a DNSSEC signed zone in order to tell the client which TLS certificate he has to expect when connecting to a secure destination over HTTPS or SMTPS. Via a secure channel (DNSSEC) the client can request the public key of the server. This means, that a Man-in-the-Middle attack (MITM) with a spoofed certificate would be exposed directly, i.e., is not possible anymore. Furthermore, the trust to certificate authorities (CAs) is not needed anymore.

In this blog post I will show how to use DANE and its DNS records within an authoritative DNS server to provide enhanced security features for the public.

In my last posts I covered a secure installation of BIND as an authoritative DNS server, as well as the implementation of DNSSEC. This is really mandatory because without a signed DNS zone DANE would be useless. Though I am using BIND for the examples below, DANE can be used with any other DNS server, too.

What’s DANE?

The abstract of RFC 6698 “The DNS-Based Authentication of Named Entities (DANE) Transport Layer Security (TLS) Protocol: TLSA”, in which DANE is proposed, describes pretty good what DANE is: “Encrypted communication on the Internet often uses Transport Layer Security (TLS), which depends on third parties to certify the keys used. This document improves on that situation by enabling the administrators of domain names to specify the keys used in that domain’s TLS servers. This requires matching improvements in TLS client software, but no change in TLS server software.”

Today, a browser establishes a secure TLS connection to a known server (DNS name) with an “unkown” certificate (not proved by the end user). We are relying to certificate authorities (CAs), which once verified the certificate to be owned by the server operator. Unluckily, any (!) CA is able to sign every (!) certificate in the world, even if a certificate is NOT owned by the server itself, but by a malicious third party that wants to intercept the secure communication via a man-in-the-middle (MITM) attack.

With the new DNS resource record “TLSA”, the hashed public key is publicized within the DNS server of the same authority/entity that owns the TLS server, e.g., an HTTPS server or an SMTPS mail gateway. Now, an end user client can really validate that the server TLS certificate is owned by the same organization which owns the DNSSEC server. Hence, MITM attacks with spoofed certificates are not possible anymore.

For more information about DANE, refer to the RFCs: 6698, 7218, 7671, and 7672.

Generate TLSA Records

No changes must be made by the TLS servers. The only thing to do is to place the hashed public key into the DNS zone. For the most common scenarios, the fields within the TLSA record are the following (refer to RFC 7671, section 5.1):

  • Usage: 3 – DANE-EE: Domain Issued Certificate
  • Selector: 1 – SPKI: Use subject public key
  • Matching-Type: 1 – SHA-256

For an on-site generation of TLSA records the tool “tlsa” out of the “hash-slinger” toolkit can be used. On a Ubuntu server this works as follows:

weberjoh@jw-nb12-lx:~$ sudo apt-get install hash-slinger
weberjoh@jw-nb12-lx:~$ tlsa --create --selector 1 --certificate host-dane.weberdns.de.crt host-dane.weberdns.de
_443._tcp.host-dane.weberdns.de. IN TLSA 3 1 1 0d6fce3320315023ff499a3f3de1c362c88f8380311ac8c036890dab13243aa7

An easy to use online tool by Shumon Huque is here: Generate TLSA Record. Copy and paste your certificate, etc., and choose the selector field of “0 – Cert”:

Generate TLSA Records 01 Generate TLSA Records 02

In any way, the TLSA resource record for my test domain “host-dane.weberdns.de” is this:

_443._tcp.host-dane.weberdns.de. IN TLSA 3 1 1 0d6fce3320315023ff499a3f3de1c362c88f8380311ac8c036890dab13243aa7

This string must be placed into the appropriate zone file on the DNSSEC signing server, in my case “weberdns.de”. After then, I can manually test/request the TLSA record

_443._tcp. ...
  via DNS and can see that it is there authentic (AD flag):
weberjoh@jw-nb12-lx:~$ dig _443._tcp.host-dane.weberdns.de tlsa +dnssec +multi

; <<>> DiG 9.10.3-P4-Ubuntu <<>> _443._tcp.host-dane.weberdns.de tlsa +dnssec +multi
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 59953
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;_443._tcp.host-dane.weberdns.de. IN TLSA

;; ANSWER SECTION:
_443._tcp.host-dane.weberdns.de. 3066 IN TLSA 3 1 1 (
                                0D6FCE3320315023FF499A3F3DE1C362C88F8380311A
                                C8C036890DAB13243AA7 )
_443._tcp.host-dane.weberdns.de. 3066 IN RRSIG TLSA 8 5 3600 (
                                20160929094014 20160830084014 57909 weberdns.de.
                                aZgVX1C6uxACoNnPo4m36CRzMjfe2Gk7pciV2knGrb5P
                                Hbq1UV/u2EdFJD6v5Dhd4JAquuM7OW9CQVfE1f0g380/
                                HsUMzg6eZeOr3sMR2ERZXv4hut4sikdtjGhVmA6jSbfg
                                EQFM0BELYz/+Xzh9uJYoqzkbJ54uKCpapaWgELs= )

;; Query time: 1 msec
;; SERVER: 192.168.120.22#53(192.168.120.22)
;; WHEN: Tue Aug 30 11:50:16 CEST 2016
;; MSG SIZE  rcvd: 278

 

Examples

I generated three different TLSA records for my test domains (IPv6-only):

  • host-dane.weberdns.de <- with a trusted CA signed certificate
  • host-dane-self.weberdns.de <- with a self-signed (!) certificate
  • mail.weberdns.de <- with a CA signed certificate whose FQDN is NOT mail.weberdns.de

The appropriate TLSA records are the following. Note that I have some different usage and matching type fields, e.g., SHA256 and SHA512:

_443._tcp.host-dane.weberdns.de.        IN TLSA 3 1 1 0d6fce3320315023ff499a3f3de1c362c88f8380311ac8c036890dab13243aa7
_443._tcp.host-dane-self.weberdns.de.   IN TLSA 3 1 1 97b57e11a9f07976ae0a44b3d68179e61637f3ca43b719a149f8d524c0dc2405
_443._tcp.host-dane-self.weberdns.de.   IN TLSA 3 1 2 bab6316ace46fdce7028ea0100c4c0c364dc2f092258f8958b9ab1bde89c73ade3bd37aebf54245268128b039114e760b6a0d79e366c8c0b396884ab4287a05a
_25._tcp.mail.weberdns.de.              IN TLSA 3 0 1 ae822a14fd5e56c213eeeb5d6755556980caf4c3f2531c1ec8eca3076f9b7e68

Note that in all three cases a TLSA check is valid though only the first TLS certificate is correctly signed by a trusted CA with its correct common name! This is the main advantage of DANE, that self-signed certificates can be used, even with incorrect names, as long as the certificate itself is the correct one published in the DNS.

Online Tools

There are great online tools for checking TLSA records either for HTTPS or for SMTPS:

Here a two sample screenshots out of the tools for my test domains. The “host-dane-self” domain is valid though self-signed, while the “mail.weberdns.de” is valid, too, though not congruent with the name of the certificate:

host-dane-self 03 Verification mail.weberdns.de DANE Validation

A more detailed view is the text output from Shumon’s SMTPS test with STARTTLS. It greatly shows the connection (via IPv4 and IPv6), the common name of the cert, as well as the matching TLSA record:

TLSA records found: 1
TLSA: 3 0 1 ae822a14fd5e56c213eeeb5d6755556980caf4c3f2531c1ec8eca3076f9b7e68

Connecting to IPv6 address: 2003:51:6012:110::15 port 25
recv: 220 mail.webertest.net ESMTP
send: EHLO cheetara.huque.com
recv: 250-mail.webertest.net
recv: 250-8BITMIME
recv: 250-SIZE 10485760
recv: 250 STARTTLS
send: STARTTLS
recv: 220 Go ahead with TLS
TLSv1.2 handshake succeeded.
Cipher: SSLv3 DHE-RSA-AES256-SHA
Peer Certificate chain:
 0 Subject CN: mail.webertest.net
   Issuer  CN: StartCom Class 2 IV Server CA
 1 Subject CN: StartCom Class 2 IV Server CA
   Issuer  CN: StartCom Certification Authority
 SAN dNSName: mail.webertest.net
DANE TLSA 3 0 1 [ae822a14fd5e...] matched EE certificate at depth 0
Validated Certificate chain:
 0 Subject CN: mail.webertest.net
   Issuer  CN: StartCom Class 2 IV Server CA
 SAN dNSName: mail.webertest.net

Connecting to IPv4 address: 80.154.108.237 port 25
recv: 220 mail.webertest.net ESMTP
send: EHLO cheetara.huque.com
recv: 250-mail.webertest.net
recv: 250-8BITMIME
recv: 250-SIZE 10485760
recv: 250 STARTTLS
send: STARTTLS
recv: 220 Go ahead with TLS
TLSv1.2 handshake succeeded.
Cipher: SSLv3 DHE-RSA-AES256-SHA
Peer Certificate chain:
 0 Subject CN: mail.webertest.net
   Issuer  CN: StartCom Class 2 IV Server CA
 1 Subject CN: StartCom Class 2 IV Server CA
   Issuer  CN: StartCom Certification Authority
 SAN dNSName: mail.webertest.net
DANE TLSA 3 0 1 [ae822a14fd5e...] matched EE certificate at depth 0
Validated Certificate chain:
 0 Subject CN: mail.webertest.net
   Issuer  CN: StartCom Class 2 IV Server CA
 SAN dNSName: mail.webertest.net

And by the way, for more information about DANE, have a look at the resources from “sys4”. They offer a DANE mailing list as well as a common mistakes help page.

Browser Add-On: DNSSEC/TLSA Validator

The only good browser plugin for checking DNSSEC and DANE records is the “DNSSEC/TLSA Validator“. Unluckily it is not updated since almost two years (as of October 2016) and I ran into some Firefox errors while this plugin was enabled.

However, for some tests it shows the status of the DNS name (first green icon) as well as the DANE/TLSA status (second green icon):

host-dane-self 04 DNSSEC Validator host-dane-self 05 DANE Validator

Problem: SSL Interception

One problem will arise if browsers do their own DANE check (which is unluckily not happening today) while organizations are using SSL/TLS interception at their firewalls/proxies. In these cases, the SSL man-in-the-middle “attack” will spoof the certificate to an own created one which is signed by the organizations CA. Though this CA is installed in the browsers, the TLSA check will fail. To my mind, the only way to accomplish this (while not stopping the MITM) is the creation of an “Island of Trust” for DNSSEC with real-time TLSA record spoofing. (Any other ideas?)

Conclusion

That was easy! With only some little DNS resource records, much more security, i.e., authentication, can be achieved. Browsers can access self-signed websites without relying on (malicious) CAs, and MTAs (mail transfer agents) can send mails with the usage of TLS directly to the correct (authentic) destinations.

Today (2016), we are still stuck in the chicken-or-egg problem: Only some sites have DNSSEC signed TLSA records while only some end systems (browsers, MTAs) can validate them. To overcome this problem: Start signing you DNS zones now and insert as many TLSA records as you can. 😉

SSHFP: Authenticate SSH Fingerprints via DNSSEC

$
0
0
SSHFP featured image

This is really cool. After DNSSEC is used to sign a complete zone, SSH connections can be authenticated via checking the SSH fingerprint against the SSHFP resource record on the DNS server. With this way, administrators will never get the well-known “The authenticity of host ‘xyz’ can’t be established.” message again. Here we go:

The Problem

If you are an SSH admin you definitely know the following message:

pi@ntp1:~ $ ssh lx.weberdns.de
The authenticity of host 'lx.weberdns.de (2003:51:6012:110::9)' can't be established.
ECDSA key fingerprint is 49:f7:d1:ea:2c:4c:f8:0a:5b:26:08:b2:ce:7d:bb:76.
Are you sure you want to continue connecting (yes/no)? ^C

You are connecting to an SSH server the first time and you get the “can’t be established” message. And we all know: Nobody ever checks this fingerprint against a manually distributed list of fingerprints… 😉 That is: If the first attempt to a new SSH server is spoofed by a man-in-the-middle attack (or a next-generation firewall with SSH decryption), you won’t recognize it!

The Solution: SSHFP

A technical solution to overcome this “whom can you trust” problem is the secure distribution of SSHFP (Secure Shell Key Fingerprints) within the Domain Name System (DNS). If the authoritative DNS server is signed via DNSSEC, the connecting SSH client can securely verify/authenticate the fingerprint of the SSH server it is connecting to.

The standard is defined in RFC 4255 “Using DNS to Securely Publish Secure Shell (SSH) Key Fingerprints” and RFC 6594 “Use of the SHA-256 Algorithm with RSA, Digital Signature Algorithm (DSA), and Elliptic Curve DSA (ECDSA) in SSHFP Resource Records” and RFC 7470 “Using Ed25519 in SSHFP Resource Records”. The DNS SSHFP Resource Record Parameters are listed by IANA.

The only required step is to distribute the SSH fingerprints within the DNS. To accomplish this, the fingerprints must be generated/listed on the SSH server itself via the ssh tool 

ssh-keygen -r name
. This lists the fingerprints for all available public key algorithms (RSA, DSA, ECDSA, Ed25519) in SHA1 and SHA256:
weberjoh@jw-nb12:~$ ssh-keygen -r lx
lx IN SSHFP 1 1 1449b6b574092366759d72c3617fd69b6093b22e
lx IN SSHFP 1 2 9ad79ecde76840aad6c07dddd8463f95f121029b94181786f6135fb817152835
lx IN SSHFP 2 1 cb0b8a83ab63f37d475a5b44f9558c96b65f4d91
lx IN SSHFP 2 2 5d1c30f734c6b1ffdc9f5c058245db7b15591855cab0149508f58bf65ddfafb9
lx IN SSHFP 3 1 0e91f83edce8bfc7c72d4e538c28d1bbcd66fb15
lx IN SSHFP 3 2 f4c7f572af9204a753f5842848743e8c18ba832b1cee8df7d979e1217006282f
lx IN SSHFP 4 1 df623280cbffce18f0bb37fc8864df51fd3d7e90
lx IN SSHFP 4 2 4e125c92d0c3bf6162b3b253ea49a167c129b606c778a1d5940bfdbab0ae8668

After these records are placed into the DNS server zone (and signed via DNSSEC), they can be queried and validated via DNSSEC. Note the “AD” flag for authentic data within the DNS header. There is only one RRSIG record since all SSHFP records are signed at once.

weberjoh@jw-nb12-lx:~$ dig lx.weberdns.de sshfp +dnssec +multi

; <<>> DiG 9.10.3-P4-Ubuntu <<>> lx.weberdns.de sshfp +dnssec +multi
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 48421
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 9, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;lx.weberdns.de.                IN SSHFP

;; ANSWER SECTION:
lx.weberdns.de.         3589 IN SSHFP 1 1 (
                                1449B6B574092366759D72C3617FD69B6093B22E )
lx.weberdns.de.         3589 IN SSHFP 2 1 (
                                CB0B8A83AB63F37D475A5B44F9558C96B65F4D91 )
lx.weberdns.de.         3589 IN SSHFP 2 2 (
                                5D1C30F734C6B1FFDC9F5C058245DB7B15591855CAB0
                                149508F58BF65DDFAFB9 )
lx.weberdns.de.         3589 IN SSHFP 4 2 (
                                4E125C92D0C3BF6162B3B253EA49A167C129B606C778
                                A1D5940BFDBAB0AE8668 )
lx.weberdns.de.         3589 IN SSHFP 1 2 (
                                9AD79ECDE76840AAD6C07DDDD8463F95F121029B9418
                                1786F6135FB817152835 )
lx.weberdns.de.         3589 IN SSHFP 3 1 (
                                0E91F83EDCE8BFC7C72D4E538C28D1BBCD66FB15 )
lx.weberdns.de.         3589 IN SSHFP 4 1 (
                                DF623280CBFFCE18F0BB37FC8864DF51FD3D7E90 )
lx.weberdns.de.         3589 IN SSHFP 3 2 (
                                F4C7F572AF9204A753F5842848743E8C18BA832B1CEE
                                8DF7D979E1217006282F )
lx.weberdns.de.         3589 IN RRSIG SSHFP 8 3 3600 (
                                20160911095338 20160812085338 57909 weberdns.de.
                                p+r5oNKajiQXN/arL8nYtUCSGJ8kWOY/2ihxhNy/NOVB
                                MkOXQn6XI5+eEXzyl8S6y6rQ6Zc7cRXXlodyaaZGGPGc
                                vdtB+ooez7Nms2+q5t2qbpyjU/LJ9UF45iMc0cTMcJ6K
                                XuUNjjJ/pDLv8IJkURrYDSka3AGB2itdtAGdyd8= )

;; Query time: 1 msec
;; SERVER: 192.168.120.22#53(192.168.120.22)
;; WHEN: Tue Aug 30 13:58:50 CEST 2016
;; MSG SIZE  rcvd: 534

An SSH client that is configured to check the SSHFP record is now able to verify the fingerprint. If this client furthermore gets authentic data (DNSSEC validated “AD” flag), it will silently connect to the SSH server since it was able to authenticate the server. Great!

Tests

Currently, the 

VerifyHostKeyDNS
  option from the OpenSSH client is not enabled by default. That is, a connection to an unknown server will still result in the following message:
weberjoh@jw-vm08-rdns:~$ ssh lx.weberdns.de
The authenticity of host 'lx.weberdns.de (2003:51:6012:110::9)' can't be established.
ECDSA key fingerprint is SHA256:T09/p/ZSubnkraG3oslDMehfIiLRe6UiVn1dGZvtjZE.
Are you sure you want to continue connecting (yes/no)? ^C

But when used with the

-o VerifyHostKeyDNS=yes
  option, it will not warn about an unauthenticated server, because it IS authenticated now:
weberjoh@jw-vm08-rdns:~$ ssh -o VerifyHostKeyDNS=yes weberjoh@lx.weberdns.de
weberjoh@lx.weberdns.de's password:

Of course, this option can/should/must be set in the global ssh config, too:

sudo nano /etc/ssh/ssh_config
    VerifyHostKeyDNS yes

This is great at all! Customers that have many servers and firewalls placed around the world can now connect from a jump host to any of them without the fear of man-in-the-middle decrypted SSH sessions. Yeah.

Note that it is crucial that the DNS reply is DNSSEC validated. If not, OpenSSH will get the SSHFP record (“Matching host key fingerprint found in DNS.”) but will still warn such as:

pi@ntp2:~ $ ssh -o VerifyHostKeyDNS=yes weberjoh@lx.weberdns.de
The authenticity of host 'lx.weberdns.de (2003:51:6012:110::9)' can't be established.
ECDSA key fingerprint is 49:f7:d1:ea:2c:4c:f8:0a:5b:26:08:b2:ce:7d:bb:76.
Matching host key fingerprint found in DNS.
Are you sure you want to continue connecting (yes/no)? ^C

 

MD5, SHA256, Hex, Base64

What? “Why is the SSHFP fingerprint not the same as the log message from ssh?” This question took my a while to fully understand. And I am not the only one (click, click). In fact, there are several options to display fingerprints, e.g., with MD5, SHA256, either in hexadecimal or base64 notation. OpenSSH displays the fingerprint in MD5-hex or SHA256-base64 notation by default, whereas the SSHFP records list the SHA1 and SHA256 fingerprints, each in hex notation. That is: they are mutually exclusive. (Refer to OpenSSH/Cookbook/Authentication Keys. “The fingerprint can be forced to display as an MD5 hash in hexadecimal instead by passing FingerprintHash configuration directive as a runtime argument or in ssh_config. But the default is now SHA256 in base64. […] In OpenSSH 6.7 and earlier this fingerprint was a hexadecimal MD5 checksum instead a of the base64-encoded SHA256 checksum currently used.”)

The output of the fingerprint can be set to other hash algorithms, such as:

weberjoh@jw-vm08-rdns:~$ ssh -o FingerprintHash=sha256 lx.weberdns.de
The authenticity of host 'lx.weberdns.de (2003:51:6012:110::9)' can't be established.
ECDSA key fingerprint is SHA256:T09/p/ZSubnkraG3oslDMehfIiLRe6UiVn1dGZvtjZE.
Are you sure you want to continue connecting (yes/no)? ^C

Now, with some online tools, this SHA256 fingerprint can be converted from base64 to hex, which then compares to the SSHFP records. 😉 Uff.

What about PuTTY?

Unfortunately PuTTY is not supporting SSHFP yet. 🙁 It is on the wishlist a few years now, but still not supported. Of course this is bad since many admins are using Windows machines with PuTTY to manage Linux servers. However, if a central (Linux) jump server is used for connecting to all other servers/firewall/routers/whatever, SSHFP is still very useful.

As a small workaround I placed a TXT record for my Linux server on the DNS to be able to compare the fingerprint with the ssh message, such as:

pi@ntp1:~ $ host -t txt lx.weberdns.de
lx.weberdns.de descriptive text "ECDSA key fingerprint is 49:f7:d1:ea:2c:4c:f8:0a:5b:26:08:b2:ce:7d:bb:76"
pi@ntp1:~ $ ssh lx.weberdns.de
The authenticity of host 'lx.weberdns.de (2003:51:6012:110::9)' can't be established.
ECDSA key fingerprint is 49:f7:d1:ea:2c:4c:f8:0a:5b:26:08:b2:ce:7d:bb:76.
Are you sure you want to continue connecting (yes/no)? ^C

Of course this is no automatic security, but at least I can manually check whether I am talking to the correct server. (But, you know, I won’t…)

DNSSEC ZSK Key Rollover

$
0
0
"Keys" by Rosa Say is licensed under CC BY-NC-ND 2.0

One important maintenance requirement for DNSSEC is the key rollover of the zone signing key (ZSK). With this procedure a new public/private key pair is used for signing the resource records, of course without any problems for the end user, i.e., no falsified signatures, etc.

In fact it is really simply to rollover the ZSK with BIND. It is almost one single CLI command to generate a new key with certain time ranges. BIND will use the correct keys at the appropriate time automatically. Here we go:

Some Prenotes

clock
TISSOT PRC200” by tomo nosi is licensed under CC BY-NC-ND 2.0

It’s all about timing! A new ZSK must be present in the zone before (!) it signs resource records. Likewise it should remain in the zone even after it is not used anymore for some time.

The DNSSEC keys have four main dates stored within them, which are the following:

  • Publish: The time at which the key is public available in the zone
  • Activate: From this time on it is used to sign RRs
  • Inactive: No longer used to sign
  • Delete: Removed from the zone

The later on used CLI commands have the following options to specify these dates: -P, -A, -I, and -D, exactly matching the first letter of the descriptions above.

Let’s have a look at a common key rollover timing, i.e., a pre-publish phase of 1 month, while an active time of 3 months, followed by one more month (inactive) before it is deleted:

Timeline ZSK Key Rollover

Note that a new key is published in the last month of the active phase from the predecessor key. This enables all DNS resolvers to see the new key before it is actively used to sign data.

Time values are specified either discrete or with an offset: “Dates can be expressed in the format YYYYMMDD or YYYYMMDDHHMMSS. If the argument begins with a ‘+’ or ‘-‘, it is interpreted as an offset from the present time. For convenience, if such an offset is followed by one of the suffixes ‘y’, ‘mo’, ‘w’, ‘d’, ‘h’, or ‘mi’, then the offset is computed in years (defined as 365 24-hour days, ignoring leap years), months (defined as 30 24-hour days), weeks, days, hours, or minutes, respectively. Without a suffix, the offset is computed in seconds. To unset a date, use ‘none’.” (From the dnssec-settime manual.) Also note that all time values are in UTC!

dnssec-settime

To command line tool

dnssec-settime
  changes dates of existing keys. In a common scenario you have never rotated your ZSK before. That is: it has no inactive nor delete time set. But to rollover to a new ZSK (created later), the inactive and delete dates must be set. Use the -I and -D options on the existing ZSK key pair, e.g., to set the inactive date 4 month from now, while the delete date to 5 month from now:
dnssec-settime -I +4mo -D +5mo <key>

For example, I started with these values for my first ZSK from

weberdns.de
and “cat”ted the result. Note the activate and inactive dates:
weberjoh@jw-vm16-ns0:/etc/bind/keys$ sudo dnssec-settime -I +4mo -D +5mo Kweberdns.de.+008+57909
dnssec-settime: warning: Permissions on the file ./Kweberdns.de.+008+57909.private have changed from 0640 to 0600 as a result of this operation.
./Kweberdns.de.+008+57909.key
./Kweberdns.de.+008+57909.private
weberjoh@jw-vm16-ns0:/etc/bind/keys$ cat Kweberdns.de.+008+57909.key
; This is a zone-signing key, keyid 57909, for weberdns.de.
; Created: 20160205194924 (Fri Feb  5 20:49:24 2016)
; Publish: 20160205194924 (Fri Feb  5 20:49:24 2016)
; Activate: 20160205194924 (Fri Feb  5 20:49:24 2016)
; Inactive: 20161001134524 (Sat Oct  1 15:45:24 2016)
; Delete: 20161031134524 (Mon Oct 31 14:45:24 2016)
weberdns.de. IN DNSKEY 256 3 8 AwEAAc1G9dfFSBL+/NxRd7//80J8Hx8hjUyaQ7oaJV0tOErEc1+To0BG p3FOB7fQFQ6dJIHzfRD4YO0KoJjaH4P7fWO6Qs+05U6dnf2BGPy91m/4 LHqM+6jzFMMf566GHxuZYB/8OkKcyRU7IS+vubtYL8jT7hqzqg+XXpQb DRlbtNgP

That was the first step. Now let’s continue with the creation of new ZSKs:

dnssec-keygen -S

As in the first post about DNSSEC signing,

dnssec-keygen
  is used to create the keys. It has the great “-S <key>” option, described as: “Create a new key which is an explicit successor to an existing key. The name, algorithm, size, and type of the key will be set to match the existing key. The activation date of the new key will be set to the inactivation date of the existing one. The publication date will be set to the activation date minus the prepublication interval, which defaults to 30 days.” That is: referring to the last key, only the inactive and delete dates must be set to generate a new key, the publish and activate dates are set automatically. If using the “ZSK rollover every 3 month” approach while starting in 4 month from now on with the activation (due to inactivation of the first key with dnssec-settime), the -I and -D values must be incremented by 3, starting with 7 and 8:
weberjoh@jw-vm16-ns0:/etc/bind/keys$ sudo dnssec-keygen -S Kweberdns.de.+008+57909 -I +7mo -D +8mo -r /dev/urandom
Generating key pair.....++++++ ....................++++++
Kweberdns.de.+008+26703

That is: this new key

  • will be published in 3 months (that is: 1 month before the first key is “inactive”),
  • used in 4 month (because the first key is inactive in 4 month),
  • inactive in 7 month (set with -I, –> after the usage of 3 months), and
  • deleted in 8 month (set with -D, –> 1 month after inactive).

Refer to the timeline figure shown above. 😉 It helps!

And then keep on going creating new keys, each one using for 3 month, i.e., increment the I and D times by 3 such as:

sudo dnssec-keygen -S Kweberdns.de.+008+26703 -I +10mo -D +11mo
sudo dnssec-keygen -S Kweberdns.de.+008+41295 -I +13mo -D +14mo
sudo dnssec-keygen -S Kweberdns.de.+008+61119 -I +16mo -D +17mo

Create as much keys as you want, e.g., for 2-3 years. But NOTE: For the last key you are creating, don’t use the -I and -D options to have a lifetime of forever. This avoids the situation in which no key can be active anymore which would result in falsified (or even no) DNS signatures.

sudo dnssec-keygen -S Kweberdns.de.+008+07401

You should add a big reminder to your calendar to generate more keys when the old ones are inactive!

In my installation of BIND with DNSSEC signing, the *.private files must be readable by the group, so I adjusted the permissions with:

sudo chmod g+r *.private

The final step is to reload the keys for the zone:

sudo rndc loadkeys weberdns.de

Watch out the syslog entries whether BIND accepts and uses them, such as:

Sep  1 16:11:20 jw-vm16-ns0 named[1720]: received control channel command 'loadkeys weberdns.de'
Sep  1 16:11:20 jw-vm16-ns0 named[1720]: zone weberdns.de/IN (signed): reconfiguring zone keys
Sep  1 16:11:20 jw-vm16-ns0 named[1720]: zone weberdns.de/IN (signed): next key event: 01-Sep-2016 17:11:20.248

That’s it.

Examples

The following DNSViz graphs and dig listings show the process during my key rollover for weberdns.de. Refer to the descriptions below the graphs for more details:

Graph 1: The DNSKEY with id=57909 is used for all RRs. No other key is published yet. Graph 2: The new ZSK with id=26703 is published but not used yet. Graph 3: The new ZSK 26703 is used for some RRs (the SOA record) while the old 57909 ZSK has still valid signatures for other RRs. Graph 4: The old ZSK is deleted, the 26709 key signs almost all RRs, and a new ZSK with id=41295 is already present and active.

The same is true if querying the dnskeys with dig. For example, the following listing only shows the first ZSK with id = 57909:

weberjoh@jw-nb12-lx:~$ dig weberdns.de dnskey +multi

; <<>> DiG 9.10.3-P4-Ubuntu <<>> weberdns.de dnskey +multi
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 54400
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;weberdns.de.           IN DNSKEY

;; ANSWER SECTION:
weberdns.de.            3591 IN DNSKEY 257 3 8 (
                                AwEAAdQXI+UfqnGbHdwJtBBStf0CM8Q8nXcriaOysrpG
                                EDNkM//amUBD2YMWQ3g+htca6tmzfDJMM5D0gOk5d4Id
                                EmdywkcH+0rGLjNiNEPFnZUpwb6XsYD+ZI/WEuSlp+KC
                                EV8vwELq7VltABrFT+9Rz5CEvokTxonzQrvnfclVHaGw
                                O7cglgALsFqJCqBpvDZvEr2Z6dSepjDnFC9BPS6V8PGS
                                NwAYEtzDp/lrQojkCj28xHj2OCjpr0dIQjdjGFJTHIlc
                                9cYTAHjdPDsC8Eqfs5HcL3ruU6cbqjTn+5Lm4RdXpOWV
                                gemVvIGDnUN+v+Tma/WgtQk7U3saizNJ3epCv3s=
                                ) ; KSK; alg = RSASHA256; key id = 63202
weberdns.de.            3591 IN DNSKEY 256 3 8 (
                                AwEAAc1G9dfFSBL+/NxRd7//80J8Hx8hjUyaQ7oaJV0t
                                OErEc1+To0BGp3FOB7fQFQ6dJIHzfRD4YO0KoJjaH4P7
                                fWO6Qs+05U6dnf2BGPy91m/4LHqM+6jzFMMf566GHxuZ
                                YB/8OkKcyRU7IS+vubtYL8jT7hqzqg+XXpQbDRlbtNgP
                                ) ; ZSK; alg = RSASHA256; key id = 57909

;; Query time: 1 msec
;; SERVER: 192.168.120.22#53(192.168.120.22)
;; WHEN: Thu Sep 01 16:35:25 CEST 2016
;; MSG SIZE  rcvd: 464

While a few days later the next ZSK with id = 26703 was published:

weberjoh@jw-nb12-lx:~$ dig weberdns.de dnskey +multi

; <<>> DiG 9.10.3-P4-Ubuntu <<>> weberdns.de dnskey +multi
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 54177
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;weberdns.de.           IN DNSKEY

;; ANSWER SECTION:
weberdns.de.            3600 IN DNSKEY 257 3 8 (
                                AwEAAdQXI+UfqnGbHdwJtBBStf0CM8Q8nXcriaOysrpG
                                EDNkM//amUBD2YMWQ3g+htca6tmzfDJMM5D0gOk5d4Id
                                EmdywkcH+0rGLjNiNEPFnZUpwb6XsYD+ZI/WEuSlp+KC
                                EV8vwELq7VltABrFT+9Rz5CEvokTxonzQrvnfclVHaGw
                                O7cglgALsFqJCqBpvDZvEr2Z6dSepjDnFC9BPS6V8PGS
                                NwAYEtzDp/lrQojkCj28xHj2OCjpr0dIQjdjGFJTHIlc
                                9cYTAHjdPDsC8Eqfs5HcL3ruU6cbqjTn+5Lm4RdXpOWV
                                gemVvIGDnUN+v+Tma/WgtQk7U3saizNJ3epCv3s=
                                ) ; KSK; alg = RSASHA256; key id = 63202
weberdns.de.            3600 IN DNSKEY 256 3 8 (
                                AwEAAdAeTdXab14Qp3A8YjQUhu2DSkJwWC6X6Y8V4O34
                                UiRAxfXb3Z3zYIeMntyQIgSXrIiY60WW532O21borUfS
                                SReundoZiyq/GBLsPtXL1iQeLXT4QWWg9w2fg3y7Xde5
                                gzTswXazRIgMX8lqttmfIuZuU9qnWi2OoUCR5Pm2/rdj
                                ) ; ZSK; alg = RSASHA256; key id = 26703
weberdns.de.            3600 IN DNSKEY 256 3 8 (
                                AwEAAc1G9dfFSBL+/NxRd7//80J8Hx8hjUyaQ7oaJV0t
                                OErEc1+To0BGp3FOB7fQFQ6dJIHzfRD4YO0KoJjaH4P7
                                fWO6Qs+05U6dnf2BGPy91m/4LHqM+6jzFMMf566GHxuZ
                                YB/8OkKcyRU7IS+vubtYL8jT7hqzqg+XXpQbDRlbtNgP
                                ) ; ZSK; alg = RSASHA256; key id = 57909

;; Query time: 21 msec
;; SERVER: 192.168.120.22#53(192.168.120.22)
;; WHEN: Sun Sep 04 23:22:17 CEST 2016
;; MSG SIZE  rcvd: 612

 

How Often?

"Calendar*" by Dafne Cholet is licensed under CC BY 2.0
Calendar*” by Dafne Cholet is licensed under CC BY 2.0

How often should you rollover your ZSK? Well, it depends. The “use your ZSK for 3 month” opinion is quite conservative from my point of view. We are talking about 2048 bit crypto! This is used within TLS certificates that stay on the Internet for a couple of years.

You should rollover your ZSK on a regular basis to be prepared if your private key got lost. That is: to never rollover your keys is not a good advise. To my mind a good compromise is to rollover the ZSK every 6 month or 12 month. With this regularity you will practise key rollovers at least once a year while you have not that much burden.

Featured image: “Keys” by Rosa Say is licensed under CC BY-NC-ND 2.0.


DNSSEC with NSEC3

$
0
0
"Chain" by Astro is licensed under CC BY 2.0

By default DNSSEC uses the next secure (NSEC) resource record “to provide authenticated denial of existence for DNS data”, RFC 4034. This feature creates a complete chain of all resource records of a complete zone. While it has its usage to prove that no entry exists between two other entries, it can be used to “walk” through a complete zone, known as zone enumeration. That is: an attacker can easily gather all information about a complete zone by just using the designed features of DNSSEC.

For this reason NSEC3 was introduced: It constructs a chain of hashed and not of plain text resource records (RFC 5155). With NSEC3 enabled it is not feasible anymore to enumerate the zone. The standard uses a hash function and adds the NSEC3PARAM resource record to the zone which provides some details such as the salt.

In this post I will show how to create the KSK and ZSK keys that are NSEC3-capable and how to insert the NSEC3PARAM parameters to the zone. (For an introduction of DNSSEC with BIND refer to this blog post or note the DNSSEC category on my blog.) For now I am using another test domain:

sshfp.net
 . I will also show some dig commands for verifying the NSEC3 hashes.

NSEC3-Capable Algorithm

The first step to sign the zone is the creation of appropriate keys. The command line interface tool

dnssec-keygen
  provides the
-3
  option: “Use an NSEC3-capable algorithm to generate a DNSSEC key. If this option is used and no algorithm is explicitly set on the command line, NSEC3RSASHA1 will be used by default. Note that RSASHA256, RSASHA512, ECCGOST, ECDSAP256SHA256 and ECDSAP384SHA384 algorithms are NSEC3-capable.” I decided to use the RSASHA512 algorithm, so here are my commands for the generation of the KSK and the ZSK, as well as the correct permissions (refer to my lasts posts):
cd /etc/bind/keys/
sudo dnssec-keygen -a RSASHA512 -b 2048 -3 -f KSK -r /dev/urandom sshfp.net
sudo dnssec-keygen -a RSASHA512 -b 2048 -3 -r /dev/urandom sshfp.net
sudo chmod g+r *.private
sudo rndc loadkeys sshfp.net

(I also tried the algorithm number 14, ECDSAP384SHA384, but this did not work at all. rndc was not responding anymore. Maybe this is related to a bug in my BIND version?)

Note that up to this point the mere NSEC is still used for signing the zone. To enable NSEC3, follow the next step:

Adding the Salt

To tell the zone to use NSEC3, the NSEC3PARAM resource record must be inserted. This is done with

rndc signing -nsec3param
 : “rndc signing -nsec3param sets the NSEC3 parameters for a zone. […] Parameters are specified in the same format as an NSEC3PARAM resource record: hash algorithm, flags, iterations, and salt, in that order.”

There is only one registered hash function that is used for NSEC3, namely SHA1, refer to DNSSEC NSEC3 Hash Algorithms. (Why aren’t there any better hash functions yet? Short discussion here.) SHA1 has value number 1 listed within the nsec3param section. The flags parameter is left by 0. For the hash iterations I chose 10. (Some notes are here.) This sets the cost of computing a dictionary for the attacker, as well as the cost for signing the zone. To my mind 10 is a good starting point but it could be increased if needed.

"Kosher Salt" by stlbites.com is licensed under CC BY-ND 2.0
Kosher Salt” by stlbites.com is licensed under CC BY-ND 2.0

Finally, a salt must be set to prevent precomputed dictionary attacks. Choose a random salt, e.g., by using a password generator. Some other tutorials recommend a salt length of 8 hexadecimal digits, but it can be much longer. However, I used 8 digits, too. (“The salt SHOULD be at least 64 bits long and unpredictable, so that an attacker cannot anticipate the value of the salt and compute the next set of dictionaries before the zone is published”, RFC 5155 section 12.1.1.)

 

In the end this is my rndc command to use NSEC3 for my zone called “sshfp.net”:

sudo rndc signing -nsec3param 1 0 10 5053851B sshfp.net.

Without any other commands BIND is now using NSEC3 with the just defined parameters.

Test with Dig

The first step to test is the presence of the nsec3param record. Answer in line 15:

weberjoh@jw-nb12-lx:~$ dig sshfp.net nsec3param +noadditional +noauthority

; <<>> DiG 9.10.3-P4-Ubuntu <<>> sshfp.net nsec3param +noadditional +noauthority
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 45143
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;sshfp.net.                     IN      NSEC3PARAM

;; ANSWER SECTION:
sshfp.net.              0       IN      NSEC3PARAM 1 0 10 5053851B

;; Query time: 5 msec
;; SERVER: 192.168.120.22#53(192.168.120.22)
;; WHEN: Fri Nov 11 15:54:13 CET 2016
;; MSG SIZE  rcvd: 59

The more interesting test case is querying a non-existent domain. With mere NSEC, some plain text FQDNs would be revealed. Not so with NSEC3 which shows many (and long …) hashes, as well as the DNSSEC signatures (which are even longer in my case since I used the SHA512 hash for signing …):

weberjoh@jw-nb12-lx:~$ dig foobar.sshfp.net +dnssec

; <<>> DiG 9.10.3-P4-Ubuntu <<>> foobar.sshfp.net +dnssec
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 24021
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 6, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;foobar.sshfp.net.              IN      A

;; AUTHORITY SECTION:
sshfp.net.              159     IN      SOA     ns1.weberdns.de. webmaster.weberdns.de. 2016090128 3600 900 2419200 180
sshfp.net.              159     IN      RRSIG   SOA 10 2 86400 20161208021634 20161108011634 31055 sshfp.net. kCY+TA1Q/RdjdzpMc1CHihGB+t4ou8QZPwuhzvkRkrYxicdXY320b+dO akTIcddJinI6dGo70OrRq+cWV9A9IAK7aak0Nonj/V20mHUzCVeaRrqp iBD1RjnKxNRqX5rb+fvf6S4NuzynGP57PWnntLqB/AnDljHcrBhN9IHe i87K0JsK/cmGzPCq9Dz50Tg4/7Pq3kI9p5pfdeRwLXyzIu4cb0BNIDvl MchVhTx/m44UbLdRlA9dzbZQuAZj5k5HqiDZFbwidK98w8AeMMbRy71P D16GvKnoIsOm3Ew+EcX0gCBWqcmccExm5zeiQkLf7KmDdDRVMvdd5uyK yZIE4w==
NA9D0NB498S0ROOIF2NGLHQF85HQLKJP.sshfp.net. 159 IN RRSIG NSEC3 10 3 180 20161207204758 20161107195347 31055 sshfp.net. GLqlvFaWiemLree+4WQeR+0ANSEYeuLW/KEWZw9mZPUJ1bcb1OQCxp43 7DNdPCSmS/RqJGiVGtSW8xsGoRgUwOdczL8s4j/z3pVi8wDlhw2jXE0k fGBiOshH+3VjZV4eLlDmDixZ3WmA9gzf0G+qAwRP9tjps2+vqRfXOpoj /UffmcMgZODEDGonHAOX/k35sBL+zIP4k6i6Kq/lpPZd8oxsxCwyxAYl E1oMxeE14TnRZoqCZdAEgvrViF91z/tnMbYAY/JNWYK4iREOuuWTLOox C0hKBsymi3fyLjwZ1NV1Bh3lqYN0rr1uo8ZSZmGrfLdg4l+hO4Xl6kG6 JTn27Q==
NA9D0NB498S0ROOIF2NGLHQF85HQLKJP.sshfp.net. 159 IN NSEC3 1 0 10 5053851B PF2TNEL79K4HTCBINCDBE9FPBU5I04KD A NS SOA MX AAAA RRSIG DNSKEY NSEC3PARAM TYPE65534
PTBUDK4PK9HRK5HKTF5JVSULBP75V0AK.sshfp.net. 159 IN RRSIG NSEC3 10 3 180 20161208011815 20161108010731 31055 sshfp.net. h3TaJpQU9JXAMY7Eu4cjS28rdXxiPpm9VDjugpr71ilpSGo6UCowXaoE 44FMQWqRXj57yXrRyjFS2BDKBa6r5FIG5hM3jye04ksJxoT95ZgH9dVN wXf45oc/vh0v9BFaQi2a/7CFmTeUf36qaEdS1duTaQOMuV9fqLhQhzwQ nga40LIHCFqHJYmOPK2R41fn8VfpxD2fI95oCYCtLr6HQkmQ2uGWGSvF fxi+zAs0I1O5zyoc6JedbX7mFVs63/6B2Q9H9rYZbPnm92Py/OKTCR9Z kX1/6NA2DQZuTJKaZf7q/qKOdSmmkX7Np8Nc52Evdzw6yTFKT031SN8X L9UNWQ==
PTBUDK4PK9HRK5HKTF5JVSULBP75V0AK.sshfp.net. 159 IN NSEC3 1 0 10 5053851B 4B37B7ENKCCOB0IM83C004NA76LA3V4T A RRSIG

;; Query time: 1 msec
;; SERVER: 192.168.120.22#53(192.168.120.22)
;; WHEN: Fri Nov 11 15:58:09 CET 2016
;; MSG SIZE  rcvd: 1198

In fact, no other DNS leaves are revealed with this query. Great!

Changing the Salt

“The salt SHOULD be changed periodically to prevent pre-computation using a single salt”, RFC 5155 section C.1.

Ok, so let’s change the salt exemplary. This is really simple because it only requires the single rndc command I already showed. For this example I increased the size of the salt to 32 bytes (128 bits) as well as the hash iteration from 10 to 20:

sudo rndc signing -nsec3param 1 0 20 80637d8af055b5eeca2a621edaaa3c5e sshfp.net.

Without any problems BIND signed the complete zone with this new parameters. Here is the new nsec3param answer:

weberjoh@jw-nb12-lx:~$ dig sshfp.net nsec3param

; <<>> DiG 9.10.3-P4-Ubuntu <<>> sshfp.net nsec3param
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 48904
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 3, ADDITIONAL: 4

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;sshfp.net.                     IN      NSEC3PARAM

;; ANSWER SECTION:
sshfp.net.              0       IN      NSEC3PARAM 1 0 20 80637D8AF055B5EECA2A621EDAAA3C5E

;; AUTHORITY SECTION:
sshfp.net.              172800  IN      NS      ns1.weberdns.de.
sshfp.net.              172800  IN      NS      ns3.weberdns.de.
sshfp.net.              172800  IN      NS      ns2.weberdns.de.

;; ADDITIONAL SECTION:
ns1.weberdns.de.        86400   IN      A       80.154.108.230
ns1.weberdns.de.        86400   IN      AAAA    2003:51:6012:110::a07:53
ns2.weberdns.de.        86400   IN      A       213.61.29.182

;; Query time: 150 msec
;; SERVER: 192.168.120.22#53(192.168.120.22)
;; WHEN: Mon Nov 14 11:20:00 CET 2016
;; MSG SIZE  rcvd: 196

And the NSEC3 answer for a non-existent domain which also shows the new salt, etc. Note that some NXDOMAIN answeres have 3 different NSEC3 records, refer to RFC 7129, section 5 (a litte bit complicated though). Furthermore note that for the following listing I wrapped the lines in the output to see the whole big bunch of the answer 😉 :

weberjoh@jw-nb12-lx:~$ dig foobar.sshfp.net +dnssec

; <<>> DiG 9.10.3-P4-Ubuntu <<>> foobar.sshfp.net +dnssec
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 12968
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 8, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;foobar.sshfp.net.              IN      A

;; AUTHORITY SECTION:
sshfp.net.              180     IN      SOA     ns1.weberdns.de. webmaster.weberdns.de. 2016090133 3600 900 2419200 180
sshfp.net.              180     IN      RRSIG   SOA 10 2 86400 20161214101931 20161114091931 31055 sshfp.net. jh67fVaz7t9W5JGtgd+Ac3IxmT6hVVIHGzvzpikZ01ITZmtR6vE/A1/Y AZidYoTtSbVOO396cwewtMR+VjS8zP/LrYzZoKSmHVY7sqLYKhV7Cw/O xcDxwIo3/EWPSuu2xNzONGVwlZ9MPvFk7PIql7O1/mFNRNygP3oZWLIW 7yTEs28LRmFl/4l3jrFXGoZtk/IxaWCVONrqW0ThfUzppN1U6bSiFLkA PT2NajPPQaUoSHBME7PNy8fQMEUzijqfD1p+++KSQlChUN6ccedm0AXK 2Cf42k7g4zSPlDenSNYNWZ9M09Pl3Ctkw17LN0wYqqE70jtyR8Y9qVJ7 fNlqcA==
1009PRUOMI99TQ7NKVD75UH5KSVG82EV.sshfp.net. 180 IN RRSIG NSEC3 10 3 180 20161214094443 20161114091931 31055 sshfp.net. Z305JjP/bCNjuLhbgx0UheRQq0ZyZgzwYiy59D0Dnxb9NO3B/caVlM0S OnqM6zjkM+xpX8QGGMVrM4xVfya/4ajOFf7/c6CL03i0v+UQ6nyPcZ5j 17hpetBW1RpTkLXnpXTfaGtNYbBC4scMj41kU9Gxj2jophQ34dgcZkJ9 lBsLQjfKva1IQOyUTBrWVo8+zjj0k07P3n3ocEp3UXf62LZEurCaMmaM iQvOsWtVDOVjsI8lmQR3d3jelCuRkXBEa7tFfFsf0jWKZ6lbTLoSXGMz RQGKQqOy7yQUjxQbuQ6vBf+N6mAe0YGH56sm1+Z/SScgpnpTAviDF9nx rj4Sow==
1009PRUOMI99TQ7NKVD75UH5KSVG82EV.sshfp.net. 180 IN NSEC3 1 0 20 80637D8AF055B5EECA2A621EDAAA3C5E 3J6JP5RLFGU7E10AMBAKNT7UGEBP6IUI A RRSIG
F5AFOMBUT7BNO1I94Q43Q6F1KJAKEJB5.sshfp.net. 180 IN RRSIG NSEC3 10 3 180 20161214092455 20161114091931 31055 sshfp.net. nCAgLDaro/t1MixVVIg2ClnnGuZ8C8YVVt1VwKJWfJr7N8JFKILJGjkM GKvvRltQAfNtTpBmUYYwP7HXDISoL3X3ruM5PNZwBNjJ0x+E7LU9MCb7 uBhuoE9eKP69L9IGefUWzL5UZYW+T288V1bjayVNZi4UsZY7TwY2WDcJ Ef25HuvZskBooTgePf5+++kZti8Qm13rwh65jSSzQQPP2OjdwZJic1HP bwqGjnu2RzzxzSfHLQvyz9Xny43uT9IImZCSwTJW/bhsghhRiv79HK8o dPqWW+l5xqdbgTTwM9Rw52k6MboU+pD1z4HAFxEjZ5iq6H81WRZLfnOq ig59OA==
F5AFOMBUT7BNO1I94Q43Q6F1KJAKEJB5.sshfp.net. 180 IN NSEC3 1 0 20 80637D8AF055B5EECA2A621EDAAA3C5E QOERG35FBV9KBEKT0HHJ603KARPRHA6E A RRSIG
VLQ247QI8P1TT3A8CGMD7GLFNDTIGSDU.sshfp.net. 180 IN RRSIG NSEC3 10 3 180 20161214092455 20161114091931 31055 sshfp.net. f62YeWWFM9+d+jqVRJWVHkkgLL740EO6fCv5sQghuRCCJTzZbehRN365 3X5YNvOFvbZtR7i41SGV2+XXV5U8JgqzW0jc9+bw2k8lK2cQF/nfodLN RSoxymiqN6mNesEsb3ovCDTamB5gSCs7bj+iT7pS8NqtctkhTRYDPJAT lAId0H6cmL486msfeziU2fAelHx++Tc29II7PhYN87VOgtWQV02omkG1 Ysp8NCm4KQbuXQnXZ9aF6nFIIB70sA95kyND4dt0WNXkRwR0CUrv53sM X2Pvcop56jl3ssdgLqb79BlYU/dZrfhUjpLXfAXaRFp3jSvukSj9qcYu bsS6bQ==
VLQ247QI8P1TT3A8CGMD7GLFNDTIGSDU.sshfp.net. 180 IN NSEC3 1 0 20 80637D8AF055B5EECA2A621EDAAA3C5E 1009PRUOMI99TQ7NKVD75UH5KSVG82EV A NS SOA MX AAAA RRSIG DNSKEY NSEC3PARAM TYPE65534

;; Query time: 9 msec
;; SERVER: 192.168.120.22#53(192.168.120.22)
;; WHEN: Mon Nov 14 11:21:14 CET 2016
;; MSG SIZE  rcvd: 1614

That’s it. 😉 Good luck.

Links

Featured image: “Chain” by Astro is licensed under CC BY 2.0.

How to walk DNSSEC Zones: dnsrecon

$
0
0
"Autumn leaves" by  Nicu Buculei is licensed under CC BY-SA 2.0

After the implementation of DNS and DNSSEC (see the last posts) it is good to do some reconnaissance attacks against the own DNS servers. Especially to see the NSEC or NSEC3 differences, i.e., whether zone walking (enumeration) is feasible or not.

For many different kinds of DNS reconnaissance the tool dnsrecon can be used. In this post I will focus on the

-z
  option which is used for DNSSEC zone walking, i.e., walk leaf by leaf of the whole DNS zone.

Installation

There are official installation instructions (great!) that work without any errors. On my Ubuntu 16.04.1 LTS it worked exactly like this:

sudo apt-get install libavahi-compat-libdnssd1 git-core python-setuptools
sudo easy_install netaddr
sudo easy_install dnspython
git clone git://github.com/darkoperator/dnsrecon.git
cd dnsrecon/
./dnsrecon.py

Note the helping page which gives a few hints how dnsrecon can be used to do dictionary or brute force attacks, or even how to use Google to search for subdomains and hosts.

DNSSEC Zone Walking

To walk a zone use the

-z
  option. In the following example I am walking through my own domain
weberdns.de
  which uses only NSEC (instead of NSEC3) and is therefore prone to zone walks.
The enumeration starts at line 21:
weberjoh@jw-nb12-lx:~/dnsrecon$ ./dnsrecon.py -d weberdns.de -z
[*] Performing General Enumeration of Domain: weberdns.de
[*] DNSSEC is configured for weberdns.de
[*] DNSKEYs:
[*]     NSEC ZSK RSASHA256 03010001cd46f5d7c54812fefcdc5177 bffff3427c1f1f218d4c9a43ba1a255d 2d384ac4735f93a34046a7714e07b7d0 150e9d2481f37d10f860ed0aa098da1f 83fb7d63ba42cfb4e54e9d9dfd8118fc bdd66ff82c7a8cfba8f314c31fe7ae86 1f1b99601ffc3a429cc9153b212fafb9 bb582fc8d3ee1ab3aa0f975e941b0d19 5bb4d80f
[*]     NSEC KSk RSASHA256 03010001d41723e51faa719b1ddc09b4 1052b5fd0233c43c9d772b89a3b2b2ba 4610336433ffda994043d9831643783e 86d71aead9b37c324c3390f480e93977 821d126772c24707fb4ac62e33623443 c59d9529c1be97b180fe648fd612e4a5 a7e282115f2fc042eaed596d001ac54f ef51cf9084be8913c689f342bbe77dc9 551da1b03bb72096000bb05a890aa069 bc366f12bd99e9d49ea630e7142f413d 2e95f0f19237001812dcc3a7f96b4288 e40a3dbcc478f63828e9af4748423763 1852531c895cf5c6130078dd3c3b02f0 4a9fb391dc2f7aee53a71baa34e7fb92 e6e11757a4e59581e995bc81839d437e bfe4e66bf5a0b5093b537b1a8b3349dd ea42bf7b
[*]      SOA ns1.weberdns.de 80.154.108.230
[*]      NS ns2.weberdns.de 213.61.29.182
[*]      Bind Version for 213.61.29.182 9.9.5-3ubuntu0.8-Ubuntu
[*]      NS ns1.weberdns.de 80.154.108.230
[*]      Bind Version for 80.154.108.230 9.9.5-3ubuntu0.8-Ubuntu
[*]      NS ns1.weberdns.de 2003:51:6012:110::a07:53
[*]      Bind Version for 2003:51:6012:110::a07:53 9.9.5-3ubuntu0.8-Ubuntu
[*]      MX mail.weberdns.de 80.154.108.237
[*]      MX mail.weberdns.de 2003:51:6012:110::15
[*]      A weberdns.de 80.154.108.230
[*]      AAAA weberdns.de 2003:51:6012:110::a07:53
[*] Enumerating SRV Records
[-] No SRV Records Found for weberdns.de
[+] 0 Records Found
[*] Performing NSEC Zone Walk for weberdns.de
[*] Getting SOA record for weberdns.de
[*] Name Server 80.154.108.230 will be used
[*]      A weberdns.de 80.154.108.230
[*]      AAAA weberdns.de 2003:51:6012:110::a07:53
[*]      A fg.weberdns.de 80.154.108.233
[*]      AAAA fg.weberdns.de 2003:51:6012::4
[*]      AAAA host-dane.weberdns.de 2003:51:6012:110:e995:f904:c293:f36a
[*]      AAAA host-dane-self.weberdns.de 2003:51:6012:110:b1dc:bada:5bf5:ca54
[*]      AAAA host-dnssec.weberdns.de 2003:51:6012:110:c2b6:ca25:284f:9033
[*]      AAAA ip.weberdns.de 2003:51:6012:110::19
[*]      A ip.weberdns.de 80.154.108.235
[*]      A lx.weberdns.de 80.154.108.239
[*]      AAAA lx.weberdns.de 2003:51:6012:110::9
[*]      A mail.weberdns.de 80.154.108.237
[*]      AAAA mail.weberdns.de 2003:51:6012:110::15
[*]      A ns0.weberdns.de 80.154.108.226
[*]      AAAA ns0.weberdns.de 2003:51:6012:120::a16:53
[*]      A ns1.weberdns.de 80.154.108.230
[*]      AAAA ns1.weberdns.de 2003:51:6012:110::a07:53
[*]      A ns1-v4.weberdns.de 80.154.108.230
[*]      AAAA ns1-v6.weberdns.de 2003:51:6012:110::a07:53
[*]      A ns2.weberdns.de 213.61.29.182
[*]      A ns3.weberdns.de 193.24.225.53
[*]      A pa.weberdns.de 80.154.108.228
[*]      AAAA pa.weberdns.de 2003:51:6012::2
[*]      A sub.sub.weberdns.de 203.0.113.3
[*]      A ttl-long.weberdns.de 198.51.100.255
[*]      A ttl-short.weberdns.de 198.51.100.0
[*]      A txt.weberdns.de no_ip
[*]      A viola.weberdns.de no_ip
[*]      AAAA webmail.weberdns.de 2003:51:6012:110::19
[*]      A webmail.weberdns.de 80.154.108.235
[*]      AAAA www.weberdns.de 2a01:488:42:1000:50ed:8588:8a:c570
[*]      A www.weberdns.de 80.237.133.136
[+] 576 records found

"Füße" by Robert Agthe is licensed under CC BY 2.0
Füße” by Robert Agthe is licensed under CC BY 2.0

That is: All (!) FQDNs are exposed within a few seconds. No brute-force or dictionary attacks are needed. The NSEC records reveal the whole zone!

However, note that not all records are listed though, e.g., my TLSA (DANE) or SSHFP records. Furthermore, not all types are listed correctly, e.g., CNAMEs. But it’s just because the dnsrecon tool does not query all of them. It is not because it’s not possible.

Following is a Wireshark (tcpdump) capture that shows an example while dnsrecon was running:

dnsrecon weberdns.de Wireshark Screenshot

Trying to walk NSEC3

Well, as per design (RFC 5155), this is not possible. NSEC3 uses hashes instead of plain text domain names. That is, zone walking is not feasible anymore. In the following example I am trying to walk through my domain

sshfp.net
  which uses NSEC3. Starting with line 23, nothing happens:
weberjoh@jw-nb12-lx:~/dnsrecon$ ./dnsrecon.py -d sshfp.net -z
[*] Performing General Enumeration of Domain: sshfp.net
[*] DNSSEC is configured for sshfp.net
[*] DNSKEYs:
[*]     NSEC3 ZSK RSASHA512 030100019ffa1f794b286687079b7dd2 660b6e0ee56a471c070a90a8213eb6d4 5e058fbbd0eb57bdb62300c0be18a146 1f60747417661ae057bc17903b98cdf0 6ac5e885ceec04d06d72d791723f019d a2599ed6d1f814212a0f6842a5c276a5 3bdd0a7fad63bbac04a6af2dc5c684cb ac97479368076d44237ac4955bfa8e4a 3a5d38dca8c13b7d951b3caabfb65b14 2f1fdc7051654526b733db1c37cf54c4 4f7652619f619e35062a11dfd0ce71ee 60e61d8b1891db29e90f3ded4a8eb1a7 cbcb9456d0b35d176a7667381fc6b466 f1092a11741f1ec9ed5072324ab6af87 84e2cdc5963a11b4b008c8cd84616701 acb942feb5775d327b04a22ff8d45497 8e09361b
[*]     NSEC3 KSk RSASHA512 03010001cb77f7287ebe3f0f6a144f9f 3d427a84c15d99d1e0abd620d6e38637 9cc6c1dbd102e3d9c928e0228bd4d75b 6cfa7643647bbd678e69bebcfd3ca125 b1c1a37747268035da5e513e08b84bfd 5e9b11e15041b7d6d7908b9b6a69fb0f 5609d543acfb848a9eef4df897deef56 56eae7336c0f82347ecadc7884baa799 b7438c8c2a0435664a36e97f1d235a01 d4e4b574f072ba0308e47d9b8c65cad7 363e0062a8b050d36ad4c63e6f811f34 4b3f3dc6ab20da8f5c0758aa82e278d4 cb4f3d3978dc71600012a30d3afc9ad6 e9ca57ae8ea751ffafd11432171a7926 5ca6766696b0f8c836c77313c532cce8 c48fc69eb50293b01d8e72039130b612 b7d2bcf9
[*]      SOA ns1.weberdns.de 80.154.108.230
[*]      NS ns3.weberdns.de 193.24.225.53
[*]      Bind Version for 193.24.225.53 9.9.5-3ubuntu0.8-Ubuntu
[*]      NS ns1.weberdns.de 80.154.108.230
[*]      Bind Version for 80.154.108.230 9.9.5-3ubuntu0.8-Ubuntu
[*]      NS ns1.weberdns.de 2003:51:6012:110::a07:53
[*]      Bind Version for 2003:51:6012:110::a07:53 9.9.5-3ubuntu0.8-Ubuntu
[*]      NS ns2.weberdns.de 213.61.29.182
[*]      Bind Version for 213.61.29.182 9.9.5-3ubuntu0.8-Ubuntu
[*]      MX mail.weberdns.de 80.154.108.237
[*]      MX mail.weberdns.de 2003:51:6012:110::15
[*]      A sshfp.net 80.154.108.235
[*]      AAAA sshfp.net 2003:51:6012:110::19
[*] Enumerating SRV Records
[-] No SRV Records Found for sshfp.net
[+] 0 Records Found
[*] Performing NSEC Zone Walk for sshfp.net
[*] Getting SOA record for sshfp.net
[*] Name Server 80.154.108.230 will be used
[*]      A sshfp.net 80.154.108.235
[*]      AAAA sshfp.net 2003:51:6012:110::19
[+] 2 records found

That’s it. If you want to hide your DNS zones, use NSEC3. But as already noted many times, security by obscurity is not a good design at all. 😉 If you want to understand your DNS replies easily, NSEC3 is not preferred.

Another Tool: dnssecwalk

Just after finishing this post I found another tool that perfectly fits for walking DNSSEC zones. It comes out of the great THC-IPv6 toolkit from van Hauser. (Google for installation guides. There are many out there.) The usage of the

dnssecwalk
  tool is really easy and it reveals all (!) records incl. the TLSA ones:

weberjoh@jw-vm09-nmap:~$ dnssecwalk
dnssecwalk v1.2 (c) 2015 by Marc Heuse <mh@mh-sec.de> http://www.mh-sec.de

Syntax: dnssecwalk [-e46] dns-server domain

Options:
 -e  ensure that the domain is present in found addresses, quit otherwise
 -4  resolve found entries to IPv4 addresses
 -6  resolve found entries to IPv6 addresses

Perform DNSSEC NSEC walking.

Example: dnssecwalk dns.test.com test.com
weberjoh@jw-vm09-nmap:~$
weberjoh@jw-vm09-nmap:~$
weberjoh@jw-vm09-nmap:~$ dnssecwalk 8.8.8.8 weberdns.de
Starting DNSSEC walking on server 8.8.8.8 about weberdns.de.
Found: 16a.weberdns.de.
Found: 16aaaa.weberdns.de.
Found: 16dual.weberdns.de.
Found: 32a.weberdns.de.
Found: 32aaaa.weberdns.de.
Found: 32aaaa-long.weberdns.de.
Found: 32dual.weberdns.de.
Found: 32dual-long.weberdns.de.
Found: 64a.weberdns.de.
Found: 64aaaa.weberdns.de.
Found: 64dual.weberdns.de.
Found: fg.weberdns.de.
Found: host-dane.weberdns.de.
Found: _443._tcp.host-dane.weberdns.de.
Found: host-dane-self.weberdns.de.
Found: _443._tcp.host-dane-self.weberdns.de.
Found: host-dnssec.weberdns.de.
Found: ip.weberdns.de.
Found: lx.weberdns.de.
Found: mail.weberdns.de.
Found: _25._tcp.mail.weberdns.de.
Found: ns0.weberdns.de.
Found: ns1.weberdns.de.
Found: ns1-v4.weberdns.de.
Found: ns1-v6.weberdns.de.
Found: ns2.weberdns.de.
Found: ns3.weberdns.de.
Found: pa.weberdns.de.
Found: sub.sub.weberdns.de.
Found: ttl-long.weberdns.de.
Found: ttl-short.weberdns.de.
Found: txt.weberdns.de.
Found: viola.weberdns.de.
Found: webmail.weberdns.de.
Found: www.weberdns.de.
Done, 35 entries found.

 

Featured image: “Autumn leaves” by Nicu Buculei is licensed under CC BY-SA 2.0.

Compare & Troubleshoot DNS Servers: dnseval

$
0
0
"Werkzeug" by Andreas Issleib is licensed under CC BY-NC-ND 2.0

The third tool out of the DNSDiag toolkit from Babak is dnseval. “dnseval is a bulk ping utility that sends an arbitrary DNS query to a given list of DNS servers. This script is meant for comparing response times of multiple DNS servers at once”. It is not only listing the response times but also further information about the DNS responses such as the TTL and the flags. Really great for comparison and troubleshooting different DNS forwarders as well as own authoritative DNS server responses as seen by others.

At first I want to thank Babak for adding so many feature requests I have sent to him. (More than ten!) Also note the two other tools from him, dnsping and dnstraceroute which I covered in other blog posts.

./dnseval with own server list

When called without any options dnseval displays a short info page:

weberjoh@jw-nb12-lx:~/dnsdiag$ ./dnseval.py
dnseval.py version 1.5

usage: dnseval.py [-h] [-f server-list] [-c count] [-t type] [-w wait] hostname
  -h  --help      show this help
  -f  --file      dns server list to use (default: system resolvers)
  -c  --count     number of requests to send (default: 10)
  -w  --wait      maximum wait time for a reply (default: 2)
  -t  --type      DNS request record type (default: A)
  -T  --tcp       Use TCP instead of UDP
  -e  --edns      Disable EDNS0 (Default: Enabled)

Note the

-f <file>
  option that uses a file which lists all the servers dnseval should query. I am always using an own list with the following entries, of course with both, IPv6 and legacy IP addresses:
  • the DNS forwarders from my ISP (Deutsche Telekom)
  • common public servers (Google Public DNS, OpenDNS)
  • my own internal recursive DNS servers (BIND, Unbound)
  • some other router/firewall/CPE DNS forwarders (Palo Alto DNS Proxy, FRITZ!Box)
  • own authoritative DNS servers (BIND).

With this big list I can check many different DNS problems as shown below:

A Picture is worth a Thousand Words

Have a look at the following sample output from dnseval and all the information you can gather out of it. (If you are not familiar with the DNS header flags, have a look here.) I queried the FQDN

fg.weberdns.de
  which I have on my own authoritative DNS servers. That is I can check whether all of these DNS servers are able to reach out my own authoritative ones:
weberjoh@jw-nb12-lx:~/dnsdiag$ ./dnseval.py -f ../dns-servers fg.weberdns.de
server                    avg(ms)     min(ms)     max(ms)     stddev(ms)  lost(%)  ttl        flags
------------------------------------------------------------------------------------------------------------------
194.25.0.68               10.998      4.044       16.210      4.496       %0       3600       QR -- -- RD RA -- --
194.25.0.60               21.514      8.169       32.698      6.527       %0       3600       QR -- -- RD RA -- --
2003:40:2000::53          8.531       3.488       21.811      6.498       %0       3600       QR -- -- RD RA -- --
2003:56::53               19.255      8.444       31.983      9.074       %0       3600       QR -- -- RD RA -- --
8.8.8.8                   44.967      12.262      78.750      22.474      %0       3599       QR -- -- RD RA AD --
8.8.4.4                   130.931     14.610      1059.192    326.610     %0       3598       QR -- -- RD RA AD --
2001:4860:4860::8888      17.181      13.751      20.350      3.152       %0       3598       QR -- -- RD RA AD --
2001:4860:4860::8844      22.530      14.902      58.615      12.892      %0       3599       QR -- -- RD RA AD --
resolver1.opendns.com     14.336      3.790       39.841      14.940      %0       3600       QR -- -- RD RA -- --
resolver2.opendns.com     4.347       3.686       7.650       1.173       %0       3600       QR -- -- RD RA -- --
ns1-v4.weberdns.de        6.710       5.903       13.215      2.287       %0       3600       QR AA -- RD -- -- --
ns1-v6.weberdns.de        4.490       4.101       5.710       0.645       %0       3600       QR AA -- RD -- -- --
ns2.weberdns.de           10.220      9.644       12.352      0.862       %0       3600       QR AA -- RD -- -- --
ns3.weberdns.de           24.978      24.110      26.742      0.834       %0       3600       QR AA -- RD -- -- --
int-dns.webernetz.net     6.559       5.929       9.449       1.098       %0       3599       QR -- -- RD RA AD --
192.168.110.1             2.233       2.048       2.594       0.164       %0       3463       QR -- -- -- -- -- --
192.168.7.1               8.359       6.431       21.811      4.739       %0       3600       QR -- -- RD RA AD --
192.168.7.5               15.352      11.708      46.910      11.091      %0       3600       QR -- -- RD RA AD --

You can see the following:

  • every server was reachable (0 % lost) and answered (QR = query response flag)
  • the OpenDNS server were faster than the Google Public DNS servers
  • the TTL seems to be correct by all servers (3600 seconds are configured), while the query was not in the cache in any of them because the TTLs just started decreasing from 3600
  • some servers are validating DNSSEC (AD = authentic data flag), which are the Google Public DNS servers as well as my own recursive ones
  • my own authoritative servers are correctly answering with the AA = authoritative answer flags, while they have no RA = recursion available, which is correct, too

Perfect! It seems that I have neither a problem on my own authoritative servers nor on any recursive ones.

Time Matters: TTL

From the DDoS attacks against Dyn we have learned that the TTL should not be too short. But what happens if the TTL is really high, e.g., 30 days = 2592000 seconds? Let’s have a look at the DNS forwarders. I am querying

ttl-long.weberdns.de
 :
weberjoh@jw-nb12-lx:~/dnsdiag$ ./dnseval.py -f ../dns-servers ttl-long.weberdns.de
server                    avg(ms)     min(ms)     max(ms)     stddev(ms)  lost(%)  ttl        flags
------------------------------------------------------------------------------------------------------------------
194.25.0.68               5.002       3.228       6.897       1.574       %0       86373      QR -- -- RD RA -- --
194.25.0.60               12.684      7.832       33.517      8.405       %0       86374      QR -- -- RD RA -- --
2003:40:2000::53          4.812       3.640       7.118       1.394       %0       86400      QR -- -- RD RA -- --
2003:56::53               8.945       8.061       15.702      2.377       %0       86373      QR -- -- RD RA -- --
8.8.8.8                   67.043      13.463      507.222     154.708     %0       86372      QR -- -- RD RA AD --
8.8.4.4                   16.761      14.265      20.786      2.744       %0       86372      QR -- -- RD RA AD --
2001:4860:4860::8888      17.270      13.400      20.694      3.253       %0       86371      QR -- -- RD RA AD --
2001:4860:4860::8844      17.578      15.262      21.558      2.766       %0       86371      QR -- -- RD RA AD --
resolver1.opendns.com     7.229       3.769       33.654      9.300       %0       604773     QR -- -- RD RA -- --
resolver2.opendns.com     3.865       3.814       3.978       0.047       %0       604773     QR -- -- RD RA -- --
ns1-v4.weberdns.de        6.444       5.929       9.226       1.030       %0       2592000    QR AA -- RD -- -- --
ns1-v6.weberdns.de        4.450       4.114       4.940       0.355       %0       2592000    QR AA -- RD -- -- --
ns2.weberdns.de           9.648       8.444       9.974       0.482       %0       2592000    QR AA -- RD -- -- --
ns3.weberdns.de           25.328      24.242      26.882      0.992       %0       2592000    QR AA -- RD -- -- --
int-dns.webernetz.net     6.338       6.073       7.794       0.525       %0       604774     QR -- -- RD RA AD --
192.168.110.1             0.000       0.000       0.000       0.000       %100     N/A        -- -- -- -- -- -- --
192.168.7.1               7.110       6.692       8.120       0.412       %0       86373      QR -- -- RD RA AD --
192.168.7.5               12.250      11.992      13.065      0.307       %0       2591973    QR -- -- RD RA AD --

In fact only one reply delivered/cached the correct TTL, namely the Unbound server. All other servers have limited the TTL, e.g., my ISP and Google to 1 day or OpenDNS to 7 days.

Short TTL values such as 60 seconds seem to be ok:

weberjoh@jw-nb12-lx:~/dnsdiag$ ./dnseval.py -f ../dns-servers ttl-short.weberdns.de
server                    avg(ms)     min(ms)     max(ms)     stddev(ms)  lost(%)  ttl        flags
------------------------------------------------------------------------------------------------------------------
194.25.0.68               13.184      4.054       18.359      4.314       %0       60         QR -- -- RD RA -- --
194.25.0.60               21.242      8.219       32.522      7.828       %0       60         QR -- -- RD RA -- --
2003:40:2000::53          11.680      4.148       18.468      4.958       %0       60         QR -- -- RD RA -- --
2003:56::53               16.581      8.108       33.683      9.342       %0       60         QR -- -- RD RA -- --
8.8.8.8                   44.196      19.879      64.991      17.435      %0       59         QR -- -- RD RA AD --
8.8.4.4                   23.051      14.727      49.934      12.653      %0       58         QR -- -- RD RA AD --
2001:4860:4860::8888      20.924      13.493      63.579      15.233      %0       58         QR -- -- RD RA AD --
2001:4860:4860::8844      17.840      15.058      24.503      3.243       %0       58         QR -- -- RD RA AD --
resolver1.opendns.com     11.289      3.878       35.229      12.658      %0       60         QR -- -- RD RA -- --
resolver2.opendns.com     4.231       3.755       5.842       0.621       %0       59         QR -- -- RD RA -- --
ns1-v4.weberdns.de        6.471       5.975       9.055       0.971       %0       60         QR AA -- RD -- -- --
ns1-v6.weberdns.de        4.516       4.207       4.954       0.340       %0       60         QR AA -- RD -- -- --
ns2.weberdns.de           9.721       9.007       10.255      0.380       %0       60         QR AA -- RD -- -- --
ns3.weberdns.de           61.182      54.789      71.092      4.264       %0       60         QR AA -- RD -- -- --
int-dns.webernetz.net     6.785       6.132       10.287      1.280       %0       60         QR -- -- RD RA AD --
192.168.110.1             0.000       0.000       0.000       0.000       %100     N/A        -- -- -- -- -- -- --
192.168.7.1               8.128       6.683       18.702      3.721       %0       60         QR -- -- RD RA AD --
192.168.7.5               13.107      11.854      22.336      3.256       %0       60         QR -- -- RD RA AD --

 

Validating DNSSEC

As already mentioned not all public DNS servers are validating DNSSEC. Google does but OpenDNS or my ISP don’t. When querying

sigfail.verteiltesysteme.net
, a false DNSSEC FQDN, no server should reply. But those do:
weberjoh@jw-nb12-lx:~/dnsdiag$ ./dnseval.py -f ../dns-servers sigfail.verteiltesysteme.net
server                    avg(ms)     min(ms)     max(ms)     stddev(ms)  lost(%)  ttl        flags
------------------------------------------------------------------------------------------------------------------
194.25.0.68               47.211      5.013       168.361     55.172      %0       60         QR -- -- RD RA -- --
194.25.0.60               72.734      8.806       305.321     90.659      %0       60         QR -- -- RD RA -- --
2003:40:2000::53          14.458      3.440       46.282      14.409      %0       59         QR -- -- RD RA -- --
2003:56::53               59.879      7.961       310.540     94.759      %0       60         QR -- -- RD RA -- --
8.8.8.8                   0.000       0.000       0.000       0.000       %100     N/A        -- -- -- -- -- -- --
8.8.4.4                   0.000       0.000       0.000       0.000       %100     N/A        -- -- -- -- -- -- --
2001:4860:4860::8888      0.000       0.000       0.000       0.000       %100     N/A        -- -- -- -- -- -- --
2001:4860:4860::8844      0.000       0.000       0.000       0.000       %100     N/A        -- -- -- -- -- -- --
resolver1.opendns.com     39.926      4.185       134.027     51.552      %0       60         QR -- -- RD RA -- --
resolver2.opendns.com     9.903       3.830       33.534      11.996      %0       60         QR -- -- RD RA -- --
ns1-v4.weberdns.de        0.000       0.000       0.000       0.000       %100     N/A        -- -- -- -- -- -- --
ns1-v6.weberdns.de        0.000       0.000       0.000       0.000       %100     N/A        -- -- -- -- -- -- --
ns2.weberdns.de           0.000       0.000       0.000       0.000       %100     N/A        -- -- -- -- -- -- --
ns3.weberdns.de           0.000       0.000       0.000       0.000       %100     N/A        -- -- -- -- -- -- --
int-dns.webernetz.net     0.000       0.000       0.000       0.000       %100     N/A        -- -- -- -- -- -- --
192.168.110.1             0.000       0.000       0.000       0.000       %100     N/A        -- -- -- -- -- -- --
192.168.7.1               0.000       0.000       0.000       0.000       %100     N/A        -- -- -- -- -- -- --
192.168.7.5               0.000       0.000       0.000       0.000       %100     N/A        -- -- -- -- -- -- --

 

That’s it for now. Did I miss some interesting test cases? Please write a comment if so.

Featured image: “Werkzeug” by Andreas Issleib is licensed under CC BY-NC-ND 2.0.

Detect DNS Spoofing: dnstraceroute

$
0
0
"decisions" by Martin Fisch is licensed under CC BY-SA 2.0

Another great tool from Babak Farrokhi is dnstraceroute. It is part of the DNSDiag toolkit from which I already showed the dnsping feature. With dnstraceroute you can verify whether a DNS request is indeed answered by the correct DNS server destination or whether a man-in-the-middle has spoofed/hijacked the DNS reply. It works by using the traceroute trick by incrementing the TTL value within the IP header from 1 to 30.

Beside detecting malicious DNS spoofing attacks, it can also be used to verify security features such as DNS sinkholing. I am showing the usage as well as a test case for verifying a sinkhole feature.

./dnstraceroute

To use dnstraceroute, the GitHub repository must be cloned, as already shown on other sites or on the official documentation:

git clone https://github.com/farrokhi/dnsdiag.git
cd dnsdiag
git submodule update --init

Since dnstraceroute needs root privileges, it must be run with sudo (or the like). It basically needs the hostname to be tested against the first DNS resolver of the system. With other options the DNS server can be set manually

-s <server>
  or some expert information can be displayed
-x
 .

Here is a typical execution of dnstraceroute. I tested the domain “blog.webernetz.net” to the Google public DNS server 8.8.8.8:

weberjoh@jw-nb12-lx:~/dnsdiag$ sudo ./dnstraceroute.py -x -s 8.8.8.8 blog.webernetz.net
dnstraceroute.py DNS: 8.8.8.8:53, hostname: blog.webernetz.net, rdatatype: A
1       pa-dmz.webernetz.net (192.168.110.1) 1 ms
2       80.154.108.225 (80.154.108.225) 3 ms
3       f-eb12.F.DE.NET.DTAG.DE (62.154.10.9) 3 ms
4       217.239.49.206 (217.239.49.206) 4 ms
5       72.14.196.17 (72.14.196.17) 3 ms
6       216.239.56.110 (216.239.56.110) 3 ms
7       216.239.57.188 (216.239.57.188) 4 ms
8       209.85.251.178 (209.85.251.178) 6 ms
9       209.85.255.39 (209.85.255.39) 18 ms
10      108.170.234.47 (108.170.234.47) 13 ms
11       *
12      google-public-dns-a.google.com (8.8.8.8) 12 ms

=== Expert Hints ===
 [*] public DNS server is next to an invisible hop (probably a firewall)

Captured with Wireshark, it looks like this: Beginning with a TTL of 1, the value is incremented until the reply came. The ICMP time-to-live exceeded messages are displayed as the hops by dnstraceroute:

dnstraceroute06-8.8.8.8-blog.webernetz.net Wireshark

DNS Sinkholing

I am happy that my ISPs here in Germany are not spoofing my DNS queries. That is, I could not test such a scenario. (Refer to “Is Your ISP Hijacking Your DNS Traffic?” at RIPE Labs for such examples.) BUT, with dnstraceroute some “good” spoofing examples can be tested, too, such as DNS sinkholing. With this technique, next-generation firewalls such as the Palo Alto Networks firewall reply to DNS queries for malicious sites with a sinkhole IP address in order to protect the client before he even TCP-SYNed to the destination.

I tested a domain name that was listed as malicious with dnstraceroute. Obviously, the real 8.8.8.8 is not directly connected to my network ;), but listed as the first and only hop by dnstraceroute:

weberjoh@jw-nb12-lx:~/dnsdiag$ sudo ./dnstraceroute.py -x -s 8.8.8.8 3qtep.69khz.com
dnstraceroute.py DNS: 8.8.8.8:53, hostname: 3qtep.69khz.com, rdatatype: A
1       google-public-dns-a.google.com (8.8.8.8) 3 ms

=== Expert Hints ===
 [*] path too short (possible DNS hijacking, unless it is a local DNS resolver)

A look at the Wireshark capture shows the DNS query with a TTL with 1, but instead of an ICMP TTL exceeded reply, the Palo Alto firewall directly replied with the DNS sinkhole address:

dnstraceroute08-8.8.8.8-3qtep.69khz.com Wireshark 01 Query dnstraceroute08-8.8.8.8-3qtep.69khz.com Wireshark 02 Reply Spoof

Yeah, the DNS sinkholing works and dnstraceroute was able to verify it.

What it does not detect

Note that this tool does not detect false DNS answers from a correct DNS server. For example, though my German ISP “Deutsche Telekom” is not hijacking DNS queries, their DNS resolvers are answering with falsified A records for unregistered domains. Of course, this is a spoofed reply, but not from a man-in-the-middle but from the real DNS resolver.

In the following example I queried my home router (FRITZ!Box) which uses the DNS resolvers from Deutsche Telekom about “weberfoobar.de”, which does not exists. The DNS proxy is two hops away, so nothing seems to be wrong:

weberjoh@jw-nb12-lx:~/dnsdiag$ sudo ./dnstraceroute.py -s 192.168.7.1 weberfoobar.de
dnstraceroute.py DNS: 192.168.7.1:53, hostname: weberfoobar.de, rdatatype: A
1       pa-dmz.webernetz.net (192.168.110.1) 1 ms
2       fritzbox-fdorf.webernetz.net (192.168.7.1) 24 ms

But when testing the same non-existent domain name to the Google server, the correct answer (after the correct traceroute path) is “non exist”:

weberjoh@jw-nb12-lx:~/dnsdiag$ sudo ./dnstraceroute.py -s 8.8.8.8 weberfoobar.de
dnstraceroute.py DNS: 8.8.8.8:53, hostname: weberfoobar.de, rdatatype: A
1       pa-dmz.webernetz.net (192.168.110.1) 1 ms
2       80.154.108.225 (80.154.108.225) 2 ms
3       f-eb12.F.DE.NET.DTAG.DE (62.154.10.9) 10 ms
4       217.239.49.206 (217.239.49.206) 14 ms
5       72.14.196.17 (72.14.196.17) 3 ms
6       216.239.56.26 (216.239.56.26) 3 ms
7       216.239.57.125 (216.239.57.125) 22 ms
8       209.85.143.26 (209.85.143.26) 7 ms
9       209.85.255.39 (209.85.255.39) 17 ms
10      209.85.243.65 (209.85.243.65) 18 ms
11       *
Invalid hostname: None of DNS query names exist: weberfoobar.de., weberfoobar.de.webernetz.net.

That is, such types of DNS spoofing must be detected with manual queries, e.g., with dig. Note that the Telekom DNS resolver answers with two A records, while the Google DNS resolver (correctly) has no answer:

weberjoh@jw-nb12-lx:~/dnsdiag$ dig @192.168.7.1 weberfoobar.de

; <<>> DiG 9.10.3-P4-Ubuntu <<>> @192.168.7.1 weberfoobar.de
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 46490
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;weberfoobar.de.                        IN      A

;; ANSWER SECTION:
weberfoobar.de.         3563    IN      A       62.157.140.133
weberfoobar.de.         3563    IN      A       80.156.86.78

;; Query time: 4 msec
;; SERVER: 192.168.7.1#53(192.168.7.1)
;; WHEN: Wed Aug 31 15:24:27 CEST 2016
;; MSG SIZE  rcvd: 64

weberjoh@jw-nb12-lx:~/dnsdiag$ dig @8.8.8.8 weberfoobar.de

; <<>> DiG 9.10.3-P4-Ubuntu <<>> @8.8.8.8 weberfoobar.de
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 53504
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;weberfoobar.de.                        IN      A

;; AUTHORITY SECTION:
de.                     1799    IN      SOA     f.nic.de. its.denic.de. 2016083157 7200 7200 3600000 7200

;; Query time: 31 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Wed Aug 31 15:24:36 CEST 2016
;; MSG SIZE  rcvd: 95

Cheers!

Featured image: “decisions” by Martin Fisch is licensed under CC BY-SA 2.0.

Idea: On-the-Fly TLSA Record Spoofing

$
0
0
On-the-Fly DANE Spoofing featured image

It is quite common that organizations use some kind of TLS decryption to have a look at the client traffic in order to protect against malware or evasion. (Some synonyms are SSL/TLS interception, decryption, visibility, man-in-the-middle, …) Next-generation firewalls as well as proxies implement such techniques, e.g., Palo Alto Networks or Blue Coat. To omit the certificate warnings by the clients, all spoofed certificates are signed by an internal root CA that is known to all internal clients. For example, the root CA is published via group policies to all end nodes.

But what happens if the DNS-based Authentication of Named Entities (DANE) is widely used within browsers? From the CA perspective, the spoofed certificates are valid, but not from the DANE perspective. To my mind we need something like an on-the-fly TLSA record spoofing technique that works in conjunction with TLS decryption.

The Situation

I won’t discuss the pros and cons of TLS decryption here. I want to deal with the fact that some customers heavily rely on such features. Actually, we do not have  a problem these days, since neither DNSSEC validation nor DANE within browsers is widely used.

[Note that we also have a similar problem with Public Key Pinning Extension for HTTP (HPKP, RFC 7469, Wikipedia) if TLS decryption is used. If so, the browser knows which certificate to expect and will not connect to a specific site if the certificate is exchanged by an intermediate device.]

But what are appropriate solutions if one day DNSSEC validation at the internal DNS servers, as well as DANE validation within the web browsers is used anywhere? With only DNSSEC we won’t have any problems because the clients are still connecting to the correct IP addresses. But DANE will (correctly) interrupt the connection to the HTTPS server if the certificate is NOT as expected from the TLSA record.

On-the-Fly DANE Spoofing without

Of course, an easy solution would be the deactivation of DANE at the DNS servers, e.g., block (do not forward) all TLSA records. Or to disable the TLSA check at the browser. But this in turn would disable some good and new security features that are welcome, e.g., for remote users working with their notebooks on the road.

The Solution

In the same way as the whole TLS certificate chain is spoofed by the firewall, TLSA records must be spoofed, too. With the internal root CA, an island of trust is built for TLS. Similar, an island of trust must be built with DNSSEC for signing the modified TLSA records.

On-the-Fly DANE Spoofing with

That is:

  • A DNSSEC signing server must build its own (partial) DNS tree, beginning with an own trust anchor, i.e., an island of trust.
  • For each TLS certificate which is intercepted by the firewall, the DNSSEC server must add the appropriate TLSA record with the hash of the public key from the spoofed certificate. <- This is the actual requirement.
  • The internal DNSSEC validation server (which must not be the same as the signing server!) must integrate the anchor of trust for “.” from the signing server.
  • Note that the actual problem to solve is not the DNSSEC validation, but the TLSA validation. But since TLSA relies on DNSSEC, the only approach is to exchange the TLSA within its own DNSSEC chain of trust.
  • If an end user opens a TLS secured website, the firewall will intercept the connection and will use its own spoofed certificate. The browser of the client will compare the TLSA record for this website, which will be correct since the DNSSEC server placed the corresponding public key into the TLSA record.

Searching for a Thesis?

To my mind, this is enough stuff for at least two master theses. The first one would be a feasibility study which shows which connections would work or not with such techniques. Which TLSA records should be used (DANE-TA, DANE-EE, …), etc. The second one would implement this technique in order to spoof TLSA records in real-time.

If you are a student and searching for a thesis, please contact me!

Idea: SSHFP Validator

$
0
0
SSHFP Validator featured image

The usage of the SSHFP resource record helps admins to authenticate the SSH server before they are exposing their credentials or before a man-in-the-middle attack occurs. This is only one great extension of DNSSEC (beside DANE whose TLSA records can be used to authenticate HTTPS/SMTPS servers).

While there are some great online tools for checking the mere DNS (1, 2), the correct DNSSEC signing (3, 4), or the placement of TLSA resource records for DANE (5, 6, 7), I have not found an online SSHFP validator. That’s the idea:

Well, you already got it: We need a webpage that connects to an SSH server to see the public key, while it verifies the SSHFP resource records via DNSSEC. A simple green checkmark should be displayed if the SSHFP is the same as the presented public key.

SSHFP Validator

Here are some ideas how to display more details:

  • Of course, use IPv6 and legacy IP to connect to the server.
  • Display the public key for all used algorithms (RSA, DSA, ECDSA, Ed25519, which requires to connect via all of these algorithms)
  • and the fingerprints for all of them in MD5-hex and SHA256-base64 (this is how OpenSSH displays fingerprints)
  • as well as SHA1-hex and SHA256-hex (this is how SSHFP RRs are used).
  • Verify the DNSSEC signature (AD flag).
  • [Optional] Display the latency and traceroute path so the SSH server.

Since the domain sshfp.net was free, I grabbed it immediately because to my mind this gives a good domain for such an SSHFP validator. 😉 And, of course, security must be considered when implementing this script. Proper sanitization must be used, etc.

Master Thesis

Anyone interested in implementing such an online tool? If you are a student and searching for a thesis, please contact me.

BIND Inline-Signing Serial Numbers Cruncher

$
0
0
"Serial number plate" by Kirill Ignatyev  is licensed under CC BY-NC 2.0

I know that BIND correctly changes the serial numbers of zones when it is enabled with inline signing and auto-dnssec. However, I got confused one more time as I looked on some of my SOA records. So, just for the record, here is an example how the serial numbers increase while the admin has not changed anything manually on the zone files.

Following are three sections that each show the real zone file directly on the server directory (

cat db.sshfp.net
 ) as well as the SOA record as it is delivered by the authoritative DNS server (
dig sshfp.net soa +multi @ns1.weberdns.de
 ).

One more sentence about the inline signing process from BIND: “Inline signing works by taking the zone file you manually maintain, transforming it into a dynamic zone, and signing the dynamic zone. DNSSEC changes are made to the journal file. As a result of this, the serial number shown to the world can differ from the serial number in your file“, Michael W. Lucas.

Section One

This is the zone file which was not touched for several weeks. Note the serial of 2016090105:

weberjoh@jw-vm16-ns0:/etc/bind$ cat db.sshfp.net
;
; BIND data file for sshfp.net
;
$TTL 1d
@       IN      SOA     ns1.weberdns.de. webmaster.weberdns.de. (
                     2016090105         ; Serial
                             1h         ; Refresh
                            15m         ; Retry
                             4w         ; Expire
                             3m )       ; Negative Cache TTL
;

While the actual SOA record looked like this (serial 2016090133!):

weberjoh@jw-nb12-lx:~$ dig sshfp.net soa +multi

;; ANSWER SECTION:
sshfp.net.              86396 IN SOA ns1.weberdns.de. webmaster.weberdns.de. (
                                2016090133 ; serial
                                3600       ; refresh (1 hour)
                                900        ; retry (15 minutes)
                                2419200    ; expire (4 weeks)
                                180        ; minimum (3 minutes)
                                )

 

Section Two

After I increased the serial number by one (though it was not the correct date, but I wanted to test it this way),

weberjoh@jw-vm16-ns0:/etc/bind$ cat db.sshfp.net
;
; BIND data file for sshfp.net
;
$TTL 1d
@       IN      SOA     ns1.weberdns.de. webmaster.weberdns.de. (
                     2016090106         ; Serial
                             1h         ; Refresh
                            15m         ; Retry
                             4w         ; Expire
                             3m )       ; Negative Cache TTL
;

the actual SOA record was increased by one, too:

weberjoh@jw-nb12-lx:~$ dig sshfp.net soa +multi @ns1.weberdns.de

;; ANSWER SECTION:
sshfp.net.              86400 IN SOA ns1.weberdns.de. webmaster.weberdns.de. (
                                2016090134 ; serial
                                3600       ; refresh (1 hour)
                                900        ; retry (15 minutes)
                                2419200    ; expire (4 weeks)
                                180        ; minimum (3 minutes)
                                )

 

Section Three

Finally I changed something within the zone and set the serial number to the correct date and to a counter of 01. After a reload of the zone, the actual SOA record had exactly the same serial number since there was no automatic signing event in the meantime.

weberjoh@jw-vm16-ns0:/etc/bind$ cat db.sshfp.net
;
; BIND data file for sshfp.net
;
$TTL 1d
@       IN      SOA     ns1.weberdns.de. webmaster.weberdns.de. (
                     2016111501         ; Serial
                             1h         ; Refresh
                            15m         ; Retry
                             4w         ; Expire
                             3m )       ; Negative Cache TTL
;

weberjoh@jw-nb12-lx:~$ dig sshfp.net soa +multi @ns1.weberdns.de

;; ANSWER SECTION:
sshfp.net.              86400 IN SOA ns1.weberdns.de. webmaster.weberdns.de. (
                                2016111501 ; serial
                                3600       ; refresh (1 hour)
                                900        ; retry (15 minutes)
                                2419200    ; expire (4 weeks)
                                180        ; minimum (3 minutes)
                                )

 

That’s it. So don’t get confused by your own serial numbers. 😉

Featured image: “Serial number plate” by Kirill Ignatyev  is licensed under CC BY-NC 2.0.


CLI Commands for Troubleshooting Juniper ScreenOS Firewalls

$
0
0
cli-commands-for-troubleshooting-juniper-screenos-firewalls

Yes I know, ScreenOS is “End of Everything” (EoE). However, for historical reasons I am still managing many Netscreen/ScreenOS firewalls for some customers. Similar to my troubleshooting CLI commands for Palo Alto and Fortinet I am listing the most common used commands for the ScreenOS devices. These are only the commands that are needed for deep troubleshooting sessions that cannot be done solely on the GUI.

At first: Always remember that the default backspace key is “Ctrl + h” and not the backspace key itself! 😉

Basics

These are the very basics on the command line:

get config
get config all                #configuration with default values
get config | incl <string>    #grep within the configuration
get system                    #serial #, software version, uptime, etc.
get event                     #event list (same as in the GUI)

How to turn off the LED alarm on the firewall:

clear led alarm
clear cluster led alarm       #on a cluster for all devices at once

 

Basic Networking

The reason why we are all here:

get arp
get route                                       #routing table
get route ip <ip-address>                       #routing table lookup for a specific IP
get vrouter <name-of-the-VR> route              #routing table from a specific virtual router
get vrouter <name-of-the-VR> protocol ?         #dynamic routing protocols such as OSPF or BGP
get counter statistics interface <interface>    #counters for hardware interfaces
get ndp                                         #IPv6 neighbor cache

ping <name|ip-address>
ping <name|ip-address> from <interface>         #ping from a specific interface
trace-route <name|ip-address>
trace-route <name|ip-address> from <interface>  #same for trace-route

 

Application Layer Gateway

I had some trouble with the application layer gateway functionality on the ScreenOS devices. Here are some hidden commands that help while troubleshooting the ALGs:

get alg                       #lists all available ALGs with an enabled/disabled statement
get service portmap           #which port is assigned to which application
get service application       #known applications by ScreenOS that trigger an ALG

And a few links concerning ALGs:

 

NSRP (High Availability)

The following command lists all details about an NetScreen Redundancy Protocol (NSRP) cluster, i.e., the IDs of all connected units, the current master, encryption and authentication passwords (in plain text!), etc.:

get nsrp

To sync the configuration from the master to the local device (AND NOT VICE VERSA!!!) [Link]:

exec nsrp sync global-config save

And to do a manual failover. This brings the current master unit into backup mode. This command must be used on the current master! [Link]:

exec nsrp vsd-group 0 mode backup

 

Session & Log

The session commands list sessions that are currently active. The traffic log shows already finished sessions (of course only if they were logged):

get session
get session ?
get session scr-ip <ip-address>
get session policy-id <id>
get log traffic
get log traffic ?
get log traffic src-ip <ip-address>
get log traffic policy <id>

Link: “How to determine how long a session has been up in ScreenOS“.

IPsec VPN

This is one of the main use cases for using the CLI on the SSG firewalls: Many details about IPsec site-to-site VPNs, e.g., the proxy-IDs for policy-based VPNs:

get ike cookies         #phase 1
get vpn auto            #list of phase 2 VPNs
get vpn <name>          #details
get sa id <number>      #details of phase 2 filtered by the tunnel-id
get sa id 2             #values from 0-9 can be entered directly
get sa id 0x0000000b    #higher values must be entered in hexadecimal notation

 

Flow

To display the most detailed information about active flows, for example to see which policies trigger or which routing table lookups are used, etc. [Link]:

undebug all             #stop all other debuggings
get ff                  #if there are any filters set, remove them with the next line:
unset ff
set ff ?                #ff = flow filter
set ff src-ip <ip>
set ff dst-ip <ip>
get ff                  #verify all filters
clear db                #clear the debug buffer
debug flow basic        #now the debug will be logged. Generate your traffic now
undebug all             #after the traffic is finished, stop debugging
get db stream           #and display the debug stream
unset ff                #finally, unset all filters to not confuese further troubleshooting sessions

 

Common Problems

Some more links to common problems or other scenarios:

 

NSM Stuff

And finally some notes concerning the “Network and Security Manager“.

  • Default port from ScreenOS device to NSM:
    TCP/7800
     .
  • Default https port to download the Java GUI:
    https://<ip>:8443
     .
  • Default port from Java GUI to NSM:
    TCP/7808
     .

To become root on the NSM CLI:

sudo su -

And some links:

 

Palo Alto Reporting

$
0
0

I wanted to configure a weekly email report on a Palo Alto Networks firewall. “Yes, no problem”, I thought. Well, it was absolutely not that easy. ;(

While the PAN firewalls have a great GUI and a good design at all they lack an easy-to-use email reporting function, especially when compared to the FortiGate firewalls which have a great local report feature. –> If you want some stats on a weekly basis you must configure it completely from scratch. Unluckily this is not that easy since you must pass several steps for that. Therefore, I drew an outline of the Palo Alto reporting stages to have an overview of them.

I am currently running a PA-200 with PAN-OS 7.1.6.

Key Facts

  • No predefined weekly report (only daily)
  • For weekly reports, you must configure them manually
  • Emails for a weekly report won’t have any graphs but only tables
  • No possibility to generate weekly reports out of the ACC <- which is really bad, because the ACC draws very nice graphs

Palo Alto Reporting Outline

This is my sketch of the reporting menus. Hopefully it helps. The comments in red are disadvantages from my point of view. The comments in green are advantages:

palo-alto-reporting-sketch

Steps for a weekly Reporting Mail

In order to have a weekly reporting mail with a PDF that has some interesting stuff, proceed as follows:

  1. Monitor -> Manage Custom Reports -> Add -> Load Template: For each template you are interested in, save it with a name (e.g., the same as the template to avoid confusion), check the scheduling, and set the time frame to “Last Calendar Week”. [Optional: Increase the rows/sort by value from top 10 to top 25, …]
  2. Monitor -> PDF Reports -> Report Groups -> Add: Select all “Custom Reports” you just created.
  3. Monitor -> PDF Reports -> Email Scheduler -> Add: Select the report group just created, an email profile and a recurrence of “Every Monday”.

Here are a few screenshots that might help:

Now, at the beginning of the week you’ll have an email with a PDF that includes all the reports over the last week.

Links

At least there are some docs from Palo Alto that describe some of the points I mentioned above:

Featured image: “That was supposed to be going up, wasn’t it?” by Rafael Matsunaga is licensed under CC BY 2.0.

In Sync 2017

$
0
0

It is not easy to sync the own files/mails/contacts/calendars/etc. in order to keep them private (not via a public cloud) and to create regular backups. Furthermore, every solution must be easy to use (at least for my wife ;)) and reliable.

Following is my approach for keeping my files in sync and private. What are yours?

This is my current setup for me and my family:

It achieves the following goals, mainly to keep my data private:

  • Sync of all private files to the ownCloud (without Dropbox)
  • Sync of all private contacts to the ownCloud (without Apple/Google)
  • Mails accessible via online webmail (instead of offline Outlook or Thunderbird)
  • Backups of all data, either by me or by my web hosting service
  • Confidentiality via encryption (HTTPS, SMTPS, IMAPS)

The following goals are still unsolved for me:

  • Calendar: Hopefully the ownCloud app will be better one day.
  • Notes: I currently sync my notes to the Exchange server of my business phone. This works for the moment but is not ideal. Maybe I could use text-files via ownCloud instead? I don’t want to install another software but want to use the built-in notes app.
  • Firefox Bookmarks: Currently I am using Firefox Sync (which works quite good). However, it is kind of a public cloud.

What are your setups? Please comment for every better solution or whatever.

Featured image: “Sync” by Dave Wild is licensed under CC BY-NC 2.0.

Palo Alto External Dynamic IP Lists

$
0
0

This is a cool and easy to use (security) feature from Palo Alto Networks firewalls: The External Dynamic Lists which can be used with some (free) 3rd party IP lists to block malicious incoming IP connections. In my case I am using two free IP lists to deny any connection from these sources coming into my network/DMZ. I am showing the configuration of such lists on the Palo Alto as well as some stats about it.

Lists

What is an external dynamic list? It is a list of known malicious sources maintained by some providers/persons on the Internet. These IP lists can be used to blacklist/block/deny connections from those sources. A good overview of such lists is “Blocklists of Suspected Malicious IPs and URLs” from Lenny Zeltser. I am currently using the following two well-known lists:

While the first one is simply a list of “malicious” IPv4 addresses, the second one is a combination of other source that also include fullbogons and other entries. FireHOL shows many graphs and stats about the distribution from their listed IP addresses. Follow the link above and have a look!

What about IPv6? Well, it seems that only legacy IP is widely supported. Bad. While FireHOL does not list any statement about that, the OpenBL FAQ says: “We are fully IPv6 enabled but the lists and the reporting currently only handle IPv4 since most of our hosts do not have a IPv6 address and also because there basically are no attacks against IPv6 targets worth mentioning, at least not yet.” I am not happy with this statement at all, but I also know that it is not easy to maintain IPv6 lists due to the large address space. (Should an IPv6 blacklist block a /128, /64 or even a /48 in case of abuse?) At least the Spamhaus Project has an IPv6 list, called DROPv6.

Some further notes:

  1. You should always check the quality of the list before using it. To my mind the two mentioned lists are quite “good”, however, note that they could be abused, too. Do some research about the trustworthiness before using it in your policies.
  2. Both lists are only IP address lists, that is, they are useful for blocking incoming connections. For outgoing (user initiated) connections you can use URL lists rather than IP lists. Lenny mentioned a few of them in his blog post. And the Palo Alto firewall is also able to use domain and even URL lists for security policies, etc.

Usage within Palo Alto

I am currently using a PA-200 with PAN-OS 7.1.7. The blacklists are configured under Objects -> External Dynamic Lists. They are from type “IP List”. Those dynamic objects can then be used within a security policy. In my case I have added two deny policies at the very beginning of my whole ruleset. Immediately after committing the traffic log shows denied connection from various IPv4 addresses:

Some Stats

At first I was interested whether the whole blacklists are used correctly by the firewall. There are some CLI commands to see/refresh the lists such as:

weberjoh@pa> request system external-list ?
> refresh    refresh external-lists
> show       Print IPs/Domains/URLs in an external list
> url-test   test accessibility for url

 

I captured this screenshot from the FireHOL page that shows 17.299 entries on January 30th, 2017. In fact, exactly the same valid entries were listed in the Palo Alto dynamic list at the same time, as the following listing shows. (Note that there are not only /32 host IPv4 addresses but also bigger [bigly?] networks such as /20):

weberjoh@pa> request system external-list show type ip name dyn_firehol

vsys1/dyn_firehol:
        Next update at        : Mon Jan 30 21:00:21 2017
        Source                : https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/firehol_level1.netset
        Referenced            : Yes
        Valid                 : Yes

        Total valid entries   : 17299
        Total invalid entries : 34
        Valid ips:
                0.0.0.0/8
                1.10.16.0/20
                1.32.128.0/18
                1.93.0.224
                1.116.0.0/14
                1.178.179.217
                1.179.170.7
[...]

Of course it looks quite the same with IPv6, here with the Spamhaus DROPv6 list:

weberjoh@pa> request system external-list show type ip name dyn_Spamhaus-DROPv6


vsys1/dyn_Spamhaus-DROPv6:
        Next update at        : Wed Feb 15 05:13:38 2017
        Source                : https://www.spamhaus.org/drop/dropv6.txt
        Referenced            : Yes
        Valid                 : Yes

        Total valid entries   : 19
        Total invalid entries : 4
        Valid ips:
                2a07:5807::/32
                2a06:2a00::/29
                2a06:e480::/29
                2a06:4740::/29
                2a06:df80::/29
                2402:6680::/32
                2a0a:c00::/29
                2a06:f680::/29
                2404:e180::/32
                2a07:5780::/29
                2a06:d240::/29
                2a00:dfe0::/29
                2a07:5786::/32
                2607:f2d0::/32
                2803:5380:ffff::/48

 

Now here is a custom report that shows all denied connections during the last calendar week, sorted by count (top 5), grouped by port. Many well-known ports such as SSH, telnet, SMTP, HTTP, NTP, SNMP, etc. are scanned from different IPv4 addresses all over the world:

I really like this feature, at least for my lab where not everything is business critical. To my mind blocking some “false positives” is still better than allowing some malicious connections (false negative).

More Links

Featured image: “Lists” by Steven Lilley is licensed under CC BY-SA 2.0.

Palo Alto PBF Problem

$
0
0

I migrated an old Juniper SSG ScreenOS firewall to a Palo Alto Networks firewall. While almost everything worked great with the Palo (of course with much more functionalities) I came across one case in which a connection did NOT work due to a bug on the Palo side. I investigated this bug with the support team from Palo Alto Networks and it turned out that it “works as designed”. Hm, I was not happy with this since I still don’t understand the design principle behind it.

However, it was a specific and not business critical case: One Palo Alto firewall with two ISP connections using a destination network address translation (DNAT, an old IPv4 problem) and policy based forwarding (PBF) with the same destination ports. Following are some more details:

(This problem appeared in April 2016. I was running a PA-200 with PAN-OS 7.1.0. After the support team told me that it works as designed, I built a workaround and did not follow this case anymore.)

The Problem

Refer to the following figure with the two different connections (red and green):

Red: Incoming connections from ISP1 to DMZ with DNAT. Green: Outgoing connections from DMZ to ISP2 via PBF.

The following NAT policy forwards incoming IPv4 connections (from ISP1 on eth1/1 for some destination ports, in my case 33004) to the private DMZ IPv4 address:

And the following PBF policy forwards outgoing IPv4 connections (from the DMZ) with the same range of destination ports (in my case again 33004) to ISP2 on eth1/2:

While outgoing connections through the PBF to eth1/2 worked anytime, incoming connections through the DNAT did NOT work while the PBF rule was enabled, see the “aged-out” connections:

The core problem was the returning path for incoming connections (red, eth1/1) which was hit by the PBF policy though it had NOT a destination port of 33004 but some other higher ports. This should not be the case. The rule was hit since the returning traffic had (of course) a source port of 33004. That is, the returning packets which should flow out of eth1/1 back to ISP1 were re-routed by the PBF rule to eth1/2. In fact, neither the NAT nor the PBF policy clearly specify which type of port (source or destination) it is using. There is only one single “service” that must be chosen, which should be always the destination port to my mind. (In case of the Juniper ScreenOS firewall there was a distinction between source and destination port.) [UPDATE] As Dmitry noted in the comment section (thanks!), the service objects are indeed configured with source and/or destination ports. However, my service objects were only configured with destination ports. That is, the hit by the PBF rule was still not correct. [/UPDATE]

The PAN support asked their engineering about this behaviour and gave me the following reply (which I don’t fully understand): “The reason we do not switch port when we do s2c direction pbf lookup is because we have some use cases that need pbf in s2c direction only. In these cases, we use either service type or destination port of c2s flow to do s2c lookup. That’s why the s2c flow hit the pbf rule.” This was captured under bug number 95540 but not fixed since it already works as designed.

Conclusion

Yes, almost everything that worked on a Juniper ScreenOS firewall (or any other firewall) also works on a Palo Alto firewall. But only “almost everything” since I had no problems with this same situation on the old ScreenOS firewall but only on the Palo.

Featured image: “Down Low” by André Hofmeister is licensed under CC BY-NC 2.0.

Viewing all 338 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>