Merge branch 'master' of https://github.com/rapid7/metasploit-framework
commit
358c43f6f6
8
Gemfile
8
Gemfile
|
@ -27,11 +27,19 @@ group :development do
|
|||
end
|
||||
|
||||
group :development, :test do
|
||||
# supplies factories for producing model instance for specs
|
||||
# Version 4.1.0 or newer is needed to support generate calls without the
|
||||
# 'FactoryGirl.' in factory definitions syntax.
|
||||
gem 'factory_girl', '>= 4.1.0'
|
||||
# running documentation generation tasks and rspec tasks
|
||||
gem 'rake'
|
||||
end
|
||||
|
||||
group :test do
|
||||
# Removes records from database created during tests. Can't use rspec-rails'
|
||||
# transactional fixtures because multiple connections are in use so
|
||||
# transactions won't work.
|
||||
gem 'database_cleaner'
|
||||
# testing framework
|
||||
gem 'rspec', '>= 2.12'
|
||||
# code coverage for tests
|
||||
|
|
|
@ -26,7 +26,10 @@ GEM
|
|||
arel (3.0.2)
|
||||
builder (3.0.4)
|
||||
coderay (1.0.9)
|
||||
database_cleaner (0.9.1)
|
||||
diff-lcs (1.1.3)
|
||||
factory_girl (4.2.0)
|
||||
activesupport (>= 3.0.0)
|
||||
i18n (0.6.1)
|
||||
json (1.7.7)
|
||||
method_source (0.8.1)
|
||||
|
@ -64,6 +67,8 @@ PLATFORMS
|
|||
DEPENDENCIES
|
||||
activerecord
|
||||
activesupport (>= 3.0.0)
|
||||
database_cleaner
|
||||
factory_girl (>= 4.1.0)
|
||||
json
|
||||
metasploit_data_models!
|
||||
msgpack
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
require 'metasploit/framework'
|
||||
|
||||
module Metasploit
|
||||
module Framework
|
||||
module Database
|
||||
def self.configurations
|
||||
YAML.load_file(configurations_pathname)
|
||||
end
|
||||
|
||||
def self.configurations_pathname
|
||||
Metasploit::Framework.root.join('config', 'database.yml')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,5 +1,4 @@
|
|||
# -*- coding: binary -*-
|
||||
###
|
||||
#
|
||||
# framework-base
|
||||
# --------------
|
||||
|
@ -13,8 +12,6 @@
|
|||
# Beyond providing the default sessions, framework-base also provides
|
||||
# a wrapper interface to framework-core that makes some of the tasks,
|
||||
# such as exploitation, into easier to manage functions.
|
||||
#
|
||||
###
|
||||
|
||||
# framework-base depends on framework-core
|
||||
require 'msf/core'
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
# -*- coding: binary -*-
|
||||
##
|
||||
# $Id$
|
||||
##
|
||||
|
||||
require 'msf/base'
|
||||
require 'msf/base/sessions/scriptable'
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
# -*- coding: binary -*-
|
||||
##
|
||||
# $Id$
|
||||
##
|
||||
|
||||
require 'msf/base/sessions/meterpreter'
|
||||
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
# -*- coding: binary -*-
|
||||
##
|
||||
# $Id$
|
||||
##
|
||||
|
||||
require 'shellwords'
|
||||
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
# -*- coding: binary -*-
|
||||
##
|
||||
# $Id$
|
||||
##
|
||||
|
||||
require 'msf/base/sessions/meterpreter'
|
||||
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
# -*- coding: binary -*-
|
||||
##
|
||||
# $Id: meterpreter_options.rb 10595 2010-10-08 04:11:47Z hdm $
|
||||
##
|
||||
|
||||
require 'msf/base/sessions/meterpreter'
|
||||
require 'msf/windows_error'
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
# -*- coding: binary -*-
|
||||
##
|
||||
# $Id$
|
||||
##
|
||||
|
||||
require 'msf/base/sessions/meterpreter'
|
||||
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
# -*- coding: binary -*-
|
||||
##
|
||||
# $Id$
|
||||
##
|
||||
|
||||
require 'msf/base/sessions/meterpreter'
|
||||
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
# -*- coding: binary -*-
|
||||
##
|
||||
# $Id$
|
||||
##
|
||||
|
||||
require 'msf/base/sessions/meterpreter'
|
||||
require 'msf/windows_error'
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
# -*- coding: binary -*-
|
||||
##
|
||||
# $Id$
|
||||
##
|
||||
|
||||
require 'msf/base'
|
||||
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
# -*- coding: binary -*-
|
||||
##
|
||||
# $Id$
|
||||
##
|
||||
|
||||
require 'msf/base'
|
||||
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
# -*- coding: binary -*-
|
||||
##
|
||||
# $Id$
|
||||
##
|
||||
|
||||
require 'msf/base'
|
||||
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
# -*- coding: binary -*-
|
||||
##
|
||||
# $Id$
|
||||
##
|
||||
|
||||
require 'msf/base/sessions/command_shell_options'
|
||||
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# Framework web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/framework/
|
||||
##
|
||||
|
||||
require 'net/https'
|
||||
require 'net/http'
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# Framework web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/framework/
|
||||
##
|
||||
|
||||
require 'net/https'
|
||||
require 'net/http'
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# Framework web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/framework/
|
||||
##
|
||||
|
||||
require 'net/https'
|
||||
require 'net/http'
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# Framework web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/framework/
|
||||
##
|
||||
|
||||
require 'net/https'
|
||||
require 'net/http'
|
||||
|
|
|
@ -1,35 +1,61 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
#
|
||||
# Standard Library
|
||||
#
|
||||
|
||||
require 'csv'
|
||||
require 'tmpdir'
|
||||
require 'uri'
|
||||
require 'zip'
|
||||
|
||||
#
|
||||
#
|
||||
# Included Libraries
|
||||
#
|
||||
#
|
||||
|
||||
#
|
||||
# PacketFu
|
||||
#
|
||||
|
||||
require 'packetfu'
|
||||
|
||||
#
|
||||
# Rex
|
||||
#
|
||||
|
||||
|
||||
require 'rex/socket'
|
||||
|
||||
# Check Rex::Parser.nokogiri_loaded for status of the Nokogiri parsers
|
||||
require 'rex/parser/nmap_nokogiri'
|
||||
require 'rex/parser/nexpose_simple_nokogiri'
|
||||
require 'rex/parser/nexpose_raw_nokogiri'
|
||||
require 'rex/parser/foundstone_nokogiri'
|
||||
require 'rex/parser/mbsa_nokogiri'
|
||||
require 'rex/parser/acunetix_nokogiri'
|
||||
require 'rex/parser/appscan_nokogiri'
|
||||
require 'rex/parser/burp_session_nokogiri'
|
||||
require 'rex/parser/ci_nokogiri'
|
||||
require 'rex/parser/wapiti_nokogiri'
|
||||
require 'rex/parser/openvas_nokogiri'
|
||||
require 'rex/parser/foundstone_nokogiri'
|
||||
require 'rex/parser/fusionvm_nokogiri'
|
||||
require 'rex/parser/mbsa_nokogiri'
|
||||
require 'rex/parser/nexpose_raw_nokogiri'
|
||||
require 'rex/parser/nexpose_simple_nokogiri'
|
||||
require 'rex/parser/nmap_nokogiri'
|
||||
require 'rex/parser/openvas_nokogiri'
|
||||
require 'rex/parser/wapiti_nokogiri'
|
||||
|
||||
# Legacy XML parsers -- these will be converted some day
|
||||
|
||||
require 'rex/parser/nmap_xml'
|
||||
require 'rex/parser/nexpose_xml'
|
||||
require 'rex/parser/retina_xml'
|
||||
require 'rex/parser/netsparker_xml'
|
||||
require 'rex/parser/nessus_xml'
|
||||
require 'rex/parser/ip360_xml'
|
||||
require 'rex/parser/ip360_aspl_xml'
|
||||
require 'rex/parser/ip360_xml'
|
||||
require 'rex/parser/nessus_xml'
|
||||
require 'rex/parser/netsparker_xml'
|
||||
require 'rex/parser/nexpose_xml'
|
||||
require 'rex/parser/nmap_xml'
|
||||
require 'rex/parser/retina_xml'
|
||||
|
||||
require 'rex/socket'
|
||||
require 'zip'
|
||||
require 'packetfu'
|
||||
require 'uri'
|
||||
require 'tmpdir'
|
||||
require 'csv'
|
||||
#
|
||||
# Project
|
||||
#
|
||||
|
||||
require 'msf/core/db_manager/import_msf_xml'
|
||||
|
||||
module Msf
|
||||
|
||||
|
@ -129,6 +155,7 @@ end
|
|||
#
|
||||
###
|
||||
class DBManager
|
||||
include Msf::DBManager::ImportMsfXml
|
||||
|
||||
def rfc3330_reserved(ip)
|
||||
case ip.class.to_s
|
||||
|
@ -3669,334 +3696,6 @@ class DBManager
|
|||
|
||||
end
|
||||
|
||||
# For each host, step through services, notes, and vulns, and import
|
||||
# them.
|
||||
# TODO: loot, tasks, and reports
|
||||
def import_msf_xml(args={}, &block)
|
||||
data = args[:data]
|
||||
wspace = args[:wspace] || workspace
|
||||
bl = validate_ips(args[:blacklist]) ? args[:blacklist].split : []
|
||||
|
||||
allow_yaml = false
|
||||
btag = nil
|
||||
|
||||
doc = rexmlify(data)
|
||||
if doc.elements["MetasploitExpressV1"]
|
||||
m_ver = 1
|
||||
allow_yaml = true
|
||||
btag = "MetasploitExpressV1"
|
||||
elsif doc.elements["MetasploitExpressV2"]
|
||||
m_ver = 2
|
||||
allow_yaml = true
|
||||
btag = "MetasploitExpressV2"
|
||||
elsif doc.elements["MetasploitExpressV3"]
|
||||
m_ver = 3
|
||||
btag = "MetasploitExpressV3"
|
||||
elsif doc.elements["MetasploitExpressV4"]
|
||||
m_ver = 4
|
||||
btag = "MetasploitExpressV4"
|
||||
elsif doc.elements["MetasploitV4"]
|
||||
m_ver = 4
|
||||
btag = "MetasploitV4"
|
||||
else
|
||||
m_ver = nil
|
||||
end
|
||||
unless m_ver and btag
|
||||
raise DBImportError.new("Unsupported Metasploit XML document format")
|
||||
end
|
||||
|
||||
doc.elements.each("/#{btag}/hosts/host") do |host|
|
||||
host_data = {}
|
||||
host_data[:workspace] = wspace
|
||||
host_data[:host] = nils_for_nulls(host.elements["address"].text.to_s.strip)
|
||||
if bl.include? host_data[:host]
|
||||
next
|
||||
else
|
||||
yield(:address,host_data[:host]) if block
|
||||
end
|
||||
host_data[:mac] = nils_for_nulls(host.elements["mac"].text.to_s.strip)
|
||||
if host.elements["comm"].text
|
||||
host_data[:comm] = nils_for_nulls(host.elements["comm"].text.to_s.strip)
|
||||
end
|
||||
%W{created-at updated-at name state os-flavor os-lang os-name os-sp purpose}.each { |datum|
|
||||
if host.elements[datum].text
|
||||
host_data[datum.gsub('-','_')] = nils_for_nulls(host.elements[datum].text.to_s.strip)
|
||||
end
|
||||
}
|
||||
host_address = host_data[:host].dup # Preserve after report_host() deletes
|
||||
hobj = report_host(host_data)
|
||||
|
||||
host.elements.each("host_details/host_detail") do |hdet|
|
||||
hdet_data = {}
|
||||
hdet.elements.each do |det|
|
||||
next if ["id", "host-id"].include?(det.name)
|
||||
if det.text
|
||||
hdet_data[det.name.gsub('-','_')] = nils_for_nulls(det.text.to_s.strip)
|
||||
end
|
||||
end
|
||||
report_host_details(hobj, hdet_data)
|
||||
end
|
||||
|
||||
host.elements.each("exploit_attempts/exploit_attempt") do |hdet|
|
||||
hdet_data = {}
|
||||
hdet.elements.each do |det|
|
||||
next if ["id", "host-id", "session-id", "vuln-id", "service-id", "loot-id"].include?(det.name)
|
||||
if det.text
|
||||
hdet_data[det.name.gsub('-','_')] = nils_for_nulls(det.text.to_s.strip)
|
||||
end
|
||||
end
|
||||
report_exploit_attempt(hobj, hdet_data)
|
||||
end
|
||||
|
||||
host.elements.each('services/service') do |service|
|
||||
service_data = {}
|
||||
service_data[:workspace] = wspace
|
||||
service_data[:host] = hobj
|
||||
service_data[:port] = nils_for_nulls(service.elements["port"].text.to_s.strip).to_i
|
||||
service_data[:proto] = nils_for_nulls(service.elements["proto"].text.to_s.strip)
|
||||
%W{created-at updated-at name state info}.each { |datum|
|
||||
if service.elements[datum].text
|
||||
if datum == "info"
|
||||
service_data["info"] = nils_for_nulls(unserialize_object(service.elements[datum], false))
|
||||
else
|
||||
service_data[datum.gsub("-","_")] = nils_for_nulls(service.elements[datum].text.to_s.strip)
|
||||
end
|
||||
end
|
||||
}
|
||||
report_service(service_data)
|
||||
end
|
||||
|
||||
host.elements.each('notes/note') do |note|
|
||||
note_data = {}
|
||||
note_data[:workspace] = wspace
|
||||
note_data[:host] = hobj
|
||||
note_data[:type] = nils_for_nulls(note.elements["ntype"].text.to_s.strip)
|
||||
note_data[:data] = nils_for_nulls(unserialize_object(note.elements["data"], allow_yaml))
|
||||
|
||||
if note.elements["critical"].text
|
||||
note_data[:critical] = true unless note.elements["critical"].text.to_s.strip == "NULL"
|
||||
end
|
||||
if note.elements["seen"].text
|
||||
note_data[:seen] = true unless note.elements["critical"].text.to_s.strip == "NULL"
|
||||
end
|
||||
%W{created-at updated-at}.each { |datum|
|
||||
if note.elements[datum].text
|
||||
note_data[datum.gsub("-","_")] = nils_for_nulls(note.elements[datum].text.to_s.strip)
|
||||
end
|
||||
}
|
||||
report_note(note_data)
|
||||
end
|
||||
|
||||
host.elements.each('tags/tag') do |tag|
|
||||
tag_data = {}
|
||||
tag_data[:addr] = host_address
|
||||
tag_data[:wspace] = wspace
|
||||
tag_data[:name] = tag.elements["name"].text.to_s.strip
|
||||
tag_data[:desc] = tag.elements["desc"].text.to_s.strip
|
||||
if tag.elements["report-summary"].text
|
||||
tag_data[:summary] = tag.elements["report-summary"].text.to_s.strip
|
||||
end
|
||||
if tag.elements["report-detail"].text
|
||||
tag_data[:detail] = tag.elements["report-detail"].text.to_s.strip
|
||||
end
|
||||
if tag.elements["critical"].text
|
||||
tag_data[:crit] = true unless tag.elements["critical"].text.to_s.strip == "NULL"
|
||||
end
|
||||
report_host_tag(tag_data)
|
||||
end
|
||||
|
||||
host.elements.each('vulns/vuln') do |vuln|
|
||||
vuln_data = {}
|
||||
vuln_data[:workspace] = wspace
|
||||
vuln_data[:host] = hobj
|
||||
vuln_data[:info] = nils_for_nulls(unserialize_object(vuln.elements["info"], allow_yaml))
|
||||
vuln_data[:name] = nils_for_nulls(vuln.elements["name"].text.to_s.strip)
|
||||
%W{created-at updated-at exploited-at}.each { |datum|
|
||||
if vuln.elements[datum] and vuln.elements[datum].text
|
||||
vuln_data[datum.gsub("-","_")] = nils_for_nulls(vuln.elements[datum].text.to_s.strip)
|
||||
end
|
||||
}
|
||||
if vuln.elements["refs"]
|
||||
vuln_data[:refs] = []
|
||||
vuln.elements.each("refs/ref") do |ref|
|
||||
vuln_data[:refs] << nils_for_nulls(ref.text.to_s.strip)
|
||||
end
|
||||
end
|
||||
|
||||
vobj = report_vuln(vuln_data)
|
||||
|
||||
vuln.elements.each("vuln_details/vuln_detail") do |vdet|
|
||||
vdet_data = {}
|
||||
vdet.elements.each do |det|
|
||||
next if ["id", "vuln-id"].include?(det.name)
|
||||
if det.text
|
||||
vdet_data[det.name.gsub('-','_')] = nils_for_nulls(det.text.to_s.strip)
|
||||
end
|
||||
end
|
||||
report_vuln_details(vobj, vdet_data)
|
||||
end
|
||||
|
||||
vuln.elements.each("vuln_attempts/vuln_attempt") do |vdet|
|
||||
vdet_data = {}
|
||||
vdet.elements.each do |det|
|
||||
next if ["id", "vuln-id", "loot-id", "session-id"].include?(det.name)
|
||||
if det.text
|
||||
vdet_data[det.name.gsub('-','_')] = nils_for_nulls(det.text.to_s.strip)
|
||||
end
|
||||
end
|
||||
report_vuln_attempt(vobj, vdet_data)
|
||||
end
|
||||
end
|
||||
|
||||
host.elements.each('creds/cred') do |cred|
|
||||
cred_data = {}
|
||||
cred_data[:workspace] = wspace
|
||||
cred_data[:host] = hobj
|
||||
%W{port ptype sname proto proof active user pass}.each {|datum|
|
||||
if cred.elements[datum].respond_to? :text
|
||||
cred_data[datum.intern] = nils_for_nulls(cred.elements[datum].text.to_s.strip)
|
||||
end
|
||||
}
|
||||
%W{created-at updated-at}.each { |datum|
|
||||
if cred.elements[datum].respond_to? :text
|
||||
cred_data[datum.gsub("-","_")] = nils_for_nulls(cred.elements[datum].text.to_s.strip)
|
||||
end
|
||||
}
|
||||
%W{source-type source-id}.each { |datum|
|
||||
if cred.elements[datum].respond_to? :text
|
||||
cred_data[datum.gsub("-","_").intern] = nils_for_nulls(cred.elements[datum].text.to_s.strip)
|
||||
end
|
||||
}
|
||||
if cred_data[:pass] == "<masked>"
|
||||
cred_data[:pass] = ""
|
||||
cred_data[:active] = false
|
||||
elsif cred_data[:pass] == "*BLANK PASSWORD*"
|
||||
cred_data[:pass] = ""
|
||||
end
|
||||
report_cred(cred_data)
|
||||
end
|
||||
|
||||
host.elements.each('sessions/session') do |sess|
|
||||
sess_id = nils_for_nulls(sess.elements["id"].text.to_s.strip.to_i)
|
||||
sess_data = {}
|
||||
sess_data[:host] = hobj
|
||||
%W{desc platform port stype}.each {|datum|
|
||||
if sess.elements[datum].respond_to? :text
|
||||
sess_data[datum.intern] = nils_for_nulls(sess.elements[datum].text.to_s.strip)
|
||||
end
|
||||
}
|
||||
%W{opened-at close-reason closed-at via-exploit via-payload}.each {|datum|
|
||||
if sess.elements[datum].respond_to? :text
|
||||
sess_data[datum.gsub("-","_").intern] = nils_for_nulls(sess.elements[datum].text.to_s.strip)
|
||||
end
|
||||
}
|
||||
sess_data[:datastore] = nils_for_nulls(unserialize_object(sess.elements["datastore"], allow_yaml))
|
||||
if sess.elements["routes"]
|
||||
sess_data[:routes] = nils_for_nulls(unserialize_object(sess.elements["routes"], allow_yaml)) || []
|
||||
end
|
||||
if not sess_data[:closed_at] # Fake a close if we don't already have one
|
||||
sess_data[:closed_at] = Time.now.utc
|
||||
sess_data[:close_reason] = "Imported at #{Time.now.utc}"
|
||||
end
|
||||
|
||||
existing_session = get_session(
|
||||
:workspace => sess_data[:host].workspace,
|
||||
:addr => sess_data[:host].address,
|
||||
:time => sess_data[:opened_at]
|
||||
)
|
||||
this_session = existing_session || report_session(sess_data)
|
||||
next if existing_session
|
||||
sess.elements.each('events/event') do |sess_event|
|
||||
sess_event_data = {}
|
||||
sess_event_data[:session] = this_session
|
||||
%W{created-at etype local-path remote-path}.each {|datum|
|
||||
if sess_event.elements[datum].respond_to? :text
|
||||
sess_event_data[datum.gsub("-","_").intern] = nils_for_nulls(sess_event.elements[datum].text.to_s.strip)
|
||||
end
|
||||
}
|
||||
%W{command output}.each {|datum|
|
||||
if sess_event.elements[datum].respond_to? :text
|
||||
sess_event_data[datum.gsub("-","_").intern] = nils_for_nulls(unserialize_object(sess_event.elements[datum], allow_yaml))
|
||||
end
|
||||
}
|
||||
report_session_event(sess_event_data)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Import web sites
|
||||
doc.elements.each("/#{btag}/web_sites/web_site") do |web|
|
||||
info = {}
|
||||
info[:workspace] = wspace
|
||||
|
||||
%W{host port vhost ssl comments}.each do |datum|
|
||||
if web.elements[datum].respond_to? :text
|
||||
info[datum.intern] = nils_for_nulls(web.elements[datum].text.to_s.strip)
|
||||
end
|
||||
end
|
||||
|
||||
info[:options] = nils_for_nulls(unserialize_object(web.elements["options"], allow_yaml)) if web.elements["options"].respond_to?(:text)
|
||||
info[:ssl] = (info[:ssl] and info[:ssl].to_s.strip.downcase == "true") ? true : false
|
||||
|
||||
%W{created-at updated-at}.each { |datum|
|
||||
if web.elements[datum].text
|
||||
info[datum.gsub("-","_")] = nils_for_nulls(web.elements[datum].text.to_s.strip)
|
||||
end
|
||||
}
|
||||
|
||||
report_web_site(info)
|
||||
yield(:web_site, "#{info[:host]}:#{info[:port]} (#{info[:vhost]})") if block
|
||||
end
|
||||
|
||||
%W{page form vuln}.each do |wtype|
|
||||
doc.elements.each("/#{btag}/web_#{wtype}s/web_#{wtype}") do |web|
|
||||
info = {}
|
||||
info[:workspace] = wspace
|
||||
info[:host] = nils_for_nulls(web.elements["host"].text.to_s.strip) if web.elements["host"].respond_to?(:text)
|
||||
info[:port] = nils_for_nulls(web.elements["port"].text.to_s.strip) if web.elements["port"].respond_to?(:text)
|
||||
info[:ssl] = nils_for_nulls(web.elements["ssl"].text.to_s.strip) if web.elements["ssl"].respond_to?(:text)
|
||||
info[:vhost] = nils_for_nulls(web.elements["vhost"].text.to_s.strip) if web.elements["vhost"].respond_to?(:text)
|
||||
|
||||
info[:ssl] = (info[:ssl] and info[:ssl].to_s.strip.downcase == "true") ? true : false
|
||||
|
||||
case wtype
|
||||
when "page"
|
||||
%W{path code body query cookie auth ctype mtime location}.each do |datum|
|
||||
if web.elements[datum].respond_to? :text
|
||||
info[datum.intern] = nils_for_nulls(web.elements[datum].text.to_s.strip)
|
||||
end
|
||||
end
|
||||
info[:headers] = nils_for_nulls(unserialize_object(web.elements["headers"], allow_yaml))
|
||||
when "form"
|
||||
%W{path query method}.each do |datum|
|
||||
if web.elements[datum].respond_to? :text
|
||||
info[datum.intern] = nils_for_nulls(web.elements[datum].text.to_s.strip)
|
||||
end
|
||||
end
|
||||
info[:params] = nils_for_nulls(unserialize_object(web.elements["params"], allow_yaml))
|
||||
when "vuln"
|
||||
%W{path query method pname proof risk name blame description category confidence}.each do |datum|
|
||||
if web.elements[datum].respond_to? :text
|
||||
info[datum.intern] = nils_for_nulls(web.elements[datum].text.to_s.strip)
|
||||
end
|
||||
end
|
||||
info[:params] = nils_for_nulls(unserialize_object(web.elements["params"], allow_yaml))
|
||||
info[:risk] = info[:risk].to_i
|
||||
info[:confidence] = info[:confidence].to_i
|
||||
end
|
||||
|
||||
%W{created-at updated-at}.each { |datum|
|
||||
if web.elements[datum].text
|
||||
info[datum.gsub("-","_")] = nils_for_nulls(web.elements[datum].text.to_s.strip)
|
||||
end
|
||||
}
|
||||
self.send("report_web_#{wtype}", info)
|
||||
|
||||
yield("web_#{wtype}".intern, info[:path]) if block
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Convert the string "NULL" to actual nil
|
||||
def nils_for_nulls(str)
|
||||
str == "NULL" ? nil : str
|
||||
|
|
|
@ -0,0 +1,580 @@
|
|||
module Msf
|
||||
class DBManager
|
||||
# Handles importing of the xml format exported by Pro. The methods are in a
|
||||
# module because (1) it's just good code layout and (2) it allows the
|
||||
# methods to be overridden in Pro without using alias_method_chain as
|
||||
# methods defined in a class cannot be overridden by including a module
|
||||
# (unless you're running Ruby 2.0 and can use prepend)
|
||||
module ImportMsfXml
|
||||
#
|
||||
# CONSTANTS
|
||||
#
|
||||
|
||||
# Elements that can be treated as text (i.e. do not need to be
|
||||
# deserialized) in {#import_msf_web_page_element}
|
||||
MSF_WEB_PAGE_TEXT_ELEMENT_NAMES = [
|
||||
'auth',
|
||||
'body',
|
||||
'code',
|
||||
'cookie',
|
||||
'ctype',
|
||||
'location',
|
||||
'mtime'
|
||||
]
|
||||
|
||||
# Elements that can be treated as text (i.e. do not need to be
|
||||
# deserialized) in {#import_msf_web_element}.
|
||||
MSF_WEB_TEXT_ELEMENT_NAMES = [
|
||||
'created-at',
|
||||
'host',
|
||||
'path',
|
||||
'port',
|
||||
'query',
|
||||
'ssl',
|
||||
'updated-at',
|
||||
'vhost'
|
||||
]
|
||||
|
||||
# Elements that can be treated as text (i.e. do not need to be
|
||||
# deserialized) in {#import_msf_web_vuln_element}.
|
||||
MSF_WEB_VULN_TEXT_ELEMENT_NAMES = [
|
||||
'blame',
|
||||
'category',
|
||||
'confidence',
|
||||
'description',
|
||||
'method',
|
||||
'name',
|
||||
'pname',
|
||||
'proof',
|
||||
'risk'
|
||||
]
|
||||
|
||||
#
|
||||
# Instance Methods
|
||||
#
|
||||
|
||||
# Imports web_form element using {Msf::DBManager#report_web_form}.
|
||||
#
|
||||
# @param element [REXML::Element] web_form element.
|
||||
# @param options [Hash{Symbol => Object}] options
|
||||
# @option options [Boolean] :allow_yaml (false) Whether to allow YAML when
|
||||
# deserializing params.
|
||||
# @option options [Mdm::Workspace, nil] :workspace
|
||||
# (Msf::DBManager#workspace) workspace under which to report the
|
||||
# Mdm::WebForm
|
||||
# @yield [event, data]
|
||||
# @yieldparam event [:web_page] The event name
|
||||
# @yieldparam data [String] path
|
||||
# @yieldreturn [void]
|
||||
# @return [void]
|
||||
def import_msf_web_form_element(element, options={}, ¬ifier)
|
||||
options.assert_valid_keys(:allow_yaml, :workspace)
|
||||
|
||||
import_msf_web_element(element,
|
||||
:allow_yaml => options[:allow_yaml],
|
||||
:notifier => notifier,
|
||||
:type => :form,
|
||||
:workspace => options[:workspace]) do |element, options|
|
||||
info = import_msf_text_element(element, 'method')
|
||||
|
||||
# FIXME https://www.pivotaltracker.com/story/show/46578647
|
||||
# FIXME https://www.pivotaltracker.com/story/show/47128407
|
||||
unserialized_params = unserialize_object(
|
||||
element.elements['params'],
|
||||
options[:allow_yaml]
|
||||
)
|
||||
info[:params] = nils_for_nulls(unserialized_params)
|
||||
|
||||
info
|
||||
end
|
||||
end
|
||||
|
||||
# Imports web_page element using {Msf::DBManager#report_web_page}.
|
||||
#
|
||||
# @param element [REXML::Element] web_page element.
|
||||
# @param options [Hash{Symbol => Object}] options
|
||||
# @option options [Boolean] :allow_yaml (false) Whether to allow YAML when
|
||||
# deserializing headers.
|
||||
# @option options [Mdm::Workspace, nil] :workspace
|
||||
# (Msf::DBManager#workspace) workspace under which to report the
|
||||
# Mdm::WebPage.
|
||||
# @yield [event, data]
|
||||
# @yieldparam event [:web_page] The event name
|
||||
# @yieldparam data [String] path
|
||||
# @yieldreturn [void]
|
||||
# @return [void]
|
||||
def import_msf_web_page_element(element, options={}, ¬ifier)
|
||||
options.assert_valid_keys(:allow_yaml, :workspace)
|
||||
|
||||
import_msf_web_element(element,
|
||||
:allow_yaml => options[:allow_yaml],
|
||||
:notifier => notifier,
|
||||
:type => :page,
|
||||
:workspace => options[:workspace]) do |element, options|
|
||||
info = {}
|
||||
|
||||
MSF_WEB_PAGE_TEXT_ELEMENT_NAMES.each do |name|
|
||||
element_info = import_msf_text_element(element, name)
|
||||
info.merge!(element_info)
|
||||
end
|
||||
|
||||
code = info[:code]
|
||||
|
||||
if code
|
||||
info[:code] = code.to_i
|
||||
end
|
||||
|
||||
# FIXME https://www.pivotaltracker.com/story/show/46578647
|
||||
# FIXME https://www.pivotaltracker.com/story/show/47128407
|
||||
unserialized_headers = unserialize_object(
|
||||
element.elements['headers'],
|
||||
options[:allow_yaml]
|
||||
)
|
||||
info[:headers] = nils_for_nulls(unserialized_headers)
|
||||
|
||||
info
|
||||
end
|
||||
end
|
||||
|
||||
# Imports web_vuln element using {Msf::DBManager#report_web_vuln}.
|
||||
#
|
||||
# @param element [REXML::Element] web_vuln element.
|
||||
# @param options [Hash{Symbol => Object}] options
|
||||
# @option options [Boolean] :allow_yaml (false) Whether to allow YAML when
|
||||
# deserializing headers.
|
||||
# @option options [Mdm::Workspace, nil] :workspace
|
||||
# (Msf::DBManager#workspace) workspace under which to report the
|
||||
# Mdm::WebPage.
|
||||
# @yield [event, data]
|
||||
# @yieldparam event [:web_page] The event name
|
||||
# @yieldparam data [String] path
|
||||
# @yieldreturn [void]
|
||||
# @return [void]
|
||||
def import_msf_web_vuln_element(element, options={}, ¬ifier)
|
||||
options.assert_valid_keys(:allow_yaml, :workspace)
|
||||
|
||||
import_msf_web_element(element,
|
||||
:allow_yaml => options[:allow_yaml],
|
||||
:notifier => notifier,
|
||||
:workspace => options[:workspace],
|
||||
:type => :vuln) do |element, options|
|
||||
info = {}
|
||||
|
||||
MSF_WEB_VULN_TEXT_ELEMENT_NAMES.each do |name|
|
||||
element_info = import_msf_text_element(element, name)
|
||||
info.merge!(element_info)
|
||||
end
|
||||
|
||||
confidence = info[:confidence]
|
||||
|
||||
if confidence
|
||||
info[:confidence] = confidence.to_i
|
||||
end
|
||||
|
||||
# FIXME https://www.pivotaltracker.com/story/show/46578647
|
||||
# FIXME https://www.pivotaltracker.com/story/show/47128407
|
||||
unserialized_params = unserialize_object(
|
||||
element.elements['params'],
|
||||
options[:allow_yaml]
|
||||
)
|
||||
info[:params] = nils_for_nulls(unserialized_params)
|
||||
|
||||
risk = info[:risk]
|
||||
|
||||
if risk
|
||||
info[:risk] = risk.to_i
|
||||
end
|
||||
|
||||
info
|
||||
end
|
||||
end
|
||||
|
||||
# For each host, step through services, notes, and vulns, and import
|
||||
# them.
|
||||
# TODO: loot, tasks, and reports
|
||||
def import_msf_xml(args={}, &block)
|
||||
data = args[:data]
|
||||
wspace = args[:wspace] || workspace
|
||||
bl = validate_ips(args[:blacklist]) ? args[:blacklist].split : []
|
||||
|
||||
doc = rexmlify(data)
|
||||
metadata = check_msf_xml_version!(doc)
|
||||
allow_yaml = metadata[:allow_yaml]
|
||||
btag = metadata[:root_tag]
|
||||
|
||||
doc.elements.each("/#{btag}/hosts/host") do |host|
|
||||
host_data = {}
|
||||
host_data[:workspace] = wspace
|
||||
host_data[:host] = nils_for_nulls(host.elements["address"].text.to_s.strip)
|
||||
if bl.include? host_data[:host]
|
||||
next
|
||||
else
|
||||
yield(:address,host_data[:host]) if block
|
||||
end
|
||||
host_data[:mac] = nils_for_nulls(host.elements["mac"].text.to_s.strip)
|
||||
if host.elements["comm"].text
|
||||
host_data[:comm] = nils_for_nulls(host.elements["comm"].text.to_s.strip)
|
||||
end
|
||||
%W{created-at updated-at name state os-flavor os-lang os-name os-sp purpose}.each { |datum|
|
||||
if host.elements[datum].text
|
||||
host_data[datum.gsub('-','_')] = nils_for_nulls(host.elements[datum].text.to_s.strip)
|
||||
end
|
||||
}
|
||||
host_address = host_data[:host].dup # Preserve after report_host() deletes
|
||||
hobj = report_host(host_data)
|
||||
|
||||
host.elements.each("host_details/host_detail") do |hdet|
|
||||
hdet_data = {}
|
||||
hdet.elements.each do |det|
|
||||
next if ["id", "host-id"].include?(det.name)
|
||||
if det.text
|
||||
hdet_data[det.name.gsub('-','_')] = nils_for_nulls(det.text.to_s.strip)
|
||||
end
|
||||
end
|
||||
report_host_details(hobj, hdet_data)
|
||||
end
|
||||
|
||||
host.elements.each("exploit_attempts/exploit_attempt") do |hdet|
|
||||
hdet_data = {}
|
||||
hdet.elements.each do |det|
|
||||
next if ["id", "host-id", "session-id", "vuln-id", "service-id", "loot-id"].include?(det.name)
|
||||
if det.text
|
||||
hdet_data[det.name.gsub('-','_')] = nils_for_nulls(det.text.to_s.strip)
|
||||
end
|
||||
end
|
||||
report_exploit_attempt(hobj, hdet_data)
|
||||
end
|
||||
|
||||
host.elements.each('services/service') do |service|
|
||||
service_data = {}
|
||||
service_data[:workspace] = wspace
|
||||
service_data[:host] = hobj
|
||||
service_data[:port] = nils_for_nulls(service.elements["port"].text.to_s.strip).to_i
|
||||
service_data[:proto] = nils_for_nulls(service.elements["proto"].text.to_s.strip)
|
||||
%W{created-at updated-at name state info}.each { |datum|
|
||||
if service.elements[datum].text
|
||||
if datum == "info"
|
||||
service_data["info"] = nils_for_nulls(unserialize_object(service.elements[datum], false))
|
||||
else
|
||||
service_data[datum.gsub("-","_")] = nils_for_nulls(service.elements[datum].text.to_s.strip)
|
||||
end
|
||||
end
|
||||
}
|
||||
report_service(service_data)
|
||||
end
|
||||
|
||||
host.elements.each('notes/note') do |note|
|
||||
note_data = {}
|
||||
note_data[:workspace] = wspace
|
||||
note_data[:host] = hobj
|
||||
note_data[:type] = nils_for_nulls(note.elements["ntype"].text.to_s.strip)
|
||||
note_data[:data] = nils_for_nulls(unserialize_object(note.elements["data"], allow_yaml))
|
||||
|
||||
if note.elements["critical"].text
|
||||
note_data[:critical] = true unless note.elements["critical"].text.to_s.strip == "NULL"
|
||||
end
|
||||
if note.elements["seen"].text
|
||||
note_data[:seen] = true unless note.elements["critical"].text.to_s.strip == "NULL"
|
||||
end
|
||||
%W{created-at updated-at}.each { |datum|
|
||||
if note.elements[datum].text
|
||||
note_data[datum.gsub("-","_")] = nils_for_nulls(note.elements[datum].text.to_s.strip)
|
||||
end
|
||||
}
|
||||
report_note(note_data)
|
||||
end
|
||||
|
||||
host.elements.each('tags/tag') do |tag|
|
||||
tag_data = {}
|
||||
tag_data[:addr] = host_address
|
||||
tag_data[:wspace] = wspace
|
||||
tag_data[:name] = tag.elements["name"].text.to_s.strip
|
||||
tag_data[:desc] = tag.elements["desc"].text.to_s.strip
|
||||
if tag.elements["report-summary"].text
|
||||
tag_data[:summary] = tag.elements["report-summary"].text.to_s.strip
|
||||
end
|
||||
if tag.elements["report-detail"].text
|
||||
tag_data[:detail] = tag.elements["report-detail"].text.to_s.strip
|
||||
end
|
||||
if tag.elements["critical"].text
|
||||
tag_data[:crit] = true unless tag.elements["critical"].text.to_s.strip == "NULL"
|
||||
end
|
||||
report_host_tag(tag_data)
|
||||
end
|
||||
|
||||
host.elements.each('vulns/vuln') do |vuln|
|
||||
vuln_data = {}
|
||||
vuln_data[:workspace] = wspace
|
||||
vuln_data[:host] = hobj
|
||||
vuln_data[:info] = nils_for_nulls(unserialize_object(vuln.elements["info"], allow_yaml))
|
||||
vuln_data[:name] = nils_for_nulls(vuln.elements["name"].text.to_s.strip)
|
||||
%W{created-at updated-at exploited-at}.each { |datum|
|
||||
if vuln.elements[datum] and vuln.elements[datum].text
|
||||
vuln_data[datum.gsub("-","_")] = nils_for_nulls(vuln.elements[datum].text.to_s.strip)
|
||||
end
|
||||
}
|
||||
if vuln.elements["refs"]
|
||||
vuln_data[:refs] = []
|
||||
vuln.elements.each("refs/ref") do |ref|
|
||||
vuln_data[:refs] << nils_for_nulls(ref.text.to_s.strip)
|
||||
end
|
||||
end
|
||||
|
||||
vobj = report_vuln(vuln_data)
|
||||
|
||||
vuln.elements.each("vuln_details/vuln_detail") do |vdet|
|
||||
vdet_data = {}
|
||||
vdet.elements.each do |det|
|
||||
next if ["id", "vuln-id"].include?(det.name)
|
||||
if det.text
|
||||
vdet_data[det.name.gsub('-','_')] = nils_for_nulls(det.text.to_s.strip)
|
||||
end
|
||||
end
|
||||
report_vuln_details(vobj, vdet_data)
|
||||
end
|
||||
|
||||
vuln.elements.each("vuln_attempts/vuln_attempt") do |vdet|
|
||||
vdet_data = {}
|
||||
vdet.elements.each do |det|
|
||||
next if ["id", "vuln-id", "loot-id", "session-id"].include?(det.name)
|
||||
if det.text
|
||||
vdet_data[det.name.gsub('-','_')] = nils_for_nulls(det.text.to_s.strip)
|
||||
end
|
||||
end
|
||||
report_vuln_attempt(vobj, vdet_data)
|
||||
end
|
||||
end
|
||||
|
||||
host.elements.each('creds/cred') do |cred|
|
||||
cred_data = {}
|
||||
cred_data[:workspace] = wspace
|
||||
cred_data[:host] = hobj
|
||||
%W{port ptype sname proto proof active user pass}.each {|datum|
|
||||
if cred.elements[datum].respond_to? :text
|
||||
cred_data[datum.intern] = nils_for_nulls(cred.elements[datum].text.to_s.strip)
|
||||
end
|
||||
}
|
||||
%W{created-at updated-at}.each { |datum|
|
||||
if cred.elements[datum].respond_to? :text
|
||||
cred_data[datum.gsub("-","_")] = nils_for_nulls(cred.elements[datum].text.to_s.strip)
|
||||
end
|
||||
}
|
||||
%W{source-type source-id}.each { |datum|
|
||||
if cred.elements[datum].respond_to? :text
|
||||
cred_data[datum.gsub("-","_").intern] = nils_for_nulls(cred.elements[datum].text.to_s.strip)
|
||||
end
|
||||
}
|
||||
if cred_data[:pass] == "<masked>"
|
||||
cred_data[:pass] = ""
|
||||
cred_data[:active] = false
|
||||
elsif cred_data[:pass] == "*BLANK PASSWORD*"
|
||||
cred_data[:pass] = ""
|
||||
end
|
||||
report_cred(cred_data)
|
||||
end
|
||||
|
||||
host.elements.each('sessions/session') do |sess|
|
||||
sess_id = nils_for_nulls(sess.elements["id"].text.to_s.strip.to_i)
|
||||
sess_data = {}
|
||||
sess_data[:host] = hobj
|
||||
%W{desc platform port stype}.each {|datum|
|
||||
if sess.elements[datum].respond_to? :text
|
||||
sess_data[datum.intern] = nils_for_nulls(sess.elements[datum].text.to_s.strip)
|
||||
end
|
||||
}
|
||||
%W{opened-at close-reason closed-at via-exploit via-payload}.each {|datum|
|
||||
if sess.elements[datum].respond_to? :text
|
||||
sess_data[datum.gsub("-","_").intern] = nils_for_nulls(sess.elements[datum].text.to_s.strip)
|
||||
end
|
||||
}
|
||||
sess_data[:datastore] = nils_for_nulls(unserialize_object(sess.elements["datastore"], allow_yaml))
|
||||
if sess.elements["routes"]
|
||||
sess_data[:routes] = nils_for_nulls(unserialize_object(sess.elements["routes"], allow_yaml)) || []
|
||||
end
|
||||
if not sess_data[:closed_at] # Fake a close if we don't already have one
|
||||
sess_data[:closed_at] = Time.now.utc
|
||||
sess_data[:close_reason] = "Imported at #{Time.now.utc}"
|
||||
end
|
||||
|
||||
existing_session = get_session(
|
||||
:workspace => sess_data[:host].workspace,
|
||||
:addr => sess_data[:host].address,
|
||||
:time => sess_data[:opened_at]
|
||||
)
|
||||
this_session = existing_session || report_session(sess_data)
|
||||
next if existing_session
|
||||
sess.elements.each('events/event') do |sess_event|
|
||||
sess_event_data = {}
|
||||
sess_event_data[:session] = this_session
|
||||
%W{created-at etype local-path remote-path}.each {|datum|
|
||||
if sess_event.elements[datum].respond_to? :text
|
||||
sess_event_data[datum.gsub("-","_").intern] = nils_for_nulls(sess_event.elements[datum].text.to_s.strip)
|
||||
end
|
||||
}
|
||||
%W{command output}.each {|datum|
|
||||
if sess_event.elements[datum].respond_to? :text
|
||||
sess_event_data[datum.gsub("-","_").intern] = nils_for_nulls(unserialize_object(sess_event.elements[datum], allow_yaml))
|
||||
end
|
||||
}
|
||||
report_session_event(sess_event_data)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Import web sites
|
||||
doc.elements.each("/#{btag}/web_sites/web_site") do |web|
|
||||
info = {}
|
||||
info[:workspace] = wspace
|
||||
|
||||
%W{host port vhost ssl comments}.each do |datum|
|
||||
if web.elements[datum].respond_to? :text
|
||||
info[datum.intern] = nils_for_nulls(web.elements[datum].text.to_s.strip)
|
||||
end
|
||||
end
|
||||
|
||||
info[:options] = nils_for_nulls(unserialize_object(web.elements["options"], allow_yaml)) if web.elements["options"].respond_to?(:text)
|
||||
info[:ssl] = (info[:ssl] and info[:ssl].to_s.strip.downcase == "true") ? true : false
|
||||
|
||||
%W{created-at updated-at}.each { |datum|
|
||||
if web.elements[datum].text
|
||||
info[datum.gsub("-","_")] = nils_for_nulls(web.elements[datum].text.to_s.strip)
|
||||
end
|
||||
}
|
||||
|
||||
report_web_site(info)
|
||||
yield(:web_site, "#{info[:host]}:#{info[:port]} (#{info[:vhost]})") if block
|
||||
end
|
||||
|
||||
%W{page form vuln}.each do |wtype|
|
||||
doc.elements.each("/#{btag}/web_#{wtype}s/web_#{wtype}") do |element|
|
||||
send(
|
||||
"import_msf_web_#{wtype}_element",
|
||||
element,
|
||||
:allow_yaml => allow_yaml,
|
||||
:workspace => wspace,
|
||||
&block
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Checks if the XML document has a format version that the importer
|
||||
# understands.
|
||||
#
|
||||
# @param document [REXML::Document] a REXML::Document produced by
|
||||
# {Msf::DBManager#rexmlify}.
|
||||
# @return [Hash{Symbol => Object}] `:allow_yaml` is true if the format
|
||||
# requires YAML loading when calling
|
||||
# {Msf::DBManager#unserialize_object}. `:root_tag` the tag name of the
|
||||
# root element for MSF XML.
|
||||
# @raise [Msf::DBImportError] if unsupported format
|
||||
def check_msf_xml_version!(document)
|
||||
metadata = {
|
||||
# FIXME https://www.pivotaltracker.com/story/show/47128407
|
||||
:allow_yaml => false,
|
||||
:root_tag => nil
|
||||
}
|
||||
|
||||
if document.elements['MetasploitExpressV1']
|
||||
# FIXME https://www.pivotaltracker.com/story/show/47128407
|
||||
metadata[:allow_yaml] = true
|
||||
metadata[:root_tag] = 'MetasploitExpressV1'
|
||||
elsif document.elements['MetasploitExpressV2']
|
||||
# FIXME https://www.pivotaltracker.com/story/show/47128407
|
||||
metadata[:allow_yaml] = true
|
||||
metadata[:root_tag] = 'MetasploitExpressV2'
|
||||
elsif document.elements['MetasploitExpressV3']
|
||||
metadata[:root_tag] = 'MetasploitExpressV3'
|
||||
elsif document.elements['MetasploitExpressV4']
|
||||
metadata[:root_tag] = 'MetasploitExpressV4'
|
||||
elsif document.elements['MetasploitV4']
|
||||
metadata[:root_tag] = 'MetasploitV4'
|
||||
end
|
||||
|
||||
unless metadata[:root_tag]
|
||||
raise Msf::DBImportError,
|
||||
'Unsupported Metasploit XML document format'
|
||||
end
|
||||
|
||||
metadata
|
||||
end
|
||||
|
||||
# Retrieves text of element if it exists.
|
||||
#
|
||||
# @param parent_element [REXML::Element] element under which element with
|
||||
# `child_name` exists.
|
||||
# @param child_name [String] the name of the element under
|
||||
# `parent_element` whose text should be returned
|
||||
# @return [{}] if element with child_name does not exist or does not have
|
||||
# text.
|
||||
# @return [Hash{Symbol => String}] Maps child_name symbol to text. Text is
|
||||
# stripped and any NULLs are converted to `nil`.
|
||||
# @return [nil] if element with `child_name` does not exist under
|
||||
# `parent_element`.
|
||||
def import_msf_text_element(parent_element, child_name)
|
||||
child_element = parent_element.elements[child_name]
|
||||
info = {}
|
||||
|
||||
if child_element
|
||||
stripped = child_element.text.to_s.strip
|
||||
attribute_name = child_name.underscore.to_sym
|
||||
info[attribute_name] = nils_for_nulls(stripped)
|
||||
end
|
||||
|
||||
info
|
||||
end
|
||||
|
||||
# Imports web_form, web_page, or web_vuln element using
|
||||
# {Msf::DBManager#report_web_form}, {Msf::DBManager#report_web_page}, and
|
||||
# {Msf::DBManager#report_web_vuln}, respectively.
|
||||
#
|
||||
# @param element [REXML::Element] the web_form, web_page, or web_vuln
|
||||
# element.
|
||||
# @param options [Hash{Symbol => Object}] options
|
||||
# @option options [Boolean] :allow_yaml (false) Whether to allow YAML when
|
||||
# deserializing elements.
|
||||
# @option options [Proc] :notifier Block called with web_* event and path
|
||||
# @option options [Symbol] :type the type of web element, such as :form,
|
||||
# :page, or :vuln. Must correspond to a report_web_<type> method on
|
||||
# {Msf::DBManager}.
|
||||
# @option options [Mdm::Workspace, nil] :workspace
|
||||
# (Msf::DBManager#workspace) workspace under which to report the
|
||||
# imported record.
|
||||
# @yield [element, options]
|
||||
# @yieldparam element [REXML::Element] the web_form, web_page, or
|
||||
# web_vuln element passed to {#import_msf_web_element}.
|
||||
# @yieldparam options [Hash{Symbol => Object}] options for parsing
|
||||
# @yieldreturn [Hash{Symbol => Object}] info
|
||||
# @return [void]
|
||||
# @raise [KeyError] if `:type` is not given
|
||||
def import_msf_web_element(element, options={}, &specialization)
|
||||
options.assert_valid_keys(:allow_yaml, :notifier, :type, :workspace)
|
||||
type = options.fetch(:type)
|
||||
|
||||
info = {}
|
||||
info[:workspace] = options[:workspace] || self.workspace
|
||||
|
||||
MSF_WEB_TEXT_ELEMENT_NAMES.each do |name|
|
||||
element_info = import_msf_text_element(element, name)
|
||||
info.merge!(element_info)
|
||||
end
|
||||
|
||||
info[:ssl] = (info[:ssl] and info[:ssl].to_s.strip.downcase == "true") ? true : false
|
||||
|
||||
specialized_info = specialization.call(element, options)
|
||||
info.merge!(specialized_info)
|
||||
|
||||
self.send("report_web_#{type}", info)
|
||||
|
||||
notifier = options[:notifier]
|
||||
|
||||
if notifier
|
||||
event = "web_#{type}".to_sym
|
||||
notifier.call(event, info[:path])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,14 +1,10 @@
|
|||
# -*- coding: binary -*-
|
||||
##
|
||||
# $Id$
|
||||
##
|
||||
|
||||
##
|
||||
#
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# Framework web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/framework/
|
||||
##
|
||||
|
||||
require 'msf/core/auxiliary'
|
||||
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
# -*- coding: binary -*-
|
||||
##
|
||||
# $Id$
|
||||
##
|
||||
|
||||
require 'rex/exploitation/cmdstager'
|
||||
require 'msf/core/exploit/exe'
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
# -*- coding: binary -*-
|
||||
##
|
||||
# $Id$
|
||||
##
|
||||
|
||||
require 'msf/core/exploit/cmdstager'
|
||||
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
# -*- coding: binary -*-
|
||||
##
|
||||
# $Id$
|
||||
##
|
||||
|
||||
require 'msf/core/exploit/cmdstager'
|
||||
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
# -*- coding: binary -*-
|
||||
##
|
||||
# $Id$
|
||||
##
|
||||
|
||||
require 'rex/text'
|
||||
require 'msf/core/exploit/tftp'
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
# -*- coding: binary -*-
|
||||
##
|
||||
# $Id$
|
||||
##
|
||||
|
||||
require 'msf/core/exploit/cmdstager'
|
||||
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
# -*- coding: binary -*-
|
||||
##
|
||||
# $Id: $
|
||||
##
|
||||
|
||||
require 'msf/core/exploit/cmdstager'
|
||||
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
# -*- coding: binary -*-
|
||||
##
|
||||
# $Id$
|
||||
##
|
||||
|
||||
require 'rex/proto/dhcp'
|
||||
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
# -*- coding: binary -*-
|
||||
##
|
||||
# $Id$
|
||||
##
|
||||
|
||||
require 'rex/proto/tftp'
|
||||
|
||||
|
|
|
@ -58,7 +58,8 @@ class Msf::Modules::Loader::Base
|
|||
MODULE_EXTENSION = '.rb'
|
||||
# String used to separate module names in a qualified module name.
|
||||
MODULE_SEPARATOR = '::'
|
||||
# The base namespace name under which {#namespace_module #namespace_modules} are created.
|
||||
# The base namespace name under which {#create_namespace_module
|
||||
# namespace modules are created}.
|
||||
NAMESPACE_MODULE_NAMES = ['Msf', 'Modules']
|
||||
# Regex that can distinguish regular ruby source from unit test source.
|
||||
UNIT_TEST_REGEX = /rb\.(ut|ts)\.rb$/
|
||||
|
@ -340,7 +341,8 @@ class Msf::Modules::Loader::Base
|
|||
# module's classes. The wrapper module must be named so that active_support's autoloading code doesn't break when
|
||||
# searching constants from inside the Metasploit(1|2|3) class.
|
||||
#
|
||||
# @param [String] namespace_module_names (see #{namespace_module_names})
|
||||
# @param namespace_module_names [Array<String>]
|
||||
# {NAMESPACE_MODULE_NAMES} + <derived-constant-safe names>
|
||||
# @return [Module] module that can wrap the module content from {#read_module_content} using
|
||||
# module_eval_with_lexical_scope.
|
||||
#
|
||||
|
@ -375,7 +377,7 @@ class Msf::Modules::Loader::Base
|
|||
namespace_module
|
||||
end
|
||||
|
||||
# Returns the module with {#module_names} if it exists.
|
||||
# Returns the module with `module_names` if it exists.
|
||||
#
|
||||
# @param [Array<String>] module_names a list of module names to resolve from Object downward.
|
||||
# @return [Module] module that wraps the previously loaded content from {#read_module_content}.
|
||||
|
@ -484,13 +486,14 @@ class Msf::Modules::Loader::Base
|
|||
# Returns the fully-qualified name to the {#create_namespace_module} that wraps the module with the given module
|
||||
# reference name.
|
||||
#
|
||||
# @param [String] module_reference_name The canonical name for referring to the module.
|
||||
# @param [String] module_full_name The canonical name for referring to the
|
||||
# module.
|
||||
# @return [String] name of module.
|
||||
#
|
||||
# @see MODULE_SEPARATOR
|
||||
# @see #namespace_module_names
|
||||
def namespace_module_name(uniq_module_reference_name)
|
||||
namespace_module_names = self.namespace_module_names(uniq_module_reference_name)
|
||||
def namespace_module_name(module_full_name)
|
||||
namespace_module_names = self.namespace_module_names(module_full_name)
|
||||
namespace_module_name = namespace_module_names.join(MODULE_SEPARATOR)
|
||||
|
||||
namespace_module_name
|
||||
|
@ -502,20 +505,20 @@ class Msf::Modules::Loader::Base
|
|||
# escaped by using 'H*' unpacking and prefixing each code with X so
|
||||
# the code remains a valid module name when it starts with a digit.
|
||||
#
|
||||
# @param [String] uniq_module_reference_name The unique canonical name
|
||||
# @param [String] module_full_name The unique canonical name
|
||||
# for the module including type.
|
||||
# @return [Array<String>] {NAMESPACE_MODULE_NAMES} + <derived-constant-safe names>
|
||||
#
|
||||
# @see namespace_module
|
||||
def namespace_module_names(uniq_module_reference_name)
|
||||
NAMESPACE_MODULE_NAMES + [ "Mod" + uniq_module_reference_name.unpack("H*").first.downcase ]
|
||||
def namespace_module_names(module_full_name)
|
||||
NAMESPACE_MODULE_NAMES + [ "Mod" + module_full_name.unpack("H*").first.downcase ]
|
||||
end
|
||||
|
||||
def namespace_module_transaction(uniq_module_reference_name, options={}, &block)
|
||||
def namespace_module_transaction(module_full_name, options={}, &block)
|
||||
options.assert_valid_keys(:reload)
|
||||
|
||||
reload = options[:reload] || false
|
||||
namespace_module_names = self.namespace_module_names(uniq_module_reference_name)
|
||||
namespace_module_names = self.namespace_module_names(module_full_name)
|
||||
|
||||
previous_namespace_module = current_module(namespace_module_names)
|
||||
|
||||
|
|
|
@ -1,4 +1,15 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
#
|
||||
# Rex
|
||||
#
|
||||
|
||||
require 'rex/ui/text/output/buffer/stdout'
|
||||
|
||||
#
|
||||
# Project
|
||||
#
|
||||
|
||||
require 'msf/ui/console/command_dispatcher/encoder'
|
||||
require 'msf/ui/console/command_dispatcher/exploit'
|
||||
require 'msf/ui/console/command_dispatcher/nop'
|
||||
|
@ -2532,11 +2543,12 @@ class Core
|
|||
# redirect output after saving the old ones and getting a new output buffer to use for redirect
|
||||
orig_driver_output = orig_driver.output
|
||||
orig_driver_input = orig_driver.input
|
||||
# we use a rex buffer but add a write method to the instance, which is required in order to be valid $stdout
|
||||
|
||||
# we use a rex buffer but add a write method to the instance, which is
|
||||
# required in order to be valid $stdout
|
||||
temp_output = Rex::Ui::Text::Output::Buffer.new
|
||||
def temp_output.write(msg = '')
|
||||
self.print_raw(msg)
|
||||
end
|
||||
temp_output.extend Rex::Ui::Text::Output::Buffer::Stdout
|
||||
|
||||
orig_driver.init_ui(orig_driver_input,temp_output)
|
||||
# run the desired command to be grepped
|
||||
orig_driver.run_single(cmd)
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
# -*- coding: binary -*-
|
||||
##
|
||||
# $Id$
|
||||
##
|
||||
|
||||
require 'rex/parser/arguments'
|
||||
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
# -*- coding: binary -*-
|
||||
##
|
||||
# $Id$
|
||||
##
|
||||
|
||||
require 'rex/exploitation/cmdstager/base'
|
||||
require 'rex/exploitation/cmdstager/vbs'
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
# -*- coding: binary -*-
|
||||
##
|
||||
# $Id: debug_asm.rb 12595 2011-05-12 18:33:49Z jduck $
|
||||
##
|
||||
|
||||
require 'rex/text'
|
||||
require 'rex/arch'
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
# -*- coding: binary -*-
|
||||
##
|
||||
# $Id: debug_write.rb 12595 2011-05-12 18:33:49Z jduck $
|
||||
##
|
||||
|
||||
require 'rex/text'
|
||||
require 'rex/arch'
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
# -*- coding: binary -*-
|
||||
##
|
||||
# $Id$
|
||||
##
|
||||
|
||||
require 'rex/text'
|
||||
require 'rex/arch'
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
# -*- coding: binary -*-
|
||||
##
|
||||
# $Id: vbs.rb 12595 2011-05-12 18:33:49Z jduck $
|
||||
##
|
||||
|
||||
require 'rex/text'
|
||||
require 'rex/arch'
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
# -*- coding: binary -*-
|
||||
##
|
||||
# $Id$
|
||||
##
|
||||
|
||||
require 'rex/text'
|
||||
require 'rkelly'
|
||||
|
|
|
@ -100,12 +100,6 @@ class Section
|
|||
def file_offset_to_rva(foffset)
|
||||
return offset_to_rva(foffset - file_offset)
|
||||
end
|
||||
# if offset < 0 || offset < file_offset || offset >= file_offset+size
|
||||
# raise BoundsError, "File offset #{offset} outside of section", caller
|
||||
# end
|
||||
#
|
||||
# return (offset - file_offset) + base_rva
|
||||
# end
|
||||
|
||||
def rva_to_offset(rva)
|
||||
offset = rva - base_rva
|
||||
|
|
|
@ -131,7 +131,7 @@ class LogicalBlock
|
|||
#
|
||||
# Increments the number of blocks that have completed their dependency
|
||||
# pass on this block. This number should never become higher than the
|
||||
# @references attribute.
|
||||
# `@references` attribute.
|
||||
#
|
||||
def deref
|
||||
@used_references += 1
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
# -*- coding: binary -*-
|
||||
##
|
||||
#
|
||||
# NAT-PMP protocol support
|
||||
#
|
||||
# by Jon Hart <jhart@spoofed.org>
|
||||
#
|
||||
##
|
||||
# @author Jon Hart <jhart@spoofed.org>
|
||||
|
||||
require 'rex/proto/natpmp/constants'
|
||||
require 'rex/proto/natpmp/packet'
|
||||
|
|
|
@ -40,17 +40,13 @@
|
|||
# The latter has a minor bug in its separate_keys function.
|
||||
# The third key has to begin from the 14th character of the
|
||||
# input string instead of 13th:)
|
||||
#--
|
||||
# $Id: ntlm.rb 11678 2011-01-30 19:26:35Z hdm $
|
||||
#++
|
||||
|
||||
#this class defines the base type needed for other modules like message and crypt
|
||||
|
||||
require 'rex/proto/ntlm/constants'
|
||||
|
||||
module Rex
|
||||
module Proto
|
||||
module NTLM
|
||||
# The base type needed for other modules like message and crypt
|
||||
class Base
|
||||
|
||||
CONST = Rex::Proto::NTLM::Constants
|
||||
|
@ -164,15 +160,19 @@ CONST = Rex::Proto::NTLM::Constants
|
|||
class FieldSet
|
||||
class << FieldSet
|
||||
def define(&block)
|
||||
c = Class.new(self)
|
||||
def c.inherited(subclass)
|
||||
proto = @proto
|
||||
subclass.instance_eval {
|
||||
@proto = proto
|
||||
}
|
||||
klass = Class.new(self) do
|
||||
def self.inherited(subclass)
|
||||
proto = @proto
|
||||
|
||||
subclass.instance_eval do
|
||||
@proto = proto
|
||||
end
|
||||
end
|
||||
end
|
||||
c.module_eval(&block)
|
||||
c
|
||||
|
||||
klass.module_eval(&block)
|
||||
|
||||
klass
|
||||
end
|
||||
|
||||
def string(name, opts)
|
||||
|
|
|
@ -1,19 +1,13 @@
|
|||
# -*- coding: binary -*-
|
||||
##
|
||||
# $Id: $
|
||||
##
|
||||
|
||||
##
|
||||
#
|
||||
# RFB protocol support
|
||||
#
|
||||
# by Joshua J. Drake <jduck>
|
||||
# @author Joshua J. Drake <jduck>
|
||||
#
|
||||
# Based on:
|
||||
# vnc_auth_none contributed by Matteo Cantoni <goony[at]nothink.org>
|
||||
# vnc_auth_login contributed by carstein <carstein.sec[at]gmail.com>
|
||||
#
|
||||
##
|
||||
|
||||
require 'rex/proto/rfb/constants'
|
||||
require 'rex/proto/rfb/cipher'
|
||||
|
|
|
@ -1,23 +1,18 @@
|
|||
#!/usr/bin/env ruby
|
||||
# -*- coding: binary -*-
|
||||
|
||||
$:.unshift(File.join(File.dirname(__FILE__), '..', '..'))
|
||||
|
||||
##
|
||||
#
|
||||
# $Id: $
|
||||
##
|
||||
|
||||
##
|
||||
#
|
||||
# RFB protocol support
|
||||
#
|
||||
# by Joshua J. Drake <jduck>
|
||||
# @author Joshua J. Drake <jduck>
|
||||
#
|
||||
# Based on:
|
||||
# vnc_auth_none contributed by Matteo Cantoni <goony[at]nothink.org>
|
||||
# vnc_auth_login contributed by carstein <carstein.sec[at]gmail.com>
|
||||
#
|
||||
##
|
||||
|
||||
$:.unshift(File.join(File.dirname(__FILE__), '..', '..'))
|
||||
|
||||
require 'rex/socket'
|
||||
require 'rex/proto/rfb'
|
||||
|
|
|
@ -1020,7 +1020,7 @@ module Text
|
|||
rand_base(len, bad, *foo )
|
||||
end
|
||||
|
||||
# Generate a random GUID, of the form {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
|
||||
# Generate a random GUID, of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.
|
||||
def self.rand_guid
|
||||
"{#{[8,4,4,4,12].map {|a| rand_text_hex(a) }.join("-")}}"
|
||||
end
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
# make sure the classes are defined before opening it to define submodule
|
||||
require 'rex/ui/text/output'
|
||||
require 'rex/ui/text/output/buffer'
|
||||
|
||||
module Rex
|
||||
module Ui
|
||||
module Text
|
||||
class Output
|
||||
class Buffer
|
||||
# Adds {#write} method to {Rex::Ui::Text::Output::Buffer} so it can
|
||||
# function as a stand-in for `$stdout`
|
||||
module Stdout
|
||||
# Prints raw message.
|
||||
#
|
||||
# @param (see Rex::Ui::Text::Output::Buffer#write)
|
||||
# @return (see Rex::Ui::Text::Output::Buffer#write)
|
||||
def write(msg = '')
|
||||
print_raw(msg)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,6 +1,7 @@
|
|||
load 'active_record/railties/databases.rake'
|
||||
|
||||
require 'metasploit/framework'
|
||||
require 'metasploit/framework/database'
|
||||
|
||||
# A modification to remove dependency on Rails.env
|
||||
#
|
||||
|
@ -21,19 +22,10 @@ def configs_for_environment
|
|||
valid_environment_configurations
|
||||
end
|
||||
|
||||
# This would normally use Rails.application.config.database_configuration
|
||||
def database_configurations
|
||||
YAML.load_file(database_configurations_pathname)
|
||||
end
|
||||
|
||||
def database_configurations_pathname
|
||||
Metasploit::Framework.root.join('config', 'database.yml')
|
||||
end
|
||||
|
||||
# emulate initializer "active_record.initialize_database" from active_record/railtie
|
||||
ActiveSupport.on_load(:active_record) do
|
||||
self.configurations = database_configurations
|
||||
puts "Connecting to database specified by #{database_configurations_pathname}"
|
||||
self.configurations = Metasploit::Framework::Database.configurations
|
||||
puts "Connecting to database specified by #{Metasploit::Framework::Database.configurations_pathname}"
|
||||
|
||||
spec = configurations[Metasploit::Framework.env]
|
||||
establish_connection(spec)
|
||||
|
@ -58,7 +50,7 @@ Rake::Task['db:seed'].clear
|
|||
|
||||
db_namespace = namespace :db do
|
||||
task :load_config do
|
||||
ActiveRecord::Base.configurations = database_configurations
|
||||
ActiveRecord::Base.configurations = Metasploit::Framework::Database.configurations
|
||||
|
||||
ActiveRecord::Migrator.migrations_paths = [
|
||||
# rails isn't in Gemfile, so can't use the more appropriate
|
||||
|
|
|
@ -39,7 +39,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
},
|
||||
'Platform' => ['php'],
|
||||
'Arch' => ARCH_PHP,
|
||||
'Targets' =>
|
||||
'Targets' =>
|
||||
[
|
||||
['stunshell', {}]
|
||||
],
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
FactoryGirl.define do
|
||||
factory :mdm_web_form, :class => Mdm::WebForm do
|
||||
#
|
||||
# Associations
|
||||
#
|
||||
association :web_site, :factory => :mdm_web_site
|
||||
|
||||
# attributes that would be in web_form element from Pro export
|
||||
trait :exported do
|
||||
method { generate :mdm_web_form_method }
|
||||
params { generate :mdm_web_form_params }
|
||||
path { generate :mdm_web_form_path }
|
||||
end
|
||||
end
|
||||
|
||||
methods = ['GET', 'POST']
|
||||
|
||||
sequence :mdm_web_form_method do |n|
|
||||
methods[n % methods.length]
|
||||
end
|
||||
|
||||
sequence :mdm_web_form_params do |n|
|
||||
[
|
||||
[
|
||||
"name#{n}",
|
||||
"value#{n}"
|
||||
]
|
||||
]
|
||||
end
|
||||
|
||||
sequence :mdm_web_form_path do |n|
|
||||
"path/to/web/form/#{n}"
|
||||
end
|
||||
end
|
|
@ -0,0 +1,64 @@
|
|||
FactoryGirl.define do
|
||||
factory :mdm_web_page, :class => Mdm::WebPage do
|
||||
auth { generate :mdm_web_page_auth }
|
||||
body { generate :mdm_web_page_body }
|
||||
code { generate :mdm_web_page_code }
|
||||
cookie { generate :mdm_web_page_cookie }
|
||||
ctype { generate :mdm_web_page_ctype }
|
||||
headers { generate :mdm_web_page_headers }
|
||||
location { generate :mdm_web_page_location }
|
||||
mtime { generate :mdm_web_page_mtime }
|
||||
query { generate :mdm_web_page_query }
|
||||
|
||||
#
|
||||
# Associations
|
||||
#
|
||||
association :web_site, :factory => :mdm_web_site
|
||||
end
|
||||
|
||||
sequence :mdm_web_page_auth do |n|
|
||||
"Authorization: #{n}"
|
||||
end
|
||||
|
||||
sequence :mdm_web_page_body do |n|
|
||||
xml = Builder::XmlMarkup.new(:indent => 2)
|
||||
|
||||
xml.html
|
||||
|
||||
xml.target!.strip
|
||||
end
|
||||
|
||||
sequence :mdm_web_page_code do |n|
|
||||
n
|
||||
end
|
||||
|
||||
sequence :mdm_web_page_cookie do |n|
|
||||
"name#{n}=value#{n}"
|
||||
end
|
||||
|
||||
sequence :mdm_web_page_ctype do |n|
|
||||
"application/x-#{n}"
|
||||
end
|
||||
|
||||
sequence :mdm_web_page_headers do |n|
|
||||
[
|
||||
[
|
||||
"Header#{n}",
|
||||
"Value#{n}"
|
||||
]
|
||||
]
|
||||
end
|
||||
|
||||
sequence :mdm_web_page_location do |n|
|
||||
"http://example.com/location/#{n}"
|
||||
end
|
||||
|
||||
sequence :mdm_web_page_mtime do |n|
|
||||
past = Time.now - n
|
||||
past.utc.strftime('%a, %d %b %Y %H:%M:%S %Z')
|
||||
end
|
||||
|
||||
sequence :mdm_web_page_query do |n|
|
||||
"param#{n}=value#{n}"
|
||||
end
|
||||
end
|
|
@ -0,0 +1,14 @@
|
|||
FactoryGirl.define do
|
||||
factory :exported_web_vuln, :parent => :mdm_web_vuln do
|
||||
blame { generate :mdm_web_vuln_blame }
|
||||
description { generate :mdm_web_vuln_description }
|
||||
end
|
||||
|
||||
sequence :mdm_web_vuln_blame do |n|
|
||||
"Blame employee ##{n}"
|
||||
end
|
||||
|
||||
sequence :mdm_web_vuln_description do |n|
|
||||
"Mdm::WebVuln#description #{n}"
|
||||
end
|
||||
end
|
|
@ -0,0 +1,22 @@
|
|||
#
|
||||
# Specs
|
||||
#
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
#
|
||||
# Project
|
||||
#
|
||||
|
||||
require 'metasploit/framework/database'
|
||||
require 'msf/core'
|
||||
|
||||
describe Msf::DBManager do
|
||||
include_context 'Msf::Simple::Framework'
|
||||
|
||||
subject(:db_manager) do
|
||||
framework.db
|
||||
end
|
||||
|
||||
it_should_behave_like 'Msf::DBManager::ImportMsfXml'
|
||||
end
|
|
@ -25,5 +25,22 @@ end
|
|||
|
||||
RSpec.configure do |config|
|
||||
config.mock_with :rspec
|
||||
|
||||
# Can't use factory_girl_rails since not using rails, so emulate
|
||||
# factory_girl.set_factory_paths initializer and after_initialize for
|
||||
# FactoryGirl::Railtie
|
||||
config.before(:suite) do
|
||||
# Need to load Mdm models first so factories can use them
|
||||
MetasploitDataModels.require_models
|
||||
|
||||
FactoryGirl.definition_file_paths = [
|
||||
MetasploitDataModels.root.join('spec', 'factories'),
|
||||
# Have metasploit-framework's definition file path last so it can
|
||||
# modify gem factories.
|
||||
Metasploit::Framework.root.join('spec', 'factories')
|
||||
]
|
||||
|
||||
FactoryGirl.find_definitions
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
shared_context 'DatabaseCleaner' do
|
||||
def with_established_connection
|
||||
begin
|
||||
ActiveRecord::Base.connection_pool.with_connection do
|
||||
yield
|
||||
end
|
||||
rescue ActiveRecord::ConnectionNotEstablished
|
||||
# if there isn't a connection established, then established one and try
|
||||
# again
|
||||
ActiveRecord::Base.configurations = Metasploit::Framework::Database.configurations
|
||||
spec = ActiveRecord::Base.configurations[Metasploit::Framework.env]
|
||||
ActiveRecord::Base.establish_connection(spec)
|
||||
|
||||
retry
|
||||
end
|
||||
end
|
||||
|
||||
# clean before all in case last test run was interrupted before
|
||||
# after(:each) could clean up
|
||||
before(:all) do
|
||||
with_established_connection do
|
||||
DatabaseCleaner.clean_with(:truncation)
|
||||
end
|
||||
end
|
||||
|
||||
# Clean up after each test
|
||||
after(:each) do
|
||||
with_established_connection do
|
||||
# Testing using both :truncation and :deletion; :truncation took long
|
||||
# for testing.
|
||||
DatabaseCleaner.clean_with(:deletion)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,39 @@
|
|||
require 'msf/base/simple/framework'
|
||||
require 'metasploit/framework'
|
||||
|
||||
shared_context 'Msf::Simple::Framework' do
|
||||
let(:dummy_pathname) do
|
||||
Metasploit::Framework.root.join('spec', 'dummy')
|
||||
end
|
||||
|
||||
let(:framework) do
|
||||
Msf::Simple::Framework.create(
|
||||
'ConfigDirectory' => framework_config_pathname.to_s,
|
||||
# don't load any module paths so we can just load the module under test and save time
|
||||
'DeferModuleLoads' => true
|
||||
)
|
||||
end
|
||||
|
||||
let(:framework_config_pathname) do
|
||||
dummy_pathname.join('framework', 'config')
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
framework_config_pathname.mkpath
|
||||
end
|
||||
|
||||
after(:each) do
|
||||
dummy_pathname.rmtree
|
||||
end
|
||||
|
||||
after(:each) do
|
||||
# explicitly kill threads so that they don't exhaust connection pool
|
||||
thread_manager = framework.threads
|
||||
|
||||
thread_manager.each do |thread|
|
||||
thread.kill
|
||||
end
|
||||
|
||||
thread_manager.monitor.kill
|
||||
end
|
||||
end
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,24 @@
|
|||
shared_examples_for 'Msf::DBManager::ImportMsfXml#check_msf_xml_version! with root tag' do |root_tag, options={}|
|
||||
options.assert_valid_keys(:allow_yaml)
|
||||
allow_yaml = options.fetch(:allow_yaml)
|
||||
|
||||
context "with #{root_tag}" do
|
||||
let(:root_tag) do
|
||||
root_tag
|
||||
end
|
||||
|
||||
should_label_by_allow_yaml = {
|
||||
true => 'should',
|
||||
false => 'should not'
|
||||
}
|
||||
should_label = should_label_by_allow_yaml[allow_yaml]
|
||||
|
||||
it "#{should_label} allow YAML" do
|
||||
expect(metadata[:allow_yaml]).to eq(allow_yaml)
|
||||
end
|
||||
|
||||
it "should have #{root_tag} as root tag" do
|
||||
metadata[:root_tag].should == root_tag
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,41 @@
|
|||
shared_examples_for 'Msf::DBManager::ImportMsfXml#import_msf_web_element specialization' do
|
||||
it 'should call #import_msf_web_element with element' do
|
||||
db_manager.should_receive(:import_msf_web_element).with(element, anything)
|
||||
|
||||
subject
|
||||
end
|
||||
|
||||
it 'should call #import_msf_web_element with :allow_yaml and :workspace' do
|
||||
db_manager.should_receive(:import_msf_web_element).with(
|
||||
anything,
|
||||
hash_including(
|
||||
:allow_yaml => allow_yaml,
|
||||
:workspace => workspace
|
||||
)
|
||||
)
|
||||
|
||||
subject
|
||||
end
|
||||
|
||||
it 'should call #import_msf_web_element with :type' do
|
||||
db_manager.should_receive(:import_msf_web_element).with(
|
||||
anything,
|
||||
hash_including(
|
||||
:type => type
|
||||
)
|
||||
)
|
||||
|
||||
subject
|
||||
end
|
||||
|
||||
it 'should pass block to #import_msf_web_element as :notifier' do
|
||||
db_manager.should_receive(
|
||||
:import_msf_web_element
|
||||
).with(
|
||||
anything,
|
||||
hash_including(:notifier => notifier)
|
||||
)
|
||||
|
||||
subject
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue