Add module for running all post test modules
This commit is contained in:
parent
2a410e126d
commit
46f7f8e7b0
|
@ -1,7 +1,10 @@
|
|||
require 'rex/stopwatch'
|
||||
|
||||
module Msf
|
||||
module ModuleTest
|
||||
attr_accessor :tests
|
||||
attr_accessor :failures
|
||||
attr_accessor :skipped
|
||||
|
||||
class SkipTestError < ::Exception
|
||||
end
|
||||
|
@ -9,13 +12,21 @@ module Msf
|
|||
def initialize(info = {})
|
||||
@tests = 0
|
||||
@failures = 0
|
||||
@skipped = 0
|
||||
super
|
||||
end
|
||||
|
||||
def run_all_tests
|
||||
tests = self.methods.select { |m| m.to_s =~ /^test_/ }
|
||||
tests.each { |test_method|
|
||||
self.send(test_method)
|
||||
begin
|
||||
self.send(test_method)
|
||||
rescue SkipTestError => e
|
||||
# If the entire def is skipped, increment tests and skip count
|
||||
@tests += 1
|
||||
@skipped += 1
|
||||
print_status("SKIPPED: def #{test_method} (#{e.message})")
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -34,8 +45,10 @@ module Msf
|
|||
return
|
||||
end
|
||||
rescue SkipTestError => e
|
||||
@skipped += 1
|
||||
print_status("SKIPPED: #{msg} (#{e.message})")
|
||||
rescue ::Exception => e
|
||||
@failures += 1
|
||||
print_error("FAILED: #{msg}")
|
||||
print_error("Exception: #{e.class}: #{e}")
|
||||
dlog("Exception in testing - #{msg}")
|
||||
|
@ -49,6 +62,11 @@ module Msf
|
|||
def pending(msg = "", &block)
|
||||
print_status("PENDING: #{msg}")
|
||||
end
|
||||
|
||||
# @return [Integer] The number of tests that have passed
|
||||
def passed
|
||||
@tests - @failures
|
||||
end
|
||||
end
|
||||
|
||||
module ModuleTest::PostTest
|
||||
|
@ -57,15 +75,20 @@ module Msf
|
|||
print_status("Running against session #{datastore["SESSION"]}")
|
||||
print_status("Session type is #{session.type} and platform is #{session.platform}")
|
||||
|
||||
t = Time.now
|
||||
@tests = 0; @failures = 0
|
||||
run_all_tests
|
||||
@tests = 0
|
||||
@failures = 0
|
||||
@skipped = 0
|
||||
|
||||
vprint_status("Testing complete in #{Time.now - t}")
|
||||
if (@failures > 0)
|
||||
print_error("Passed: #{@tests - @failures}; Failed: #{@failures}")
|
||||
_res, elapsed_time = Rex::Stopwatch.elapsed_time do
|
||||
run_all_tests
|
||||
end
|
||||
|
||||
vprint_status("Testing complete in #{elapsed_time.round(2)} seconds")
|
||||
status = "Passed: #{passed}; Failed: #{@failures}; Skipped: #{@skipped}"
|
||||
if @failures > 0
|
||||
print_error(status)
|
||||
else
|
||||
print_status("Passed: #{@tests - @failures}; Failed: #{@failures}")
|
||||
print_status(status)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,155 @@
|
|||
require 'rex'
|
||||
|
||||
lib = File.join(Msf::Config.install_root, "test", "lib")
|
||||
$LOAD_PATH.push(lib) unless $LOAD_PATH.include?(lib)
|
||||
require 'module_test'
|
||||
|
||||
class MetasploitModule < Msf::Post
|
||||
|
||||
def initialize(info = {})
|
||||
super(
|
||||
update_info(
|
||||
info,
|
||||
'Name' => 'Test all applicable post modules',
|
||||
'Description' => %q{ This module run all applicable post modules against the current session },
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => [ 'alanfoster'],
|
||||
'Platform' => [ 'linux', 'unix', 'osx', 'windows', 'java' ],
|
||||
'SessionTypes' => [ 'meterpreter', 'shell', 'powershell' ]
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
def run
|
||||
available_modules = select_available_modules
|
||||
session_metadata = "#{session.session_type} session #{session.sid}"
|
||||
|
||||
print_status("Applicable modules:")
|
||||
print_line(
|
||||
matching_modules_table(available_modules, header: "Valid modules for #{session_metadata}", with_results: false)
|
||||
)
|
||||
|
||||
module_results = run_modules(available_modules)
|
||||
|
||||
print_status("Modules results:")
|
||||
print_line(matching_modules_table(module_results, header: "Results for #{session_metadata}", with_results: true))
|
||||
end
|
||||
|
||||
def select_available_modules
|
||||
session_platform = Msf::Module::Platform.find_platform(session.platform)
|
||||
session_type = session.type
|
||||
|
||||
module_results = []
|
||||
framework.modules.post.each do |refname, _clazz|
|
||||
next unless refname.start_with?('test/') && refname != self.refname
|
||||
mod = framework.modules.create(refname)
|
||||
|
||||
verify_result = {
|
||||
is_session_platform: mod.platform.platforms.include?(session_platform),
|
||||
is_session_type: mod.session_types.include?(session_type)
|
||||
}
|
||||
verify_result[:is_valid] = verify_result[:is_session_platform] && verify_result[:is_session_type]
|
||||
module_results << { module: mod, **verify_result }
|
||||
end
|
||||
module_results
|
||||
end
|
||||
|
||||
def run_modules(available_modules)
|
||||
results = []
|
||||
available_modules.each do |available_module|
|
||||
next unless available_module[:is_valid]
|
||||
|
||||
print_status("Running #{available_module[:module].refname} against session #{datastore["SESSION"]}")
|
||||
print_status("-" * 80)
|
||||
|
||||
module_replicant = nil
|
||||
available_module[:module].run_simple(
|
||||
'LocalInput' => user_input,
|
||||
'LocalOutput' => user_output,
|
||||
'Options' => datastore.copy
|
||||
) { |yielded_module_replicant| module_replicant = yielded_module_replicant }
|
||||
|
||||
results << {
|
||||
**available_module,
|
||||
tests: module_replicant.tests,
|
||||
passed: module_replicant.passed,
|
||||
failures: module_replicant.failures,
|
||||
skipped: module_replicant.skipped,
|
||||
}
|
||||
|
||||
print_status("-" * 80)
|
||||
end
|
||||
results
|
||||
end
|
||||
|
||||
def matching_modules_table(module_results, header:, with_results:)
|
||||
name_styler = ::Msf::Ui::Console::TablePrint::CustomColorStyler.new
|
||||
boolean_styler = ::Msf::Ui::Console::TablePrint::CustomColorStyler.new({ 'Yes' => '%grn', 'No' => '%red' })
|
||||
rows = module_results.sort_by { |module_result| module_result[:is_valid] ? 0 : 1 }.map.with_index do |module_result, index|
|
||||
next if with_results && !module_result[:is_valid]
|
||||
|
||||
name_styler.merge!({ module_result[:module].refname => module_result[:is_valid] ? '%grn' : '%red' })
|
||||
data = [
|
||||
index,
|
||||
module_result[:module].refname,
|
||||
module_result[:is_session_platform] ? 'Yes' : 'No',
|
||||
module_result[:is_session_type] ? 'Yes' : 'No',
|
||||
]
|
||||
|
||||
if with_results
|
||||
data += [
|
||||
module_result[:tests].to_s,
|
||||
module_result[:passed].to_s,
|
||||
module_result[:failures].to_s,
|
||||
module_result[:skipped].to_s,
|
||||
]
|
||||
end
|
||||
|
||||
data
|
||||
end.compact
|
||||
|
||||
table = Rex::Text::Table.new(
|
||||
'Header' => header,
|
||||
'Indent' => 1,
|
||||
'Columns' => [ '#', 'Name', 'is_session_platform', 'is_session_type' ] + (with_results ? ['total', 'passed', 'failures', 'skipped'] : []),
|
||||
'SortIndex' => -1,
|
||||
'WordWrap' => false,
|
||||
'ColProps' => {
|
||||
'Name' => {
|
||||
'Stylers' => [name_styler]
|
||||
},
|
||||
'is_session_platform' => {
|
||||
'Stylers' => [boolean_styler]
|
||||
},
|
||||
'is_session_type' => {
|
||||
'Stylers' => [boolean_styler]
|
||||
},
|
||||
'total' => {
|
||||
'Stylers' => []
|
||||
},
|
||||
'passed' => {
|
||||
'Stylers' => [StyleIfGreaterThanZero.new(color: '%grn')]
|
||||
},
|
||||
'failures' => {
|
||||
'Stylers' => [StyleIfGreaterThanZero.new(color: '%red')]
|
||||
},
|
||||
'skipped' => {
|
||||
'Stylers' => [StyleIfGreaterThanZero.new(color: '%yel')]
|
||||
}
|
||||
},
|
||||
'Rows' => rows
|
||||
)
|
||||
|
||||
table.to_s
|
||||
end
|
||||
|
||||
class StyleIfGreaterThanZero
|
||||
def initialize(color:)
|
||||
@color = color
|
||||
end
|
||||
|
||||
def style(value)
|
||||
value.to_i > 0 ? "#{@color}#{value}%clr" : value
|
||||
end
|
||||
end
|
||||
end
|
|
@ -15,8 +15,8 @@ class MetasploitModule < Msf::Post
|
|||
'Name' => 'Meterpreter cmd_exec test',
|
||||
'Description' => %q( This module will test the meterpreter cmd_exec API ),
|
||||
'License' => MSF_LICENSE,
|
||||
'Platform' => ['windows', 'linux', 'unix'],
|
||||
'SessionTypes' => ['meterpreter']
|
||||
'Platform' => [ 'windows', 'linux', 'unix', 'java', 'osx' ],
|
||||
'SessionTypes' => ['meterpreter', 'shell', 'powershell']
|
||||
)
|
||||
)
|
||||
end
|
||||
|
|
|
@ -20,8 +20,8 @@ class MetasploitModule < Msf::Post
|
|||
'Description' => %q{ This module will test Post::File API methods },
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => [ 'egypt' ],
|
||||
'Platform' => [ 'windows', 'linux', 'unix', 'java' ],
|
||||
'SessionTypes' => [ 'meterpreter', 'shell' ]
|
||||
'Platform' => [ 'windows', 'linux', 'unix', 'java', 'osx' ],
|
||||
'SessionTypes' => [ 'meterpreter', 'shell', 'powershell' ]
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
@ -19,8 +19,8 @@ class MetasploitModule < Msf::Post
|
|||
'Description' => %q{ This module will test Post::Common get envs API methods },
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => [ 'Ben Campbell'],
|
||||
'Platform' => [ 'windows', 'linux', 'java', 'python' ],
|
||||
'SessionTypes' => [ 'meterpreter', 'shell' ]
|
||||
'Platform' => [ 'windows', 'linux', 'unix', 'java', 'python', 'osx' ],
|
||||
'SessionTypes' => [ 'meterpreter', 'shell', 'powershell' ]
|
||||
)
|
||||
)
|
||||
end
|
||||
|
|
|
@ -17,7 +17,7 @@ class MetasploitModule < Msf::Post
|
|||
'Description' => %q{ This module will test meterpreter API methods },
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => [ 'egypt'],
|
||||
'Platform' => [ 'windows', 'linux', 'java' ],
|
||||
'Platform' => [ 'windows', 'linux', 'java', 'osx' ],
|
||||
'SessionTypes' => [ 'meterpreter' ]
|
||||
)
|
||||
)
|
||||
|
|
|
@ -16,7 +16,8 @@ class MetasploitModule < Msf::Post
|
|||
'Description' => %q{ This module will test railgun api functions },
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => [ 'Spencer McIntyre' ],
|
||||
'Platform' => [ 'linux', 'osx', 'windows' ]
|
||||
'Platform' => [ 'linux', 'osx', 'windows' ],
|
||||
'SessionTypes' => [ 'meterpreter' ]
|
||||
)
|
||||
)
|
||||
end
|
||||
|
|
|
@ -21,7 +21,8 @@ class MetasploitModule < Msf::Post
|
|||
'Description' => %q{ This module will test railgun code used in post modules},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => [ 'kernelsmith'],
|
||||
'Platform' => [ 'windows' ]
|
||||
'Platform' => [ 'linux', 'osx', 'windows' ],
|
||||
'SessionTypes' => [ 'meterpreter' ]
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
@ -25,7 +25,8 @@ class MetasploitModule < Msf::Post
|
|||
'kernelsmith', # original
|
||||
'egypt', # PostTest conversion
|
||||
],
|
||||
'Platform' => [ 'windows' ]
|
||||
'Platform' => [ 'windows' ],
|
||||
'SessionTypes' => [ 'meterpreter', 'shell', 'powershell' ]
|
||||
)
|
||||
)
|
||||
end
|
||||
|
|
|
@ -17,7 +17,7 @@ class MetasploitModule < Msf::Post
|
|||
'Description' => %q{ This module will test the meterpreter search method },
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => [ 'timwr'],
|
||||
'Platform' => [ 'windows', 'linux', 'java' ],
|
||||
'Platform' => [ 'windows', 'linux', 'java', 'osx' ],
|
||||
'SessionTypes' => [ 'meterpreter' ]
|
||||
)
|
||||
)
|
||||
|
|
|
@ -22,7 +22,7 @@ class MetasploitModule < Msf::Post
|
|||
'License' => MSF_LICENSE,
|
||||
'Author' => [ 'kernelsmith', 'egypt' ],
|
||||
'Platform' => [ 'windows' ],
|
||||
'SessionTypes' => [ 'meterpreter', 'shell' ]
|
||||
'SessionTypes' => [ 'meterpreter', 'shell', 'powershell' ]
|
||||
)
|
||||
)
|
||||
register_options(
|
||||
|
|
|
@ -22,7 +22,7 @@ class MetasploitModule < Msf::Post
|
|||
'Description' => %q{ This module will test Post::File API methods },
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => [ 'egypt'],
|
||||
'Platform' => [ 'linux', 'java' ],
|
||||
'Platform' => [ 'linux', 'unix', 'java', 'osx' ],
|
||||
'SessionTypes' => [ 'meterpreter', 'shell' ]
|
||||
)
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue