Name services (DNS)
Setup
We will be using a virtual machine in the faculty's cloud.
When creating a virtual machine in the Launch Instance window:
- Name your VM using the following convention:
scgc_lab<no>_<username>
, where<no>
is the lab number and<username>
is your institutional account. - Select Boot from image in Instance Boot Source section
- Select SCGC Template in Image Name section
- Select the m1.large flavor.
In the base virtual machine:
-
Download the laboratory archive from here in the
work
directory. Use:wget https://repository.grid.pub.ro/cs/scgc/laboratoare/lab-dns.zip
to download the archive. -
Extract the archive. The
.qcow2
files will be used to start virtual machines using therunvm.sh
script. -
Start the virtual machines using
bash runvm.sh
. -
The username for connecting to the nested VMs is
student
and the password isstudent
. -
For ease of use we recommend adding entries in the
/etc/hosts
file corresponding to the two VMs:192.168.100.11 dns
192.168.100.12 helper
- These two lines will allow using
dns
instead of the IP address of the DNS VM for clarity. Likewise, we can usehelper
instead of the IP address of the helper VM.
$ # change the working dir
$ cd ~/work
$ # download the archive
$ wget https://repository.grid.pub.ro/cs/scgc/laboratoare/lab-dns.zip
$ unzip lab-dns.zip
$ # start VMs; it may take a while
$ bash runvm.sh
$ # check if the VMs booted
$ virsh net-dhcp-leases labvms
Please note that the dns and helper names will be used interchangeably
with their respective IP addresses throughout the lab. If you do not define the
host-IP mappings in each VM, you may encounter errors if you attempt to use
the name in commands (e.g., host google.com dns
). In this case, you can use
the IP address directly, without any issues (e.g., host google.com 192.168.100.11
).
DNS Resolvers
In this task we will examine how we ca use two DNS resolvers to query DNS servers.
The two DNS resolvers we will use are host
and dig
.
root@dns:~# apt update
[...]
root@dns:~# apt install host dnsutils
[...]
host
Next, we find out the IP address of a website using host.
root@dns:~# host acs.pub.ro
acs.pub.ro has address 141.85.227.151
acs.pub.ro mail is handled by 10 mx.acs.pub.ro.
We can see from this output DNS records, such as NS(name server), MX(mail server), AAAA(IPv6 address), SOA(start of authority).
For more information, we can use the -v
parameter.
root@dns:~# host -v acs.pub.ro
Trying "acs.pub.ro"
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 1805
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 3, ADDITIONAL: 3
;; QUESTION SECTION:
;acs.pub.ro. IN A
;; ANSWER SECTION:
acs.pub.ro. 28800 IN A 141.85.227.151
;; AUTHORITY SECTION:
acs.pub.ro. 28800 IN NS ns1.cs.pub.ro.
acs.pub.ro. 28800 IN NS ns1.grid.pub.ro.
acs.pub.ro. 28800 IN NS ns2.cs.pub.ro.
;; ADDITIONAL SECTION:
ns1.cs.pub.ro. 28800 IN A 141.85.226.5
ns1.grid.pub.ro. 3600 IN A 141.85.241.15
ns2.cs.pub.ro. 28800 IN A 141.85.241.113
Received 154 bytes from 141.85.241.15#53 in 1 ms
Trying "acs.pub.ro"
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 58004
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 0
;; QUESTION SECTION:
;acs.pub.ro. IN AAAA
;; AUTHORITY SECTION:
acs.pub.ro. 28800 IN SOA ns1.cs.pub.ro. admin.acs.pub.ro. 2017120701 28800 7200 604800 86400
Received 77 bytes from 141.85.241.15#53 in 0 ms
Trying "acs.pub.ro"
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 755
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 3, ADDITIONAL: 4
;; QUESTION SECTION:
;acs.pub.ro. IN MX
;; ANSWER SECTION:
acs.pub.ro. 1 IN MX 10 mx.acs.pub.ro.
;; AUTHORITY SECTION:
acs.pub.ro. 28800 IN NS ns1.grid.pub.ro.
acs.pub.ro. 28800 IN NS ns1.cs.pub.ro.
acs.pub.ro. 28800 IN NS ns2.cs.pub.ro.
;; ADDITIONAL SECTION:
mx.acs.pub.ro. 28800 IN A 141.85.227.151
ns1.cs.pub.ro. 28800 IN A 141.85.226.5
ns1.grid.pub.ro. 3600 IN A 141.85.241.15
ns2.cs.pub.ro. 28800 IN A 141.85.241.113
Received 173 bytes from 141.85.241.15#53 in 2 ms
In order to request a specific record we can use the -t
parameter and the record we want.
root@dns:~# host -t ns acs.pub.ro
acs.pub.ro name server ns2.cs.pub.ro.
acs.pub.ro name server ns1.cs.pub.ro.
acs.pub.ro name server ns1.grid.pub.ro.
root@dns:~# host -t mx acs.pub.ro
acs.pub.ro mail is handled by 10 mx.acs.pub.ro.
root@dns:~# host -t soa acs.pub.ro
acs.pub.ro has SOA record ns1.cs.pub.ro. admin.acs.pub.ro. 2017120701 28800 7200 604800 86400
host will query the DNS servers from /etc/resolv.conf
. If we want to query a specific DNS server, we can use host as such:
root@dns:~# host acs.pub.ro 8.8.8.8
Using domain server:
Name: 8.8.8.8
Address: 8.8.8.8#53
Aliases:
acs.pub.ro has address 141.85.227.151
acs.pub.ro mail is handled by 10 mx.acs.pub.ro.
dig
Now use dig to get the detailed information, the IP address and specific records for a website.
Also, use dig to query the Google DNS server 8.8.8.8
.
It is noteworthy, that dig and host do not use /etc/nsswitch.conf
for querying
DNS servers and they do not use the system's DNS resolver, which is usually a library.
We can see this from the following commands:
root@dns:~# strace -e openat host acs.pub.ro
[...]
openat(AT_FDCWD, "/etc/resolv.conf", O_RDONLY) = 6
acs.pub.ro has address 141.85.227.151
acs.pub.ro mail is handled by 10 mx.acs.pub.ro.
[...]
root@dns:~# strace -e openat ping -c 1 acs.pub.ro
[...]
openat(AT_FDCWD, "/etc/resolv.conf", O_RDONLY|O_CLOEXEC) = 4
openat(AT_FDCWD, "/etc/resolv.conf", O_RDONLY|O_CLOEXEC) = 4
openat(AT_FDCWD, "/etc/nsswitch.conf", O_RDONLY|O_CLOEXEC) = 4
[...]
openat(AT_FDCWD, "/etc/host.conf", O_RDONLY|O_CLOEXEC) = 4
openat(AT_FDCWD, "/etc/hosts", O_RDONLY|O_CLOEXEC) = 4
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 4
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libnss_dns.so.2", O_RDONLY|O_CLOEXEC) = 4
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libresolv.so.2", O_RDONLY|O_CLOEXEC) = 4
PING acs.pub.ro (141.85.227.151) 56(84) bytes of data.
openat(AT_FDCWD, "/etc/hosts", O_RDONLY|O_CLOEXEC) = 4
64 bytes from acs.pub.ro (141.85.227.151): icmp_seq=1 ttl=62 time=0.688 ms
--- acs.pub.ro ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.688/0.688/0.688/0.000 ms
We can see that host will use the /etc/resolv.conf
file directly,
while the ping command reads the resolver configuration first:
the /etc/nsswitch.conf
and the /etc/resolv.conf
file are opened and then
calls are made to the resolving library (libresolv.so.2
).
DNS Servers
Now that we have seen how we can query DNS servers, let's configure our very own DNS server on the dns VM using bind.
root@dns:~# apt install bind9 bind9utils
For Debian-based distributions, bind will have the following configuration files:
- Main configuration file:
/etc/bind/named.conf.options
. - Zone names file:
/etc/bind/named.conf.local
. - Default zone file location:
/var/cache/bind/
.
We will set up the dns VM to respond to queries about our very own domain.
Use <your_last_name>.scgc.ro
as your very own domain name.
In the following examples we will be using scgc.ro
as our domain.
Simple DNS configuration
First, we will configure our DNS server to listen for queries received from outside the server.
For this we have to add the following line to the /etc/bind/named.conf.options
file:
options {
[...]
dnssec-validation no;
[...]
listen-on { 192.168.100.11; localhost; };
[...]
};
Most services do not have automatic configuration reloads. Make sure to restart the DNS service whenever you make a change in the configuration files.
The IP address 192.168.100.11, used in the example may not be the IP address that you will use when configuring your server.
Replace it with your own IP address, which can be determined by using the ip
command:
root@dns:~# ip a
[...]
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc pfifo_fast state UP group default qlen 1000
link/ether fa:16:3e:00:7f:98 brd ff:ff:ff:ff:ff:ff
inet 192.168.100.11/16 brd 10.9.255.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::f816:3eff:fe00:7f98/64 scope link
valid_lft forever preferred_lft forever
Next, we will configure the local file(/etc/bind/named.conf.local
), to specify our DNS zone.
Aside from a few comments, the file should be empty.
Add the zone with the following lines (substitute the zone name with your own):
zone "scgc.ro" {
type master;
file "/etc/bind/db.scgc.ro"; # zone file path
};
We will base our zone file on the sample db.local
zone file.
cp /etc/bind/db.local /etc/bind/db.scgc.ro
Initially, it will look something like the following:
root@dns:~# cat /etc/bind/db.scgc.ro
;
; BIND data file for local loopback interface
;
$TTL 604800
@ IN SOA localhost. root.localhost. (
2 ; Serial
604800 ; Refresh
86400 ; Retry
2419200 ; Expire
604800 ) ; Negative Cache TTL
;
@ IN NS localhost. ; delete this line
@ IN A 127.0.0.1 ; delete this line
@ IN AAAA ::1 ; delete this line
First, you will want to edit the SOA record.
Replace the localhost
with your domain name.
Also, every time you edit a zone file, you should increment the serial value before you restart the named process; we will increment it to 3
.It should look something like this:
@ IN SOA scgc.ro. root.scgc.ro. (
3 ; Serial
Now delete the three records at the end of the file (after the SOA record).
If you're not sure which lines to delete, they are marked with a delete this line
comment above.
At the end of the file, add your nameserver record with the following line (replace the name with your own).
Note that the second column specifies that these are NS
records:
; name servers - NS records
IN NS ns1.scgc.ro.
Then add the A records for your hosts that belong in this zone.
This includes any server whose name we want to end with .scgc.ro
(substitute the names and IP addresses).
Using our example names and private IP addresses, we will add A
records for ns1
,
and a host corresponding to the www.scgc.ro
, like so:
; name servers - A records
ns1.scgc.ro. IN A 192.168.100.11
www.scgc.ro. IN A 192.168.100.11
Our final example forward zone file looks like the following:
$TTL 604800
@ IN SOA scgc.ro. root.scgc.ro. (
3 ; Serial
604800 ; Refresh
86400 ; Retry
2419200 ; Expire
604800 ) ; Negative Cache TTL
; name servers - NS records
IN NS ns1.scgc.ro.
; name servers - A records
ns1.scgc.ro. IN A 192.168.100.11
www.scgc.ro. IN A 192.168.100.11
Testing our configuration
Now that we have the a minimal configuration, let us check that it works.
Run the following command to check the syntax of the named.conf*
files:
root@dns:~# named-checkconf
If your named configuration files have no syntax errors, you will return to your shell prompt and see no error messages. If there are problems with your configuration files, review the error message and fix the configuration files.
The named-checkzone
command can be used to check the correctness of your zone files.
Its first argument specifies a zone name, and the second argument specifies the
corresponding zone file, which are both defined in named.conf.local
.
For example, to check the scgc.ro
zone configuration, run the following command (change the names to match your zone and file):
root@dns:~# named-checkzone scgc.ro /etc/bind/db.scgc.ro
zone scgc.ro/IN: loaded serial 3
OK
When all of your configuration and zone files have no errors in them, you should be ready to restart the BIND service:
root@dns:~# service bind9 restart
Now we should be able to test our DNS server.
We will be using host
, however feel free to use dig
or any other command to test your server:
root@dns:~# host www.scgc.ro localhost
Using domain server:
Name: 192.168.100.11
Address: 192.168.100.11#53
Aliases:
www.scgc.ro has address 192.168.100.11
root@dns:~# host -t ns scgc.ro localhost
Using domain server:
Name: 192.168.100.11
Address: 192.168.100.11#53
Aliases:
scgc.ro name server ns1.scgc.ro.
root@dns:~# host ns1.scgc.ro localhost
Using domain server:
Name: 192.168.100.11
Address: 192.168.100.11#53
Aliases:
ns1.scgc.ro has address 192.168.100.11
Now let's try to query from outside the server.
We will test that the helper
VM will receive the same response(replace with the appropriate name and IP address):
[root@helper ~]# host www.scgc.ro dns
Using domain server:
Name: 192.168.100.11
Address: 192.168.100.11#53
Aliases:
www.scgc.ro has address 192.168.100.11
To install host, dig, nslookup on Alma Linux 8, run the following command:
sudo dnf install bind-utils
Additional records
Add another NS record to the zone corresponding to another IP address and two MX records
(one for the dns server with priority 10
and one for the helper server with priority 20
).
See here how to configure MX records.
Restart your BIND server and test your configurations.
DNS Fine Tuning
Allow only local recursive queries
By default, bind will make recursive queries for any unknown query received.
Recursive queries are quite costly, therefore they should only be allowed explicitly.
We can check this by quering for google.com
from the dns and helper VMs:
root@dns:~# host google.com localhost
Using domain server:
Name: localhost
Address: ::1#53
Aliases:
google.com has address 216.58.214.206
google.com has IPv6 address 2a00:1450:400d:802::200e
google.com mail is handled by 40 alt3.aspmx.l.google.com.
google.com mail is handled by 50 alt4.aspmx.l.google.com.
google.com mail is handled by 30 alt2.aspmx.l.google.com.
google.com mail is handled by 10 aspmx.l.google.com.
google.com mail is handled by 20 alt1.aspmx.l.google.com.
[root@helper ~]# host google.com dns
Using domain server:
Name: 192.168.100.11
Address: 192.168.100.11#53
Aliases:
google.com has address 216.58.214.206
google.com has IPv6 address 2a00:1450:400d:802::200e
google.com mail is handled by 10 aspmx.l.google.com.
google.com mail is handled by 30 alt2.aspmx.l.google.com.
google.com mail is handled by 20 alt1.aspmx.l.google.com.
google.com mail is handled by 40 alt3.aspmx.l.google.com.
google.com mail is handled by 50 alt4.aspmx.l.google.com.
In order to restrict who can make recursive queries, we have to edit the /etc/bind/named.conf.options
file and add the following lines:
acl goodguys { 192.168.100.11; 127.0.0.1; ::1; };
options {
[...]
allow-recursion { goodguys; };
recursion yes;
[...]
};
Do not forget to restart the BIND service after changing the configuration.
Now, if we query again for google.com
, from the dns VM the query should suceed and from the helper VM it should now fail.
[root@helper ~]# host google.com dns
Using domain server:
Name: 192.168.100.11
Address: 192.168.100.11#53
Aliases:
Host google.com.cloud.grid.pub.ro not found: 5(REFUSED)
Allow recursive queries from a specific host
Change the /etc/bind/named.conf.options file
on the dns VM to allow recursive queries from the helper VM.
Security of DNS Servers
DNS is a critical infrastructure and it is one of the most desired hosts to be compromised. Some common attacks on the DNS servers are:
- DNS Spoofing: A MITM (Man-in-the-Middle) attack where a malicious host acts like a legitimate DNS server and serves another IP for the desired domain.
- DoS Attacks: by flooding the DNS servers with random domains (when recursive queries are allowed) or random subdomains, the DNS server will not respond to legitimate queries.
- DNS Hijacking
DNS Reconnaissance
When inspecting the security of a network (pentesting), the first step is to conduct a reconnaissance attack. Usually, you start by inspecting all the hosts in the target network, their open ports and their services.
For this task, you must allow recursive queries for your DNS server.
You can do additional checking on the DNS server. You can discover new hosts, maybe ones not exposed to the Internet (i.e. with local network IP addresses) and you can get a better view of the target's network layout. From there, you can start the next attack step.
Add the following zone to your DNS server:
$ cat /etc/bind/db.demoscgc.ro
;
; BIND data file for local loopback interface
;
$TTL 604800
@ IN SOA demoscgc.ro. admin.demoscgc.ro. (
20220310 ; Serial
604800 ; Refresh
86400 ; Retry
2419200 ; Expire
604800 ) ; Negative Cache TTL
;
; NS records
IN NS ns1.demoscgc.ro.
IN NS ns2.demoscgc.ro.
; MX records
IN MX 42 mail.demoscgc.ro.
IN MX 60 mail2.demoscgc.ro.
; A records
ns1.demoscgc.ro. IN A 192.168.100.11
ns2.demoscgc.ro. IN A 192.168.100.2
www.demoscgc.ro. IN A 192.168.100.1
mail.demoscgc.ro. IN A 192.168.100.3
mail2.demoscgc.ro. IN A 192.168.100.4
blog.demoscgc.ro. IN A 192.168.100.5
internal.demoscgc.ro. IN A 192.168.100.6
vmware.demoscgc.ro. IN A 192.168.100.7
ftp.demoscgc.ro. IN A 192.168.100.8
support.demoscgc.ro. IN A 192.168.100.9
transfer IN CNAME ftp
vlog IN CNAME blog
intranet IN CNAME internal
Don't forget to add another zone to the /etc/bind/named.conf.local
file.
Restart bind
.
Install dnsrecon
on the BASE VM:
$ sudo apt update
$ sudo apt install dnsrecon
Start a scan over your DNS Server:
$ dnsrecon -d demoscgc.ro -n 192.168.100.11 -t std,brt
[*] Performing General Enumeration of Domain:demoscgc.ro
[-] DNSSEC is not configured for demoscgc.ro
[-] Error while resolving SOA record.
[*] NS ns1.demoscgc.ro 192.168.100.11
[-] Recursion enabled on NS Server 192.168.100.11
[*] Bind Version for 192.168.100.11 b'9.16.22-Debian'
....
dnsrecon
scans your DNS server and extract different information such as:
- if you have DNSSEC
- if your nameserver allows recursion
- your bind version
- NS entries
- mail servers
- searches against commonly used subdomain name
Run dnsrecon -h
for more details.
The scan will take a while. You can let it run and continue with other tasks.
NXDOMAIN Attack
A common DNS Denial-of-Service attack is NXDOMAIN attack.
NXDOMAIN
(Non eXistent DOMAIN) is the error you receive when checking for an nonexistent domain name:
$ host magic.scgc.ro
Host magic.scgc.ro not found: 3(NXDOMAIN)
When flooding a DNS Server with unique requests that will return NXDOMAIN
, you
may make the server unavailable for legitimate requests.
We will see how to make a denial of service attack on a DNS server. You will need to open three terminals to the host (SCGC Template).
For the sake of this task, enable recursion for the helper VM. This should be already configured from the previous task, but double check to make sure.
Connect to the helper VM. Clone the following repository and change the working directory:
[student@helper ~]$ git clone https://github.com/shiroe41/DNS-NXDOMAIN-FLood-Attack
[student@helper ~]$ cd DNS-NXDOMAIN_FLood-Attack/src
Modify the source code to use your DNS server IP address and compile the code:
[student@helper ~]$ grep dest_sock_addr.sin_addr.s_addr dos_attack.c
dest_sock_addr.sin_addr.s_addr = inet_addr("192.168.100.11"); /* target DNS server ip address */
ip_header->ip_dst.s_addr = dest_sock_addr.sin_addr.s_addr;
[student@helper ~]$ gcc -o dos_attack dos_attack.c
Interrogate your DNS server to check if everything works fine (both from the base VM and from the helper VM).
Use <your_last_name>.scgc.ro
(the domain you configured earlier) for testing. In the following examples we will be using scgc.ro as our domain.
$ host scgc.ro dns
Using domain server:
Name: 192.168.100.11
Address: 192.168.100.11#53
Aliases:
scgc.ro mail is handled by 42 mail.scgc.ro.
scgc.ro mail is handled by 60 mail2.scgc.ro.
From the base VM, run tcpdump
:
$ sudo tcpdump -i virbr-labs udp port 53 # we check only the DNS traffic
From the first terminal, start the attack:
[student@helper ~]$ sudo ./dos_attack
While the attack is running, from the base VM, test the DNS server:
$ host scgc.ro 192.168.100.11
Using domain server:
Name: 192.168.100.11
Address: 192.168.100.11#53
Aliases:
;; connection timed out; no servers could be reached
The server will hardly respond or will fail.
Stop the attack and the tcpdump. Inspect the tcpdump output:
...
23:26:48.364788 IP 10.0.2.20.29264 > 192.168.100.11.domain: 40664+ A? idcdy.fuawv.lulix. (35)
23:26:48.364829 IP 10.0.2.20.8518 > 192.168.100.11.domain: 11612+ A? lsrae.olszf.lkttp. (35)
23:26:48.364870 IP 10.0.2.20.46214 > 192.168.100.11.domain: 28079+ A? ctqzq.bvblt.xltqp. (35)
^C
760212 packets captured
1864674 packets received by filter
1104462 packets dropped by kernel
We can see that a high number of packages were sent to the DNS server in a short time. Pay attention to the DNS requests: all the domains are randomly generated.
A mitigation method is to allow recursion only for some hosts. You can either remove the helper VM from the ACL list or disable recursion. Redo the steps above and check the new behaviour. Even though the DNS Server does not make any more recursive queries and the attacker's queries are refused, the server is still flooded and unavailable.
Another workaround is to limit the response rate. By adding the following lines in
your /etc/bind/named.conf.options
file, you can limit the number of unique responses
that are delivered each second:
...
options {
...
rate-limit {
responses-per-second 20;
};
...
};
Restart bind and redo the attack steps. You can see in the tcpdump output that the DNS server ignores the queries from the helper network, and legitimate queries are resolved. However, you should be careful when you set this option since it may affect legitimate traffic (depending on your expected traffic).
Usually, the best way to mitigate these attacks is to use a firewall. You can set your DNS server behind a dedicated firewall (CISCO, FortiGate, Juniper, PaloAlto, pfSense, MikroTik) or use a software firewall on your server.
DNS Spoofing
DNS Spoofing is an attack that relies on sending modified DNS responses to the victim.
When the victim tries to access a domain example.com
,
the attacker will respond that example.com
has an IP controlled by the attacker.
A possible scenario that uses DNS Spoofing in the vector attack is presented in the image above. The attacker is a malicious host in the same network as the victim (a coffee shop with free public WiFi). Using ARP Cache Poisoning, the attacker listen to all the traffic between the victim and the local router (acts like a MitM). When the victim wants to access a well-known domain (e.g. a social network page), the solver will check locally for caches. If the caches are expired, they will send a DNS server request. The attacker will intercept the traffic and will respond that the social network has a particular IP address. Using that IP, the victim will connect to a page that resembles the social network one. Thus, the attacker can steal the victim's credentials.
A method of mitigating this kind of attack is to set up DNSSEC. DNSSEC signs the DNS responses, and the victim's local server will reject the attacker's mangled package.
Reproducing this attack is out of the scope of this laboratory. We'll not do that for the moment. However, if you want to see how this works, you can try and check replicating this attack with virtual machines. You need to set up a VM that acts as a DNS server and VMs for the victim, attacker, and webserver to redirect traffic. You can add DNSSEC to your DNS Server configuration and see if you can reproduce the attack.
DNSSEC
DNS is vulnerable to MITM attacks. An attacker can pretend to be a DNS server and supply an unsuspecting victim with the wrong IP address for a URL. In order to combat this, DNSSEC can be used and configured to validate the identity of the DNS server.
Using the instructions from here, setup DNSSEC for your DNS server.