Files
metasploit-gs/lib/msf/core/exploit/dns/server.rb
T
RageLtMan 2347c8df99 Create basic packet manipulation modules
Create Rex::Proto::DNS::Packet and Packet::Raw to allow common
parsing, validation, and raw data operations across both Rex and
Msf namespaces.

The modules contain class methods and do not need to be mixed in
to use their functionality Packet.method is enough, and reduces GC
strain since new objects are not constantly being instantiated, and
these modules contain no internal state.

Clean up UDP socket leak from Rex::Proto::DNS::Server under certain
conditions.

Create Msf::Exploit::DNS::Common mixin to provide descendants with
access to Packet and the hostname Regex.

-----

Testing:
  Tested running the RC provided in the pull request
  Manual testing in IRB/Pry while porting PoC for CVE-2015-7547
2017-06-23 19:58:37 -04:00

175 lines
4.7 KiB
Ruby

# -*- coding: binary -*-
require 'msf/core'
require 'rex/proto/dns'
module Msf
###
#
# This module exposes methods for querying a remote DNS service
#
###
module Exploit::Remote::DNS
module Server
include Common
include Exploit::Remote::SocketServer
#
# Initializes an exploit module that serves DNS requests
#
def initialize(info = {})
super
register_options(
[
OptPort.new('SRVPORT', [true, 'The local port to listen on.', 53]),
OptString.new('STATIC_ENTRIES', [ false, "DNS domain search list (hosts file or space/semicolon separate entries)"]),
OptBool.new('DISABLE_RESOLVER', [ false, "Disable DNS request forwarding", false]),
OptBool.new('DISABLE_NS_CACHE', [ false, "Disable DNS response caching", false])
], Exploit::Remote::DNS::Server
)
register_advanced_options(
[
OptBool.new('DNS_SERVER_UDP', [true, "Serve UDP DNS requests", true]),
OptBool.new('DNS_SERVER_TCP', [true, "Serve TCP DNS requests", false])
], Exploit::Remote::DNS::Server
)
end
attr_accessor :service
#
# Process static entries
#
# @param entries [String] Filename or String containing static entries
# @param type [String] Type of record for which to add static entries
#
# @return [Array] List of static entries in the cache
def add_static_hosts(entries = datastore['STATIC_ENTRIES'], type = 'A')
return if entries.nil? or entries.empty?
if File.file?(File.expand_path(entries))
data = File.read(File.expand_path(entries)).split("\n")
else
data = entries.split(';')
end
data.each do |entry|
next if entry.gsub(/\s/,'').empty?
addr, names = entry.split(' ', 2)
names.split.each do |name|
name << '.' unless name[-1] == '.'
service.cache.add_static(name, addr, type)
end
end
service.cache.records.select {|r,e| e == 0}
end
#
# Flush all static entries
#
def flush_static_hosts
data.cache.records.select {|r,e| e == 0}.each do |flush|
data.cache.delete(flush)
end
end
#
# Flush cache entries
# @param static [TrueClass, FalseClass] flush static hosts
def flush_cache(static = false)
self.service.cache.stop(true)
flush_static_hosts if static
self.service.cache.start
end
#
# Handle incoming requests
# Override this method in modules to take flow control
#
def on_dispatch_request(cli, data)
service.default_dispatch_request(cli,data)
end
#
# Handle incoming requests
# Override this method in modules to take flow control
#
def on_send_response(cli, data)
cli.write(data)
end
#
# Starts the server
#
def start_service
options.validate(datastore) # This is a hack, DS values should not be Strings prior to this
if !datastore['DISABLE_RESOLVER'] and self.respond_to?(:setup_resolver)
setup_resolver
end
begin
comm = _determine_server_comm
self.service = Rex::Proto::DNS::Server.new(
datastore['SRVHOST'],
datastore['SRVPORT'],
datastore['DNS_SERVER_UDP'],
datastore['DNS_SERVER_TCP'],
(datastore['DISABLE_RESOLVER'] ? false : @dns_resolver),
comm,
{'Msf' => framework, 'MsfExploit' => self}
) if self.service.nil?
self.service.dispatch_request_proc = Proc.new do |cli, data|
on_dispatch_request(cli,data)
end
self.service.send_response_proc = Proc.new do |cli, data|
on_send_response(cli,data)
end
add_static_hosts
self.service.start(!datastore['DISABLE_NS_CACHE'])
rescue ::Errno::EACCES => e
if (srvport.to_i < 1024)
print_line(" ")
print_error("Could not start the DNS server: #{e}.")
print_error(
"This module is configured to use a privileged port (#{srvport}). " +
"On Unix systems, only the root user account is allowed to bind to privileged ports." +
"Please run the framework as root to use this module."
)
print_error(
"On Microsoft Windows systems, this error is returned when a process attempts to "+
"listen on a host/port combination that is already in use. For example, Windows XP "+
"will return this error if a process attempts to bind() over the system SMB/NetBIOS services."
)
print_line(" ")
end
raise e
end
end
#
# Stops the server
# @param destroy [TrueClass,FalseClass] Dereference the server object
def stop_service(destroy = false)
self.service.stop unless self.service.nil?
if destroy
@dns_resolver = nil
self.service = nil
end
end
#
# Resets the DNS server
#
def reset_service
stop_service(true)
start_service
end
end
end
end