Skip to content

Commit

Permalink
Land #10940, add default service mapping to imports
Browse files Browse the repository at this point in the history
  • Loading branch information
busterb authored and jmartin-tech committed Dec 8, 2018
1 parent 2cd0b56 commit fe53537
Show file tree
Hide file tree
Showing 3 changed files with 137 additions and 3 deletions.
64 changes: 62 additions & 2 deletions lib/msf/core/db_manager/import.rb
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,69 @@ def import(args={}, &block)
data = args[:data] || args['data']
ftype = import_filetype_detect(data)
yield(:filetype, @import_filedata[:type]) if block
self.send "import_#{ftype}".to_sym, args, &block
self.send "import_#{ftype}".to_sym, args.merge(workspace: wspace.name), &block
# post process the import here for missing default port maps
mrefs, mports, _mservs = Msf::Modules::Metadata::Cache.instance.all_remote_exploit_maps
# the map build above is a little expensive, another option is to do
# a host by ref search for each vuln ref and then check port reported for each module
# IMHO this front loaded cost here is worth it with only a small number of modules
# compared to the vast number of possible references offered by a Vulnerability scanner.
deferred_service_ports = [ 139 ] # I hate special cases, however 139 is no longer a preferred default

new_host_ids = Mdm::Host.where(workspace: wspace).map(&:id)
(new_host_ids - existing_host_ids).each do |id|
imported_host = Mdm::Host.where(id: id).first
next if imported_host.vulns.nil? || imported_host.vulns.empty?
# get all vulns with ports
with_ports = []
imported_host.vulns.each do |vuln|
next if vuln.service.nil?
with_ports << vuln.name
end

imported_host.vulns.each do |vuln|
# now get default ports for vulns where service is nil
next unless vuln.service.nil?
next if with_ports.include?(vuln.name)
serv = nil

# Module names that match this vulnerability
matched = mrefs.values_at(*(vuln.refs.map { |x| x.name.upcase } & mrefs.keys)).map { |x| x.values }.flatten.uniq
next if matched.empty?
match_names = matched.map { |mod| mod.full_name }

second_pass_services = []

imported_host.services.each do |service|
if deferred_service_ports.include?(service.port)
second_pass_services << service
next
end
next unless mports[service.port]
if (match_names - mports[service.port].keys).count < match_names.count
serv = service
break
end
end

# post process any deferred services if no match has been found
if serv.nil? && !second_pass_services.empty?
second_pass_services.each do |service|
next unless mports[service.port]
if (match_names - mports[service.port].keys).count < match_names.count
serv = service
break
end
end
end

next if serv.nil?
vuln.service = serv
vuln.save

end
end
if preserve_hosts
new_host_ids = Mdm::Host.where(workspace: wspace).map(&:id)
(new_host_ids - existing_host_ids).each do |id|
Mdm::Host.where(id: id).first.normalize_os
end
Expand Down
7 changes: 6 additions & 1 deletion lib/msf/core/modules/metadata/cache.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
require 'msf/core/modules/metadata/obj'
require 'msf/core/modules/metadata/search'
require 'msf/core/modules/metadata/store'
require 'msf/core/modules/metadata/maps'

#
# Core service class that provides storage of module metadata as well as operations on the metadata.
Expand All @@ -19,6 +20,7 @@ class Cache
include Singleton
include Msf::Modules::Metadata::Search
include Msf::Modules::Metadata::Store
include Msf::Modules::Metadata::Maps

#
# Refreshes cached module metadata as well as updating the store
Expand Down Expand Up @@ -79,7 +81,10 @@ def refresh_metadata(module_sets)
end
end

update_store if has_changes
if has_changes
update_store
clear_maps
end
}
end

Expand Down
69 changes: 69 additions & 0 deletions lib/msf/core/modules/metadata/maps.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#
# Core service class that provides storage of module metadata as well as operations on the metadata.
# Note that operations on this metadata are included as separate modules.
#
module Msf::Modules::Metadata::Maps

@mrefs = {}
@mports = {}
@mservs = {}


def all_remote_exploit_maps

return @mrefs, @mports, @mservs if @mrefs && !@mrefs.empty?

mrefs = {}
mports = {}
mservs = {}

get_metadata.each do |exploit|
next unless exploit.type == "exploit" && exploit.is_server
fullname = exploit.full_name
exploit.references.each do |reference|
next if reference =~ /^URL/
ref = reference
ref.upcase!

mrefs[ref] ||= {}
mrefs[ref][fullname] = exploit
end

if exploit.rport
rport = exploit.rport
mports[rport.to_i] ||= {}
mports[rport.to_i][fullname] = exploit
end

unless exploit.autofilter_ports.nil? || exploit.autofilter_ports.empty?
exploit.autofilter_ports.each do |rport|
next unless port_allowed?(rport)
mports[rport.to_i] ||= {}
mports[rport.to_i][fullname] = exploit
end
end

unless exploit.autofilter_services.nil? || exploit.autofilter_services.empty?
exploit.autofilter_services.each do |serv|
mservs[serv] ||= {}
mservs[serv][fullname] = exploit
end
end

end
@mrefs = mrefs
@mports = mports
@mservs = mservs

return @mrefs, @mports, @mservs
end

private

def clear_maps
@mrefs = nil
@mports = nil
@mservs = nil
end

end

0 comments on commit fe53537

Please sign in to comment.