Spinning local DNS server sourcing responses over HTTPS to combat Man-in-the-middle attack

Arnav Kumar

What is DNS

  • Hierarchical decentralized naming system
  • Authoritative name servers
  • Resolvers
  • Recursive and caching name server
  • OS Querying caching DNS servers
dig .
.          6185	IN	SOA	a.root-servers.net. nstld.verisign-grs.com. 2017110301 1800 900 604800 86400

dig com.
com.         32	IN	SOA	a.gtld-servers.net. nstld.verisign-grs.com. 1509848642 1800 900 604800 86400

dig github.com
github.com.  45	IN	A	192.30.255.113

dig

  • domain information groper 
  • querying specified servers for specific records
dig atx.sx

; <<>> DiG 9.8.3-P1 <<>> atx.sx
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 20540
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;atx.sx.				IN	A

;; ANSWER SECTION:
atx.sx.			299	IN	A	104.27.158.213
atx.sx.			299	IN	A	104.27.159.213

;; Query time: 417 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Mon Sep 11 21:44:23 2017
;; MSG SIZE  rcvd: 56

dig @127.0.0.1 -p 53 txt txt.ns.atx.sx

Problem at hand

  • DNS communication over UDP or TCP is unencrypted. This is vulnerable to eavesdropping and spoofing
  • Responses from resolvers to clients are vulnerable to tampering
  • DNSSEC provides check of authenticity but NOT availability
    Extensions for features that depend on DNSSEC must validate it themselves, as the browser and the OS may not be able to validate DNSSEC
dig thepiratebay.org
;; ANSWER SECTION:
thepiratebay.org.	10	IN	A	49.207.46.34

;; Query time: 7 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Sun Nov  5 08:10:29 2017
;; MSG SIZE  rcvd: 66

ping -c 3 8.8.8.8
64 bytes from 8.8.8.8: icmp_seq=0 ttl=48 time=75.316 ms
64 bytes from 8.8.8.8: icmp_seq=1 ttl=48 time=75.115 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=48 time=77.209 ms

Mirages

  • Changing your DNS servers from the default provided by ISPs to your favourite 8.8.8.8 is NOT guaranteed to solve the problem as the ISP may as-well tamper all communication on Port 53 to respond on behalf of any server, leaving you still with wrong DNS records.
  • Tunneling the full traffic via VPN is not a practical solution just to obtain authentic DNS records.

tl;dr We cannot afford the DNS traffic to leave our premises, and we cannot force our systems to fetch DNS over an encrypted channel

Take matters into our

own hands

  • We run a DNS Resolver ourselves and tell our Operating System to fetch DNS via the Resolver.
  • Our DNS Resolver fetches DNS over HTTPS using APIs provided by Google

Tools of trade

  • Twisted
    • names
      • DNSServerFactory
      • Resolver
  • requests

twisted.names

  • is both a domain name server and a client resolver library
  • we use DNSServerFactory, and pass to it a CustomResolver built on top of ResolverBase

CustomResolver

  • client.Resolver opens an upstream connection on TCP/UDP port 53, fetches the DNS packets, parses it to Twisted dns.Message, and dispatches it.
  • The CustomResolver mimics a client.Resolver for most of its part. It makes an API call over HTTPS, fetches the JSON, translates the JSON to Twisted dns.Message, and dispatches it similarily

Spices to Twisted Async

  • Reactor
  • Deferred

Reactor

  • The reactor is the core of the event loop within Twisted
  • The event loop is a programming construct that waits for and dispatches events or messages in a program
  • Choice of different reactors
  • reactor.callLater

Deferred

  • Twisted's way to deal with callbacks
  • Deferred is a promise. It's a forecast of things to come.
  • deferred.addCallback, deferred.addErrback
  • deferred.callback, deferred.errback

DNS Resource Record (RR) Types

  • DNS does not only deal with addresses
  • RR major types : A, AAAA, CNAME, MX, NS, TXT, SPF
  • Utilizing twisted.names.dns classes for RRs
  • Implementing decodeJSON for each RR class to work seamlessly like client.Resolver

Caveats

  • We must not assume to have a DNS system inplace when our app is being used
  • A simple HTTPS request would fail as dns.google.com would fail to resolve
  • Changing just the dns.google.com to an IP will not work as HTTPS SSL would fail for an IP (it would be valid for google domain)
  • To change the Host Header in the packet, we need to use HostHeaderSSLAdapter from requests-toolbelt

Putting pieces together 

github.com/arn7av/gDNS

Using it on system as primary DNS

  • Check if everything is running fine with dig
  • Running it as root (to allow binding it to port 53)
  • Depending on the OS, we follow instructions to make 127.0.0.1 as our DNS server
  • GG

To Infinity and Beyond 

  • Writing custom caching rules
  • Writing a separate resolver for our internal network and adding it to DNSServerFactory clients
  • Extending the failure mechanism to revert to DNS over TCP/UDP
  • Your imagination :-)

gDNS

By arnAV

gDNS

  • 1,339