CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/tools/modules/missing_payload_tests.rb
Views: 1904
1
#!/usr/bin/env ruby
2
3
##
4
# This module requires Metasploit: https://metasploit.com/download
5
# Current source: https://github.com/rapid7/metasploit-framework
6
##
7
8
#
9
# Reads untest payload modules from log/untested-payloads.log (which can be produced by running `rake spec`) and prints
10
# the statements that need to be added to `spec/modules/payloads_spec.rb`. **Note: this script depends on the payload
11
# being loadable, so if module is not loadable, then the developer must manually determine which single needs to be tested
12
# or which combinations of stages and stagers need to be tested.**
13
#
14
15
msfbase = __FILE__
16
while File.symlink?(msfbase)
17
msfbase = File.expand_path(File.readlink(msfbase), File.dirname(msfbase))
18
end
19
20
$:.unshift(File.expand_path(File.join(File.dirname(msfbase), '..', '..', 'lib')))
21
require 'msfenv'
22
23
framework = Msf::Simple::Framework.create()
24
25
options_set_by_ancestor_reference_name = Hash.new { |hash, ancestor_reference_name|
26
hash[ancestor_reference_name] = Set.new
27
}
28
29
framework.payloads.each_module { |reference_name, payload_class|
30
next unless payload_class
31
module_ancestors = payload_class.ancestors.select { |ancestor|
32
# need to use try because name may be nil for anonymous Modules
33
ancestor.name.try(:start_with?, 'Msf::Modules::')
34
}
35
ancestor_reference_names = module_ancestors.map { |module_ancestor|
36
unpacked_module_ancestor_full_name = module_ancestor.name.sub(/^Msf::Modules::Mod/, '')
37
.sub(/::MetasploitModule/, '')
38
module_ancestor_full_name = [unpacked_module_ancestor_full_name].pack("H*")
39
module_ancestor_full_name.sub(%r{^payload/}, '')
40
}
41
42
options = {
43
reference_name: reference_name,
44
ancestor_reference_names: ancestor_reference_names
45
}
46
47
# record for both ancestor_reference_names as which is untested is not known here
48
ancestor_reference_names.each do |ancestor_reference_name|
49
options_set_by_ancestor_reference_name[ancestor_reference_name].add options
50
end
51
}
52
53
tested_options = Set.new
54
55
$stderr.puts "Add the following context to `spec/modules/payloads_spec.rb` by inserting them in lexical order between the pre-existing contexts:"
56
57
File.open('log/untested-payloads.log') { |f|
58
f.each_line do |line|
59
ancestor_reference_name = line.strip
60
61
options_set = options_set_by_ancestor_reference_name[ancestor_reference_name]
62
63
options_set.each do |options|
64
# don't print a needed test twice
65
unless tested_options.include? options
66
reference_name = options[:reference_name]
67
68
$stdout.puts
69
$stdout.puts " context '#{reference_name}' do\n" \
70
" it_should_behave_like 'payload cached size is consistent',\n" \
71
" ancestor_reference_names: ["
72
73
ancestor_reference_names = options[:ancestor_reference_names]
74
75
if ancestor_reference_names.length == 1
76
$stdout.puts " '#{ancestor_reference_names[0]}'"
77
else
78
$stdout.puts " '#{ancestor_reference_names[1]}',"
79
$stdout.puts " '#{ancestor_reference_names[0]}'"
80
end
81
82
$stdout.puts " ],\n" \
83
" dynamic_size: false,\n" \
84
" modules_pathname: modules_pathname,\n" \
85
" reference_name: '#{reference_name}'\n" \
86
" end"
87
88
tested_options.add options
89
end
90
end
91
end
92
}
93
94