diff --git a/Gemfile b/Gemfile index 83b7b2811fbd..768eb09b0144 100644 --- a/Gemfile +++ b/Gemfile @@ -53,3 +53,5 @@ group :test do gem 'timecop' end +# remove after https://github.com/rapid7/rex-socket/pull/65 is landed +gem 'rex-socket', git: 'https://github.com/zeroSteiner/rex-socket', branch: 'feat/util-is-name' diff --git a/Gemfile.lock b/Gemfile.lock index 748516bd4b07..a203ed83eac9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,3 +1,11 @@ +GIT + remote: https://github.com/zeroSteiner/rex-socket + revision: 764718bf3dd397c0a5ecc41ee0874d826e9c9144 + branch: feat/util-is-name + specs: + rex-socket (0.1.56) + rex-core + PATH remote: . specs: @@ -419,8 +427,6 @@ GEM metasm rex-core rex-text - rex-socket (0.1.55) - rex-core rex-sslscan (0.1.10) rex-core rex-socket @@ -562,6 +568,7 @@ DEPENDENCIES pry-byebug rake redcarpet + rex-socket! rspec-rails rspec-rerun rubocop diff --git a/lib/msf/ui/console/command_dispatcher/dns.rb b/lib/msf/ui/console/command_dispatcher/dns.rb index bca88d4ee6c9..89db88e7d584 100755 --- a/lib/msf/ui/console/command_dispatcher/dns.rb +++ b/lib/msf/ui/console/command_dispatcher/dns.rb @@ -338,11 +338,16 @@ def add_static_dns(*args) end hostname = args.shift - if (ip_address = args.find { |a| !Rex::Socket.is_ip_addr?(a) }) + if !Rex::Proto::DNS::StaticHostnames.is_valid_hostname?(hostname) + raise ::ArgumentError.new("Invalid hostname: #{hostname}") + end + + ip_addresses = args + if (ip_address = ip_addresses.find { |a| !Rex::Socket.is_ip_addr?(a) }) raise ::ArgumentError.new("Invalid IP address: #{ip_address}") end - args.each do |ip_address| + ip_addresses.each do |ip_address| resolver.static_hostnames.add(hostname, ip_address) print_status("Added static hostname mapping #{hostname} to #{ip_address}") end @@ -482,8 +487,11 @@ def remove_static_dns(*args) end hostname = args.shift - ip_addresses = args + if !Rex::Proto::DNS::StaticHostnames.is_valid_hostname?(hostname) + raise ::ArgumentError.new("Invalid hostname: #{hostname}") + end + ip_addresses = args if ip_addresses.empty? ip_addresses = resolver.static_hostnames.get(hostname, Dnsruby::Types::A) + resolver.static_hostnames.get(hostname, Dnsruby::Types::AAAA) if ip_addresses.empty? diff --git a/lib/rex/proto/dns/static_hostnames.rb b/lib/rex/proto/dns/static_hostnames.rb index cce09e171e77..4b43771b616b 100644 --- a/lib/rex/proto/dns/static_hostnames.rb +++ b/lib/rex/proto/dns/static_hostnames.rb @@ -69,7 +69,7 @@ def get1(hostname, type = Dnsruby::Types::A) # @rtype [Array] def get(hostname, type = Dnsruby::Types::A) hostname = hostname.downcase - @hostnames.fetch(hostname, {}).fetch(type, []) + @hostnames.fetch(hostname, {}).fetch(type, []).dup end # Add an IP address for the specified hostname. @@ -78,6 +78,12 @@ def get(hostname, type = Dnsruby::Types::A) # @param [IPAddr, String] ip_address The IP address that is being defined for the hostname. If this value is a # string, it will be converted to an IPAddr instance. def add(hostname, ip_address) + unless self.class.is_valid_hostname?(hostname) + # it is important to validate the hostname because assumptions about what characters it may contain are made + # when saving and loading it from the configuration + raise ::ArgumentError.new("Invalid hostname: #{hostname}") + end + ip_address = IPAddr.new(ip_address) if ip_address.is_a?(String) && Rex::Socket.is_ip_addr?(ip_address) hostname = hostname.downcase @@ -129,6 +135,16 @@ def delete(hostname, ip_address) def flush @hostnames.clear end + + def self.is_valid_hostname?(name) + # check if it appears to be a fully qualified domain name, e.g. www.metasploit.com + return true if Rex::Socket.is_name?(name) + + # check if it appears to at least be a valid hostname, e.g. localhost + return true if (name =~ /^([a-z0-9][a-z0-9\-]{0,61})?[a-z0-9]$/i) && (name =~ /\s/).nil? + + false + end end end end