123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293 |
- #!/usr/bin/env ruby
- ##
- # This module requires Metasploit: https://metasploit.com/download
- # Current source: https://github.com/rapid7/metasploit-framework
- ##
- #
- # Reads untest payload modules from log/untested-payloads.log (which can be produced by running `rake spec`) and prints
- # the statements that need to be added to `spec/modules/payloads_spec.rb`. **Note: this script depends on the payload
- # being loadable, so if module is not loadable, then the developer must manually determine which single needs to be tested
- # or which combinations of stages and stagers need to be tested.**
- #
- msfbase = __FILE__
- while File.symlink?(msfbase)
- msfbase = File.expand_path(File.readlink(msfbase), File.dirname(msfbase))
- end
- $:.unshift(File.expand_path(File.join(File.dirname(msfbase), '..', '..', 'lib')))
- require 'msfenv'
- framework = Msf::Simple::Framework.create()
- options_set_by_ancestor_reference_name = Hash.new { |hash, ancestor_reference_name|
- hash[ancestor_reference_name] = Set.new
- }
- framework.payloads.each_module { |reference_name, payload_class|
- next unless payload_class
- module_ancestors = payload_class.ancestors.select { |ancestor|
- # need to use try because name may be nil for anonymous Modules
- ancestor.name.try(:start_with?, 'Msf::Modules::')
- }
- ancestor_reference_names = module_ancestors.map { |module_ancestor|
- unpacked_module_ancestor_full_name = module_ancestor.name.sub(/^Msf::Modules::Mod/, '')
- .sub(/::MetasploitModule/, '')
- module_ancestor_full_name = [unpacked_module_ancestor_full_name].pack("H*")
- module_ancestor_full_name.sub(%r{^payload/}, '')
- }
- options = {
- reference_name: reference_name,
- ancestor_reference_names: ancestor_reference_names
- }
- # record for both ancestor_reference_names as which is untested is not known here
- ancestor_reference_names.each do |ancestor_reference_name|
- options_set_by_ancestor_reference_name[ancestor_reference_name].add options
- end
- }
- tested_options = Set.new
- $stderr.puts "Add the following context to `spec/modules/payloads_spec.rb` by inserting them in lexical order between the pre-existing contexts:"
- File.open('log/untested-payloads.log') { |f|
- f.each_line do |line|
- ancestor_reference_name = line.strip
- options_set = options_set_by_ancestor_reference_name[ancestor_reference_name]
- options_set.each do |options|
- # don't print a needed test twice
- unless tested_options.include? options
- reference_name = options[:reference_name]
- $stdout.puts
- $stdout.puts " context '#{reference_name}' do\n" \
- " it_should_behave_like 'payload cached size is consistent',\n" \
- " ancestor_reference_names: ["
- ancestor_reference_names = options[:ancestor_reference_names]
- if ancestor_reference_names.length == 1
- $stdout.puts " '#{ancestor_reference_names[0]}'"
- else
- $stdout.puts " '#{ancestor_reference_names[1]}',"
- $stdout.puts " '#{ancestor_reference_names[0]}'"
- end
- $stdout.puts " ],\n" \
- " dynamic_size: false,\n" \
- " modules_pathname: modules_pathname,\n" \
- " reference_name: '#{reference_name}'\n" \
- " end"
- tested_options.add options
- end
- end
- end
- }
|