From: Petr Špaček Date: Mon, 28 Jul 2025 09:33:14 +0000 (+0200) Subject: Test that spoofed DNAME is not accepted via spoofable transport X-Git-Tag: v9.21.17~14^2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=e223ee709765e6eff2bb6ae980ec5eec83d64390;p=thirdparty%2Fbind9.git Test that spoofed DNAME is not accepted via spoofable transport A single spoofed DNAME answer can impact many names, and because of the nature of DNAME, the attacker can use randomized query names to get unlimited number of tries to spoof the answer. To limit impact, we should not be accepting DNAME over insecure transport, like UDP without cookies etc. In short, the attacker tries to spoof at least one answer that has the following form: opcode QUERY rcode NOERROR flags QR AA ;QUESTION trigger$RANDOM.test. IN A ;ANSWER trigger$RANDOM.test. 3600 IN CNAME trigger$RANDOM.attacker.net. test. 3600 IN DNAME attacker.net. ;AUTHORITY ;ADDITIONAL This has been discovered internally. Co-authored-by: Michał Kępień --- diff --git a/bin/tests/system/bailiwick/ans2/ans.py b/bin/tests/system/bailiwick/ans2/ans.py index d1627fd5bd6..1a9be3d931e 100644 --- a/bin/tests/system/bailiwick/ans2/ans.py +++ b/bin/tests/system/bailiwick/ans2/ans.py @@ -77,6 +77,31 @@ class ParentGlueSpoofer(ResponseSpoofer, mode="parent-glue"): yield DnsResponseSend(response, authoritative=False) +class DnameSpoofer(ResponseSpoofer, mode="dname"): + + qname = "trigger.victim." + + async def get_responses( + self, qctx: QueryContext + ) -> AsyncGenerator[ResponseAction, None]: + response = qctx.prepare_new_response(with_zone_data=False) + + cname_rrset = dns.rrset.from_text( + qctx.qname, + TTL, + qctx.qclass, + dns.rdatatype.CNAME, + "trigger.attacker.", + ) + dname_rrset = dns.rrset.from_text( + "victim.", TTL, qctx.qclass, dns.rdatatype.DNAME, "attacker." + ) + response.answer.append(cname_rrset) + response.answer.append(dname_rrset) + + yield DnsResponseSend(response, authoritative=True) + + def main() -> None: spoofing_server().run() diff --git a/bin/tests/system/bailiwick/tests_bailiwick.py b/bin/tests/system/bailiwick/tests_bailiwick.py index 2e1c845a220..7245c71bce2 100644 --- a/bin/tests/system/bailiwick/tests_bailiwick.py +++ b/bin/tests/system/bailiwick/tests_bailiwick.py @@ -109,3 +109,11 @@ def test_bailiwick_parent_glue(servers: Dict[str, NamedInstance]) -> None: time.sleep(61) check_domain_hijack(ns4) + + +def test_bailiwick_spoofed_dname(servers: Dict[str, NamedInstance]) -> None: + set_spoofing_mode(ans1="none", ans2="dname") + + ns4 = servers["ns4"] + send_trigger_query(ns4, "trigger.victim.") + check_domain_hijack(ns4)