This repository is the official repository for ResolverFuzz published on the 33rd USENIX Security Symposium (USENIX Security 2024). The extended version of this paper is available on ArXiv.
ResolverFuzz
is a grammar-based blackbox fuzzing tool designed to detect non-crash vulnerabilities in DNS software automatically/semi-automatically via differential analysis among different DNS software. In total, we identified 23 vulnerabilities with 19 confirmed and 15 CVEs assigned.
@inproceedings{zhang2024resolverfuzz,
year = {2024},
author = {Zhang, Qifan and Bai, Xuesong and Li, Xiang and Duan, Haixin and Li, Qi and Li, Zhou},
title = {{ResolverFuzz: Automated Discovery of DNS Resolver Vulnerabilities with Query-Response Fuzzing}},
booktitle = {Proceedings of the 33rd USENIX Security Symposium},
series = {USENIX Security '24}
}
Software | Version | Docker Image |
---|---|---|
BIND | 9.18.0 | qifanz/resolverfuzz-bind9:9.18.0 |
Unbound | 1.16.0 | qifanz/resolverfuzz-unbound:1.16.0 |
Knot Resolver | 5.5.0 | qifanz/resolverfuzz-knot:5.5.0 |
PowerDNS | 4.7.0 | qifanz/resolverfuzz-powerdns:4.7.0 |
MaraDNS | 3.5.0022 | qifanz/resolverfuzz-maradns:3.5.0022 |
Technitium DNS | 10.0.1 | qifanz/resolverfuzz-technitium:10.0.1 |
The hardware specs of our workstation for ResolverFuzz
development and testing are:
- CPU: AMD Ryzen 5950X
- Memory: 128 GB
- Disk space: 1TB SSD (for OS) + 2TB SSD (for result storage)
ResolverFuzz
is configurable to fit workstations with different hard specs to boost the maximum performance.
ResolverFuzz
is developed and tested on Ubuntu 22.04 with Python 3.8 and Docker Engine. To set up the software dependencies, you first need to install Docker Engine and install Anaconda.
Note:
- After installation of Docker Engine, it's recommended to manage Docker as a non-root use. With this setting,
docker
commands don't have to be prefaced withsudo
. Otherwise, all thedocker
commands are needed to be prefaced withsudo
privilege.
Then, the Python environment named resolverfuzz
could be imported from environment.yml via the command:
conda env create -n resolverfuzz --file environment.yml
After installing the Docker Engine, Docker images ("images") are required to be pulled from the Docker hub. All the Docker containers ("containers") are created from those images.
First, we need to first pull images of 6 DNS software, and tag them for local use:
docker pull qifanz/resolverfuzz-bind9:9.18.0
docker pull qifanz/resolverfuzz-unbound:1.16.0
docker pull qifanz/resolverfuzz-knot:5.5.0
docker pull qifanz/resolverfuzz-powerdns:4.7.0
docker pull qifanz/resolverfuzz-maradns:3.5.0022
docker pull qifanz/resolverfuzz-technitium:10.0.1
docker tag qifanz/resolverfuzz-bind9:9.18.0 bind9:9.18.0
docker tag qifanz/resolverfuzz-unbound:1.16.0 unbound:1.16.0
docker tag qifanz/resolverfuzz-knot:5.5.0 knot:5.5.0
docker tag qifanz/resolverfuzz-powerdns:4.7.0 powerdns:4.7.0
docker tag qifanz/resolverfuzz-maradns:3.5.0022 maradns:3.5.0022
docker tag qifanz/resolverfuzz-technitium:10.0.1 technitium:10.0.1
Then, we need to pull the images of the attacker client, the authoritative server and DNSTap Listener:
docker pull qifanz/resolverfuzz-dnstap-listener
docker pull qifanz/resolverfuzz-attacker
docker pull qifanz/resolverfuzz-auth-srv
docker tag qifanz/resolverfuzz-dnstap-listener dnstap-listener
docker tag qifanz/resolverfuzz-attacker attacker
docker tag qifanz/resolverfuzz-auth-srv auth-srv
All the containers are connected to a Docker network named test_net_batch
. All the queries and responses generated by ResolverFuzz are transmitted via the Docker network. To create a Docker network named test_net_batch
with a subnet 172.22.0.0/16, run the command:
docker network create --subnet "172.22.0.0/16" test_net_batch
Since the authoritative server is implemented to send response packets via monitoring network traffic, enabling ICMP will automatically send back ICMP packets before our generated DNS responses are sent back. In consequence, the resolvers will never receive the packets with generated DNS responses. Therefore, we need to drop all the ICMP packets on the network.
To drop all the ICMP packets, We need to first check the interface of the Docker network via the command:
ip addr
Then, all the network interfaces will be displayed. We need to identify the interface with the IP range 172.22.0.1/16 assigned. For example, on our workstation, we could find:
6: br-0ed6b350123e: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:6e:e1:47:92 brd ff:ff:ff:ff:ff:ff
inet 172.22.0.1/16 brd 172.22.255.255 scope global br-0ed6b350123e
valid_lft forever preferred_lft forever
In this case, the network interface in the OS for the Docker network test_net_batch
is br-0ed6b350123e
. Then, we drop all the ICMP packets on the network interface with the command:
sudo iptables -I FORWARD -i [network_interface] -p icmp -j DROP
On our workstation, for example, the command will be:
sudo iptables -I FORWARD -i br-0ed6b350123e -p icmp -j DROP
We implemented a local nameserver to avoid possible effects on other remote nameservers. Installation of this local nameserver is optional, and will not affect the performance of ResolverFuzz. See README.md for instructions.
See README.md for instructions.
See README.md for instructions.
- Pre-published paper
- Extended version
- Poster presented on NDSS 2024
The artifacts of ResolverFuzz, including this repository, are licensed under the MIT license. See LICENSE for details.