DNS protocol is one of the attack vectors on your corporate network and IoT devices in particular. Most operating systems access DNS servers using legacy unencrypted protocol by default despite the fact that there are modern secure enhancements for this protocol: DNSSEC, DNS-over-HTTPS, DNS-over-TLS. In this article we discuss these enhancements and explain how to configure them in your network.
Table of contents
- What is DNS?
- Cache poisoning attack
- DNS traffic encryption
- Hard-coded DNS servers
- DNS data exfiltration
- Wrap-up
What is DNS?
Domain Name System is a protocol that resolves human-readable names into machine-readable IP addresses and vice versa — the address book of the Internet.
DNS records are stored on the servers that are organized in a tree. Leaves of the tree are managed by cloud providers, internet providers, and other businesses, whereas roots are managed by an international organization IANA.
DNS was conceived more than thirty years ago (RFC 1035). As such it doesn't have any encryption and trustworthiness built-in. It is easy to spoof DNS name, to spoof DNS server address and to analyze DNS traffic going through your router.
Cache poisoning attack
This type of attack involves falsifying DNS records by a corrupt DNS server. These records are cached by downstream servers and eventually reach the clients — your IoT devices and servers. These attacks are sometimes called DNS cache poisoning.
To mitigate this attack IETF introduced a set of security extensions to DNS collectively called DNSSEC (RFC 9364). These extensions need to be enabled both on the client and on the server side.
Mitigating on the server
If DNSSEC is enabled for a particular domain, then there is a RRSIG record for this domain. DNS client needs to verify the signature from this record, if the verification fails then return name resolution failure. Dig command verifies DNSSEC record by default, however, it does not fail when there is no such record. Use the following command to resolve DNS name and print the RRSIG record (+dnssec
flag).
dig staex.io +dnssec # should resolve to the ip address
dig badsign-a.test.dnssec-tools.org +dnssec # should fail
Usually DNS providers have an option to enable DNSSEC in their portal. Configuring DNSSEC for your own DNS server is out of scope of this article.
Mitigating on the client
To use DNSSEC system-wide you need a capable DNS resolver. One such resolver is Stubby. We will use Stubby in this article because it also supports DNS encryption that we will discuss later.
To enable DNSSEC in Stubby edit the configuration file (/etc/stubby/stubby.yml
by default), and add/replace the following options.
# /etc/stubby/stubby.yml
dnssec: GETDNS_EXTENSION_TRUE
To check that Stubby works, we repeat dig commands but specify 127.0.0.1 as the server.
dig staex.io +dnssec @127.0.0.1 # should resolve to the ip address
dig badsign-a.test.dnssec-tools.org +dnssec @127.0.0.1 # should fail
In all our tests the second address failed to resolve with or without dnssec
flag in the configuration file. We assume that it was filtered on the server side prior to reaching the client. Better safe than sorry.
DNS traffic encryption
DNS traffic is still unencrypted even if DNSSEC is enabled, and the solution is to use either DNS-over-TLS or DNS-over-HTTPS. DoT and DoH encapsulate the packet in TLS and HTTPS frame respectively. Both protocols use state-of-the-art encryption (signed private keys obtained via public key exchange) and offer protection from replay attacks and man-in-the-middle attacks during initial key exchange. Both protocols are extensively used in the Internet and are regularly updated with new ciphers and other cryptographic algorithms.
Mitigating on the server
Both DoH and DoT are supported by popular DNS resolvers like BIND. Configuring these protocols on the server side is out of scope of this article.
Mitigating on the client
To enable DoT on the client side we again use Stubby. This name resolver uses DoT by default. If you want to change the upstream DNS server, then add the following lines to the configuration file (/etc/stubby/stubby.yml
by default).
# /etc/stubby/stubby.yml
upstream_recursive_servers:
- address_data: 9.9.9.11
tls_auth_name: "dns11.quad9.net"
- address_data: 149.112.112.11
tls_auth_name: "dns11.quad9.net"
Here we configured Quad9 servers. Other alternatives are NextDNS, Cloudflare, Google. Some of them filter malicious sites which might be useful for browsers but is not so important for IoT devices.
Hard-coded DNS servers
So far we configured encryption and signature verification for DNS traffic, and in ideal world this should be enough to protect your devices. However, some devices use a hard-coded list of DNS servers in their firmware, and do not allow us to change the firmware.
Mitigation
To solve this problem we will redirect DNS traffic from those devices to Stubby. The irony is that we use the fact that legacy DNS packets can be easily rewritten and sent to another server without the client noticing.
Below is a set of iptables
rules that will redirect any incoming traffic on port 53 to the local Stubby server. These rules are for the router.
# network interface that receives DNS packets
interface=br-lan
# IP address assigned to the network interface
interface_ip_address=192.168.1.1
# local stubby port
stubby_port=53
for protocol in udp tcp; do
iptables -t nat -A PREROUTING \
-i $interface ! -s $interface_ip_address \
-p $protocol --dport 53 \
-j DNAT --to $interface_ip_address:$stubby_port
done
These rules will not work for DoT and DoH, and will not work if the device in question uses non-standard DNS port. The first problem can be solve by deploying HTTPS proxy (which might not be desirable) and the second can be solved with eBPF rules. Diving into these solutions worth an article of its own.
DNS data exfiltration
This data exfiltration technique is rather new, but has already been exploited by various malicious programs. To use DNS queries to exfiltrate stolen data an attacker sets up a DNS resolver for his/her domain. Then on the victim's device the stolen data is encoded in subdomains of this domain: an attacker resolves subdomains and DNS servers forward the name resolution requests to the attacker's DNS server.
Mitigation
One problem of this attack is that the traffic goes through perfectly secure public DNS servers and there is no 100% reliable way to detect it on the server side. However, we can easily block the data exfiltration on the client's side using a list of allowed DNS names and allowed IP addresses to which these names resolve. If a program tries to resolve a name that is not in the list, then the name resolution fails.
Below is a set of rules for iptables
that restrict the names that are allowed to be resolved to IP addresses.
# wan interface
interface=eth0
iptables -A OUTPUT -o $interface \
-p udp --port 53 \
-m string --hex-string "|05|staex|02|io" -algo bm \
-j ACCEPT
# 05 --- length of "staex" in hexadecimal format
# 02 --- length of "io" in hexadecimal format
Below is the script that generates a set of IP addresses to and from which the traffic is allowed. It is a good idea to run this script periodically to get DNS records' updates. Beware that DNS servers themselves need to be in the set as well.
cleanup() {
rm -f "$ip_addresses"
}
set -e
trap cleanup EXIT
# resolve hostnames
allowed_hostnames="dns9.quad9.net one.one.one.one"
ip_addresses="$(mktemp)"
for hostname in $allowed_hostnames; do
dig +short "$hostname"
done >"$ip_addresses"
# create ipset
name=allowlist
ipset -exist create $name hash:ip
ipset flush $name
while read -r ip_address; do
ipset add $name $ip_address
done <"$ip_addresses"
Below are iptables
rules that restrict the IP addresses that are allowed for inbound and outbound traffic. For these rules to work you need to disallow all inbound and outbound traffic by default. You might want to use iptables-apply command to not to lock yourself out of the server.
name=allowlist
iptables -A INPUT ! -m set --match-set $name src -j DROP
iptables -A OUTPUT ! -m set --match-set $name dst -j DROP
These rules might not work for DNS queries that use pointers to encode names. DoT and DoH queries are also problematic. The first problem can be solved using eBPF and the second by using HTTPS proxy. Again, diving into these solutions worth an article of its own.
It is worth noting that data exfiltration is the second-order threat, since an attacker needs to infiltrate the node first to steal the data. Nevertheless, it is important to have multiple layers of security — an approach encouraged by zero-trust security model.
Wrap-up
DNS protocol is not secure by default, and you need to protect your devices from common attacks yourself. Implementing full protection is a huge endeavor that is best done by professionals. However, implementing «good enough» protection is manageable and can be done using the techniques from this article.
Signature verification via DNSSEC and traffic encryption via DoT or DoH is a must for any serious IoT project, whereas hard-coded DNS servers and DNS data exfiltration are mostly second-order threats.
Future versions of Staex will include all the mitigations mentioned in the article thus making your IoT network secure by default. Subscribe to our newsletter to be the first to know about the new features.
Originally posted on staex.io.
We at Staex help our clients make IoT devices first-class citizens in their private networks, protect from common attacks, reduce mobile data usage, and enable audacious use cases that were not possible before. To learn more about our product please visit this page.
Top comments (0)