Over the years, we’ve written and spoken on Naked Security many times about the thorny problem of DNS hijacking.
DNS, as you probably know, is short for domain name system, and you’ll often hear it described as the internet’s “telephone directory” or “gazetteer”.
If you’re not familiar with the word gazeteer, it refers to the index at the back of an atlas where you look up, say, Monrovia, Liberia in a convenient alphabetic list, and it says something like 184 - C4
. This tells you to turn straight to page 184, and to follow the grid lines down from the letter C at the top of the map, and across from the number 4 on the left. Where the lines meet, you’ll find Monrovia.
For most users, most DNS lookups go out containing a server name, asking for a reply to come back that includes what’s known as its A-record or its AAAA-record.
(A-records are used for 32-bit IPv4 internet numbers, such as 203.0.113.42
; AAAA-records are the equivalent answers for a 128-bit IPv6 addresses, such as 2001:db8:15a:d0c::42
 – in this article, we’ll just use A-records and IPv4 numbers, but the same security issues apply to the lookup process in both cases.)
Here’s an example, where we’re looking up the imaginary domain name naksec.test
via a DNS server that was specially created to track and teach you about DNS traffic.
We’ve used the old-school Linux tool dig
, short for domain internet groper, to generate a simple DNS request (dig
defaults to looking up A-records) for the server we want:
$ dig +noedns @127.42.42.254 naksec.test ;; QUESTION SECTION: ;naksec.test. IN A ;; ANSWER SECTION: NAKSEC.TEST. 5 IN A 203.0.113.42 ;; Query time: 1 msec ;; SERVER: 127.42.42.254#53(127.42.42.254) (UDP) ;; WHEN: Mon Jan 23 14:38:42 GMT 2023 ;; MSG SIZE rcvd: 56
Here’s how our DNS server dealt with the request, showing a hex dump of the incoming request, and the successful reply that went back:
---> Request from 127.0.0.1:57708 to 127.42.42.254:53 ---> 00000000 62 4e 01 20 00 01 00 00 00 00 00 00 06 6e 61 6b |bN. .........nak| 00000010 73 65 63 04 74 65 73 74 00 00 01 00 01 |sec.test..... | DNS lookup: A-record for naksec.test ==> A=203.0.113.42 <--- Reply from 127.42.42.254:53 to 127.0.0.1:57708 <--- 00000000 62 4e 84 b0 00 01 00 01 00 00 00 00 06 6e 61 6b |bN...........nak| 00000010 73 65 63 04 74 65 73 74 00 00 01 00 01 06 4e 41 |sec.test......NA| 00000020 4b 53 45 43 04 54 45 53 54 00 00 01 00 01 00 00 |KSEC.TEST.......| 00000030 00 05 00 04 cb 00 71 2a |......q* |
Note that, for performance reasons, most DNS requests use UDP, the user datagram protocol, which works on a send-and-hope basis: you fire off a UDP packet at the server you want to talk to, and then wait to see if a reply comes back.
This makes UDP much simpler and faster than its big cousin TCP, the transmission control protocol, which, as its name suggests, automatically takes care of lots of details that UDP doesn’t.
Notably, TCP deals with detecting data gets lost and asking foir it again; ensuring that any chunks of data arrive in the right order; and providing a single network connection that, once set up, can be used for sending and receiving at the same time.
UDP doesn’t have the concept of a “connection”, so that requests and replies essentially travel independently:
- A DNS request arrives at the DNS server in a UDP packet of its own.
- The DNS server keeps a record of which computer sent that particular packet.
- The server sets about finding an answer to send back, or deciding that there isn’t one.
- The server sends a reply to the original sender, using a second UDP packet.
From the level of the operating system or the network, those two UDP packets above are independent, standalone transmissions – they aren’t tied together as part of the same digital connection.
It’s up to the server to remember which client to send each reply to; and it’s up to the client to figure out which replies relate to which requests it originally sent out.
How can you be sure?
Learning CoreDNS: Configuring DNS for Cloud Native Environments
InfoSec books | InfoSec tools | InfoSec services