commit
dee89bdfa0
|
@ -6,6 +6,8 @@
|
|||
.yardoc
|
||||
# Mac OS X files
|
||||
.DS_Store
|
||||
# simplecov coverage data
|
||||
coverage
|
||||
data/meterpreter/ext_server_pivot.dll
|
||||
data/meterpreter/ext_server_pivot.x64.dll
|
||||
doc
|
||||
|
|
3
Gemfile
3
Gemfile
|
@ -24,4 +24,7 @@ end
|
|||
group :test do
|
||||
# testing framework
|
||||
gem 'rspec'
|
||||
# code coverage for tests
|
||||
# any version newer than 0.5.4 gives an Encoding error when trying to read the source files.
|
||||
gem 'simplecov', '0.5.4', :require => false
|
||||
end
|
||||
|
|
|
@ -45,6 +45,10 @@ GEM
|
|||
rspec-expectations (2.11.3)
|
||||
diff-lcs (~> 1.1.3)
|
||||
rspec-mocks (2.11.3)
|
||||
simplecov (0.5.4)
|
||||
multi_json (~> 1.0.3)
|
||||
simplecov-html (~> 0.5.3)
|
||||
simplecov-html (0.5.3)
|
||||
slop (3.3.3)
|
||||
tzinfo (0.3.33)
|
||||
yard (0.8.2.1)
|
||||
|
@ -60,4 +64,5 @@ DEPENDENCIES
|
|||
rake
|
||||
redcarpet
|
||||
rspec
|
||||
simplecov (= 0.5.4)
|
||||
yard
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
Metasploit [![Build Status](https://travis-ci.org/rapid7/metasploit-framework.png)](https://travis-ci.org/rapid7/metasploit-framework)
|
||||
Metasploit [![Build Status](https://travis-ci.org/rapid7/metasploit-framework.png)](https://travis-ci.org/rapid7/metasploit-framework) [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/rapid7/metasploit-framework)
|
||||
==
|
||||
The Metasploit Framework is released under a BSD-style license. See
|
||||
COPYING for more details.
|
||||
|
|
|
@ -133,7 +133,7 @@ module Exploit::Remote::RealPort
|
|||
banner
|
||||
end
|
||||
|
||||
def realport_send(port=0, data)
|
||||
def realport_send(port=0, data="")
|
||||
sock.put( [port].pack("C") + data )
|
||||
end
|
||||
|
||||
|
|
|
@ -323,6 +323,12 @@ module Exploit::Remote::WinRM
|
|||
end
|
||||
end
|
||||
|
||||
def wmi_namespace
|
||||
return datastore['NAMESPACE'] if datastore['NAMESPACE']
|
||||
return @namespace_override if @namespace_override
|
||||
return "/root/cimv2/"
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
|
@ -433,7 +439,7 @@ module Exploit::Remote::WinRM
|
|||
def winrm_uri_action(type)
|
||||
case type
|
||||
when "wql"
|
||||
return %q{<w:ResourceURI mustUnderstand="true">http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/*</w:ResourceURI>
|
||||
return %Q{<w:ResourceURI mustUnderstand="true">http://schemas.microsoft.com/wbem/wsman/1/wmi#{wmi_namespace}*</w:ResourceURI>
|
||||
<a:Action mustUnderstand="true">http://schemas.xmlsoap.org/ws/2004/09/enumeration/Enumerate</a:Action>}
|
||||
when "create_shell"
|
||||
return %q{<w:ResourceURI mustUnderstand="true">http://schemas.microsoft.com/wbem/wsman/1/windows/shell/cmd</w:ResourceURI>
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
# Base error class for all error under {Msf::Modules}
|
||||
class Msf::Modules::Error < StandardError
|
||||
def initialize(attributes={})
|
||||
@module_path = attributes[:module_path]
|
||||
@module_reference_name = attributes[:module_reference_name]
|
||||
|
||||
message_parts = []
|
||||
message_parts << "Failed to load module"
|
||||
|
||||
if module_reference_name or module_path
|
||||
clause_parts = []
|
||||
|
||||
if module_reference_name
|
||||
clause_parts << module_reference_name
|
||||
end
|
||||
|
||||
if module_path
|
||||
clause_parts << "from #{module_path}"
|
||||
end
|
||||
|
||||
clause = clause_parts.join(' ')
|
||||
message_parts << "(#{clause})"
|
||||
end
|
||||
|
||||
causal_message = attributes[:causal_message]
|
||||
|
||||
if causal_message
|
||||
message_parts << "due to #{causal_message}"
|
||||
end
|
||||
|
||||
message = message_parts.join(' ')
|
||||
|
||||
super(message)
|
||||
end
|
||||
|
||||
attr_reader :module_reference_name
|
||||
attr_reader :module_path
|
||||
end
|
|
@ -3,6 +3,7 @@
|
|||
#
|
||||
require 'msf/core/modules/loader'
|
||||
require 'msf/core/modules/namespace'
|
||||
require 'msf/core/modules/metasploit_class_compatibility_error'
|
||||
require 'msf/core/modules/version_compatibility_error'
|
||||
|
||||
# Responsible for loading modules for {Msf::ModuleManager}.
|
||||
|
@ -117,12 +118,17 @@ class Msf::Modules::Loader::Base
|
|||
|
||||
metasploit_class = nil
|
||||
|
||||
module_content = read_module_content(parent_path, type, module_reference_name)
|
||||
|
||||
if module_content.empty?
|
||||
# read_module_content is responsible for calling {#load_error}, so just return here.
|
||||
return false
|
||||
end
|
||||
|
||||
loaded = namespace_module_transaction(type + "/" + module_reference_name, :reload => reload) { |namespace_module|
|
||||
# set the parent_path so that the module can be reloaded with #load_module
|
||||
namespace_module.parent_path = parent_path
|
||||
|
||||
module_content = read_module_content(parent_path, type, module_reference_name)
|
||||
|
||||
begin
|
||||
namespace_module.module_eval_with_lexical_scope(module_content, module_path)
|
||||
# handle interrupts as pass-throughs unlike other Exceptions so users can bail with Ctrl+C
|
||||
|
@ -133,45 +139,33 @@ class Msf::Modules::Loader::Base
|
|||
begin
|
||||
namespace_module.version_compatible!(module_path, module_reference_name)
|
||||
rescue Msf::Modules::VersionCompatibilityError => version_compatibility_error
|
||||
error_message = "Failed to load module (#{module_path}) due to error and #{version_compatibility_error}"
|
||||
load_error(module_path, version_compatibility_error)
|
||||
else
|
||||
error_message = "#{error.class} #{error}"
|
||||
load_error(module_path, error)
|
||||
end
|
||||
|
||||
# record the error message without the backtrace for the console
|
||||
module_manager.module_load_error_by_path[module_path] = error_message
|
||||
|
||||
error_message_with_backtrace = "#{error_message}:\n#{error.backtrace.join("\n")}"
|
||||
elog(error_message_with_backtrace)
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
begin
|
||||
namespace_module.version_compatible!(module_path, module_reference_name)
|
||||
rescue Msf::Modules::VersionCompatibilityError => version_compatibility_error
|
||||
error_message = version_compatibility_error.to_s
|
||||
|
||||
elog(error_message)
|
||||
module_manager.module_load_error_by_path[module_path] = error_message
|
||||
load_error(module_path, version_compatibility_error)
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
metasploit_class = namespace_module.metasploit_class
|
||||
begin
|
||||
metasploit_class = namespace_module.metasploit_class!(module_path, module_reference_name)
|
||||
rescue Msf::Modules::MetasploitClassCompatibilityError => error
|
||||
load_error(module_path, error)
|
||||
|
||||
unless metasploit_class
|
||||
error_message = "Missing Metasploit class constant"
|
||||
|
||||
elog(error_message)
|
||||
module_manager.module_load_error_by_path[module_path] = error_message
|
||||
|
||||
return false
|
||||
return false
|
||||
end
|
||||
|
||||
unless usable?(metasploit_class)
|
||||
ilog(
|
||||
"Skipping module #{module_reference_name} under #{parent_path} because is_usable returned false.",
|
||||
"Skipping module (#{module_reference_name} from #{module_path}) because is_usable returned false.",
|
||||
'core',
|
||||
LEV_1
|
||||
)
|
||||
|
@ -409,6 +403,29 @@ class Msf::Modules::Loader::Base
|
|||
raise ::NotImplementedError
|
||||
end
|
||||
|
||||
# Records the load error to {Msf::ModuleManager::Loading#module_load_error_by_path} and the log.
|
||||
#
|
||||
# @param [String] module_path Path to the module as returned by {#module_path}.
|
||||
# @param [Exception, #class, #to_s, #backtrace] error the error that cause the module not to load.
|
||||
# @return [void]
|
||||
#
|
||||
# @see #module_path
|
||||
def load_error(module_path, error)
|
||||
# module_load_error_by_path does not get the backtrace because the value is echoed to the msfconsole where
|
||||
# backtraces should not appear.
|
||||
module_manager.module_load_error_by_path[module_path] = "#{error.class} #{error}"
|
||||
|
||||
log_lines = []
|
||||
log_lines << "#{module_path} failed to load due to the following error:"
|
||||
log_lines << error.class.to_s
|
||||
log_lines << error.to_s
|
||||
log_lines << "Call stack:"
|
||||
log_lines += error.backtrace
|
||||
|
||||
log_message = log_lines.join("\n")
|
||||
elog(log_message)
|
||||
end
|
||||
|
||||
# @return [Msf::ModuleManager] The module manager for which this loader is loading modules.
|
||||
attr_reader :module_manager
|
||||
|
||||
|
|
|
@ -75,13 +75,17 @@ class Msf::Modules::Loader::Directory < Msf::Modules::Loader::Base
|
|||
|
||||
module_content = ''
|
||||
|
||||
# force to read in binary mode so Pro modules won't be truncated on Windows
|
||||
File.open(full_path, 'rb') do |f|
|
||||
# Pass the size of the file as it leads to faster reads due to fewer buffer resizes. Greatest effect on Windows.
|
||||
# @see http://www.ruby-forum.com/topic/209005
|
||||
# @see https://github.com/ruby/ruby/blob/ruby_1_8_7/io.c#L1205
|
||||
# @see https://github.com/ruby/ruby/blob/ruby_1_9_3/io.c#L2038
|
||||
module_content = f.read(f.stat.size)
|
||||
begin
|
||||
# force to read in binary mode so Pro modules won't be truncated on Windows
|
||||
File.open(full_path, 'rb') do |f|
|
||||
# Pass the size of the file as it leads to faster reads due to fewer buffer resizes. Greatest effect on Windows.
|
||||
# @see http://www.ruby-forum.com/topic/209005
|
||||
# @see https://github.com/ruby/ruby/blob/ruby_1_8_7/io.c#L1205
|
||||
# @see https://github.com/ruby/ruby/blob/ruby_1_9_3/io.c#L2038
|
||||
module_content = f.read(f.stat.size)
|
||||
end
|
||||
rescue Errno::ENOENT => error
|
||||
load_error(full_path, error)
|
||||
end
|
||||
|
||||
module_content
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
require 'msf/core/modules/error'
|
||||
|
||||
# Error raised by {Msf::Modules::Namespace#metasploit_class!} if it cannot the namespace_module does not have a constant
|
||||
# with {Msf::Framework::Major} or lower as a number after 'Metasploit', which indicates a compatible Msf::Module.
|
||||
class Msf::Modules::MetasploitClassCompatibilityError < Msf::Modules::Error
|
||||
def initialize(attributes={})
|
||||
super_attributes = {
|
||||
:causal_message => 'Missing compatible Metasploit<major_version> class constant',
|
||||
}.merge(attributes)
|
||||
|
||||
super(super_attributes)
|
||||
end
|
||||
end
|
|
@ -10,8 +10,6 @@ module Msf::Modules::Namespace
|
|||
# @return [nil] if such as class is not defined.
|
||||
def metasploit_class
|
||||
metasploit_class = nil
|
||||
# don't search ancestors for the metasploit_class
|
||||
#inherit = false
|
||||
|
||||
::Msf::Framework::Major.downto(1) do |major|
|
||||
# Since we really only care about the deepest namespace, we don't
|
||||
|
@ -29,6 +27,19 @@ module Msf::Modules::Namespace
|
|||
metasploit_class
|
||||
end
|
||||
|
||||
def metasploit_class!(module_path, module_reference_name)
|
||||
metasploit_class = self.metasploit_class
|
||||
|
||||
unless metasploit_class
|
||||
raise Msf::Modules::MetasploitClassCompatibilityError.new(
|
||||
:module_path => module_path,
|
||||
:module_reference_name => module_reference_name
|
||||
)
|
||||
end
|
||||
|
||||
metasploit_class
|
||||
end
|
||||
|
||||
# Raises an error unless {Msf::Framework::VersionCore} and {Msf::Framework::VersionAPI} meet the minimum required
|
||||
# versions defined in RequiredVersions in the module content.
|
||||
#
|
||||
|
|
|
@ -1,20 +1,43 @@
|
|||
require 'msf/core/modules/error'
|
||||
|
||||
# Error raised by {Msf::Modules::Namespace#version_compatible!} on {Msf::Modules::Loader::Base#create_namespace_module}
|
||||
# if the API or Core version does not meet the minimum requirements defined in the RequiredVersions constant in the
|
||||
# {Msf::Modules::Loader::Base#read_module_content module content}.
|
||||
class Msf::Modules::VersionCompatibilityError < StandardError
|
||||
class Msf::Modules::VersionCompatibilityError < Msf::Modules::Error
|
||||
# @param [Hash{Symbol => Float}] attributes
|
||||
# @option attributes [Float] :minimum_api_version The minimum {Msf::Framework::VersionAPI} as defined in
|
||||
# RequiredVersions.
|
||||
# @option attributes [Float] :minimum_core_version The minimum {Msf::Framework::VersionCore} as defined in
|
||||
# RequiredVersions.
|
||||
def initialize(attributes={})
|
||||
@module_path = attributes[:module_path]
|
||||
@module_reference_name = attributes[:module_reference_name]
|
||||
@minimum_api_version = attributes[:minimum_api_version]
|
||||
@minimum_core_version = attributes[:minimum_core_version]
|
||||
|
||||
super("Failed to reload module (#{module_reference_name} from #{module_path}) due to version check " \
|
||||
"(requires API:#{minimum_api_version} Core:#{minimum_core_version})")
|
||||
message_parts = []
|
||||
message_parts << 'version check'
|
||||
|
||||
if minimum_api_version or minimum_core_version
|
||||
clause_parts = []
|
||||
|
||||
if minimum_api_version
|
||||
clause_parts << "API >= #{minimum_api_version}"
|
||||
end
|
||||
|
||||
if minimum_core_version
|
||||
clause_parts << "Core >= #{minimum_core_version}"
|
||||
end
|
||||
|
||||
clause = clause_parts.join(' and ')
|
||||
message_parts << "(requires #{clause})"
|
||||
end
|
||||
|
||||
causal_message = message_parts.join(' ')
|
||||
|
||||
super_attributes = {
|
||||
:causal_message => causal_message
|
||||
}.merge(attributes)
|
||||
|
||||
super(super_attributes)
|
||||
end
|
||||
|
||||
# @return [Float] The minimum value of {Msf::Framework::VersionAPI} for the module to be compatible.
|
||||
|
|
|
@ -40,7 +40,8 @@ class Metasploit3 < Msf::Auxiliary
|
|||
[
|
||||
OptString.new('WQL', [ true, "The WQL query to run", "Select Name,Status from Win32_Service" ]),
|
||||
OptString.new('USERNAME', [ true, "The username to authenticate as"]),
|
||||
OptString.new('PASSWORD', [ true, "The password to authenticate with"])
|
||||
OptString.new('PASSWORD', [ true, "The password to authenticate with"]),
|
||||
OptString.new('NAMESPACE', [true, 'The WMI namespace to use for queries', '/root/cimv2/'])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'WinRM VBS Remote Code Execution',
|
||||
'Name' => 'WinRM Script Exec Remote Code Execution',
|
||||
'Description' => %q{
|
||||
This module uses valid credentials to login to the WinRM service
|
||||
and execute a payload. It has two available methods for payload
|
||||
|
|
|
@ -16,7 +16,7 @@ class Metasploit3 < Msf::Post
|
|||
|
||||
def initialize(info={})
|
||||
super( update_info( info,
|
||||
'Name' => 'Windows Manage Process Migration',
|
||||
'Name' => 'Windows Manage Smart Process Migration',
|
||||
'Description' => %q{ This module will migrate a Meterpreter session.
|
||||
It will first attempt to migrate to winlogon.exe . If that fails it will
|
||||
then look at all of the explorer.exe processes. If there is one that exists
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Msf::Modules::Error do
|
||||
context 'instance methods' do
|
||||
context '#initialize' do
|
||||
include_context 'Msf::Modules::Error attributes'
|
||||
|
||||
context 'with :causal_message' do
|
||||
subject do
|
||||
described_class.new(:causal_message => causal_message)
|
||||
end
|
||||
|
||||
it 'should include causal_message in error' do
|
||||
subject.to_s.should == "Failed to load module due to #{causal_message}"
|
||||
end
|
||||
end
|
||||
|
||||
context 'with :causal_message and :module_path' do
|
||||
subject do
|
||||
described_class.new(
|
||||
:causal_message => causal_message,
|
||||
:module_path => module_path
|
||||
)
|
||||
end
|
||||
|
||||
it 'should include causal_message and module_path in error' do
|
||||
subject.to_s.should == "Failed to load module (from #{module_path}) due to #{causal_message}"
|
||||
end
|
||||
end
|
||||
|
||||
context 'with :causal_message and :module_reference_name' do
|
||||
subject do
|
||||
described_class.new(
|
||||
:causal_message => causal_message,
|
||||
:module_reference_name => module_reference_name
|
||||
)
|
||||
end
|
||||
|
||||
it 'should include causal_message and module_reference_name in error' do
|
||||
subject.to_s.should == "Failed to load module (#{module_reference_name}) due to #{causal_message}"
|
||||
end
|
||||
end
|
||||
|
||||
context 'with :causal_message, :module_path, and :module_reference_nam' do
|
||||
subject do
|
||||
described_class.new(
|
||||
:causal_message => causal_message,
|
||||
:module_path => module_path,
|
||||
:module_reference_name => module_reference_name
|
||||
)
|
||||
end
|
||||
|
||||
it 'should include causal_message, module_path, and module_reference_name in error' do
|
||||
subject.to_s.should == "Failed to load module (#{module_reference_name} from #{module_path}) due to #{causal_message}"
|
||||
end
|
||||
end
|
||||
|
||||
context 'with :module_path' do
|
||||
subject do
|
||||
described_class.new(:module_path => module_path)
|
||||
end
|
||||
|
||||
it 'should use :module_path for module_path' do
|
||||
subject.module_path.should == module_path
|
||||
end
|
||||
|
||||
it 'should include module_path in error' do
|
||||
subject.to_s.should == "Failed to load module (from #{module_path})"
|
||||
end
|
||||
end
|
||||
|
||||
context 'with :module_path and :module_reference_name' do
|
||||
subject do
|
||||
described_class.new(
|
||||
:module_path => module_path,
|
||||
:module_reference_name => module_reference_name
|
||||
)
|
||||
end
|
||||
|
||||
it 'should include module_path and module_reference_name in error' do
|
||||
subject.to_s.should == "Failed to load module (#{module_reference_name} from #{module_path})"
|
||||
end
|
||||
end
|
||||
|
||||
context 'with :module_reference_name' do
|
||||
subject do
|
||||
described_class.new(:module_reference_name => module_reference_name)
|
||||
end
|
||||
|
||||
it 'should use :module_reference_name for module_reference_name' do
|
||||
subject.module_reference_name.should == module_reference_name
|
||||
end
|
||||
|
||||
it 'should include module_reference_name in error' do
|
||||
subject.to_s.should == "Failed to load module (#{module_reference_name})"
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
|
@ -3,6 +3,8 @@ require 'spec_helper'
|
|||
require 'msf/core'
|
||||
|
||||
describe Msf::Modules::Loader::Base do
|
||||
include_context 'Msf::Modules::Loader::Base'
|
||||
|
||||
let(:described_class_pathname) do
|
||||
root_pathname.join('lib', 'msf', 'core', 'modules', 'loader', 'base.rb')
|
||||
end
|
||||
|
@ -37,18 +39,6 @@ describe Msf::Modules::Loader::Base do
|
|||
'rspec/mock'
|
||||
end
|
||||
|
||||
let(:parent_path) do
|
||||
parent_pathname.to_s
|
||||
end
|
||||
|
||||
let(:parent_pathname) do
|
||||
root_pathname.join('modules')
|
||||
end
|
||||
|
||||
let(:root_pathname) do
|
||||
Pathname.new(Msf::Config.install_root)
|
||||
end
|
||||
|
||||
let(:type) do
|
||||
Msf::MODULE_AUX
|
||||
end
|
||||
|
@ -230,7 +220,7 @@ describe Msf::Modules::Loader::Base do
|
|||
|
||||
context 'instance methods' do
|
||||
let(:module_manager) do
|
||||
mock('Module Manager')
|
||||
mock('Module Manager', :module_load_error_by_path => {})
|
||||
end
|
||||
|
||||
subject do
|
||||
|
@ -323,13 +313,14 @@ describe Msf::Modules::Loader::Base do
|
|||
end
|
||||
|
||||
it 'should call #namespace_module_transaction with the module full name and :reload => true' do
|
||||
subject.stub(:read_module_content => module_content)
|
||||
|
||||
subject.should_receive(:namespace_module_transaction).with(module_full_name, hash_including(:reload => true))
|
||||
|
||||
subject.load_module(parent_path, type, module_reference_name)
|
||||
end
|
||||
|
||||
it 'should set the parent_path on the namespace_module to match the parent_path passed to #load_module' do
|
||||
module_manager.stub(:module_load_error_by_path => {})
|
||||
module_manager.stub(:on_module_load)
|
||||
|
||||
subject.stub(:read_module_content => module_content)
|
||||
|
@ -339,7 +330,6 @@ describe Msf::Modules::Loader::Base do
|
|||
end
|
||||
|
||||
it 'should call #read_module_content to get the module content so that #read_module_content can be overridden to change loading behavior' do
|
||||
module_manager.stub(:module_load_error_by_path => {})
|
||||
module_manager.stub(:on_module_load)
|
||||
|
||||
subject.should_receive(:read_module_content).with(parent_path, type, module_reference_name).and_return(module_content)
|
||||
|
@ -348,7 +338,6 @@ describe Msf::Modules::Loader::Base do
|
|||
|
||||
it 'should call namespace_module.module_eval_with_lexical_scope with the module_path' do
|
||||
subject.stub(:read_module_content => malformed_module_content)
|
||||
module_manager.stub(:module_load_error_by_path => {})
|
||||
module_manager.stub(:on_module_load)
|
||||
|
||||
# if the module eval error includes the module_path then the module_path was passed along correctly
|
||||
|
@ -356,13 +345,29 @@ describe Msf::Modules::Loader::Base do
|
|||
subject.load_module(parent_path, type, module_reference_name, :reload => true).should be_false
|
||||
end
|
||||
|
||||
context 'with empty module content' do
|
||||
before(:each) do
|
||||
subject.stub(:read_module_content).with(parent_path, type, module_reference_name).and_return('')
|
||||
end
|
||||
|
||||
it 'should return false' do
|
||||
subject.load_module(parent_path, type, module_reference_name).should be_false
|
||||
end
|
||||
|
||||
it 'should not attempt to make a new namespace_module' do
|
||||
subject.should_not_receive(:namespace_module_transaction)
|
||||
subject.load_module(parent_path, type, module_reference_name).should be_false
|
||||
end
|
||||
end
|
||||
|
||||
context 'with errors from namespace_module_eval_with_lexical_scope' do
|
||||
before(:each) do
|
||||
@namespace_module = mock('Namespace Module')
|
||||
@namespace_module.stub(:parent_path=)
|
||||
|
||||
subject.stub(:namespace_module_transaction).and_yield(@namespace_module)
|
||||
subject.stub(:read_module_content)
|
||||
module_content = mock('Module Content', :empty? => false)
|
||||
subject.stub(:read_module_content).and_return(module_content)
|
||||
end
|
||||
|
||||
context 'with Interrupt' do
|
||||
|
@ -409,16 +414,8 @@ describe Msf::Modules::Loader::Base do
|
|||
@namespace_module.stub(:version_compatible!).with(module_path, module_reference_name)
|
||||
end
|
||||
|
||||
it 'should report error class and string in module_manager.module_load_error_by_path' do
|
||||
subject.load_module(parent_path, type, module_reference_name).should be_false
|
||||
@module_load_error_by_path[module_path].should == "#{error_class} #{error}"
|
||||
end
|
||||
|
||||
it 'should report error class, string, and backtrace in the log' do
|
||||
subject.should_receive(:elog).with(
|
||||
# don't use join on backtrace as that will match implementation too closely
|
||||
"#{error_class} #{error}:\n#{backtrace[0]}\n#{backtrace[1]}"
|
||||
)
|
||||
it 'should record the load error using the original error' do
|
||||
subject.should_receive(:load_error).with(module_path, error)
|
||||
subject.load_module(parent_path, type, module_reference_name).should be_false
|
||||
end
|
||||
end
|
||||
|
@ -448,18 +445,8 @@ describe Msf::Modules::Loader::Base do
|
|||
)
|
||||
end
|
||||
|
||||
it 'should report module_path and version compatibility error string in module_manager.module_load_error_by_path' do
|
||||
subject.load_module(parent_path, type, module_reference_name).should be_false
|
||||
|
||||
@module_load_error_by_path[module_path].should include(module_path)
|
||||
@module_load_error_by_path[module_path].should include(version_compatibility_error.to_s)
|
||||
end
|
||||
|
||||
it 'should report backtrace of original error in the log' do
|
||||
formatted_backtrace = "\n#{backtrace[0]}\n#{backtrace[1]}"
|
||||
escaped_backtrace = Regexp.escape(formatted_backtrace)
|
||||
|
||||
subject.should_receive(:elog).with(/#{escaped_backtrace}/)
|
||||
it 'should record the load error using the Msf::Modules::VersionCompatibilityError' do
|
||||
subject.should_receive(:load_error).with(module_path, version_compatibility_error)
|
||||
subject.load_module(parent_path, type, module_reference_name).should be_false
|
||||
end
|
||||
end
|
||||
|
@ -479,7 +466,7 @@ describe Msf::Modules::Loader::Base do
|
|||
@namespace_module.stub(:module_eval_with_lexical_scope).with(module_content, module_path)
|
||||
|
||||
metasploit_class = mock('Metasploit Class', :parent => @namespace_module)
|
||||
@namespace_module.stub(:metasploit_class => metasploit_class)
|
||||
@namespace_module.stub(:metasploit_class! => metasploit_class)
|
||||
|
||||
subject.stub(:namespace_module_transaction).and_yield(@namespace_module)
|
||||
|
||||
|
@ -521,13 +508,8 @@ describe Msf::Modules::Loader::Base do
|
|||
)
|
||||
end
|
||||
|
||||
it 'should report error in module_manage.module_load_error_by_path' do
|
||||
subject.load_module(parent_path, type, module_reference_name).should be_false
|
||||
@module_load_error_by_path[module_path].should == version_compatibility_error.to_s
|
||||
end
|
||||
|
||||
it 'should log error' do
|
||||
subject.should_receive(:elog).with(version_compatibility_error.to_s)
|
||||
it 'should record the load error' do
|
||||
subject.should_receive(:load_error).with(module_path, version_compatibility_error)
|
||||
subject.load_module(parent_path, type, module_reference_name).should be_false
|
||||
end
|
||||
|
||||
|
@ -548,24 +530,27 @@ describe Msf::Modules::Loader::Base do
|
|||
end
|
||||
|
||||
context 'without metasploit_class' do
|
||||
let(:error) do
|
||||
Msf::Modules::MetasploitClassCompatibilityError.new(
|
||||
:module_path => module_path,
|
||||
:module_reference_name => module_reference_name
|
||||
)
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
@namespace_module.stub(:metasploit_class).and_return(nil)
|
||||
@namespace_module.stub(:metasploit_class!).with(module_path, module_reference_name).and_raise(error)
|
||||
end
|
||||
|
||||
let(:error_message) do
|
||||
'Missing Metasploit class constant'
|
||||
end
|
||||
|
||||
it 'should log missing Metasploit class' do
|
||||
subject.should_receive(:elog).with(error_message)
|
||||
it 'should record load error' do
|
||||
subject.should_receive(
|
||||
:load_error
|
||||
).with(
|
||||
module_path,
|
||||
kind_of(Msf::Modules::MetasploitClassCompatibilityError)
|
||||
)
|
||||
subject.load_module(parent_path, type, module_reference_name).should be_false
|
||||
end
|
||||
|
||||
it 'should record error in module_manager.module_load_error_by_path' do
|
||||
subject.load_module(parent_path, type, module_reference_name).should be_false
|
||||
@module_load_error_by_path[module_path].should == error_message
|
||||
end
|
||||
|
||||
it 'should return false' do
|
||||
subject.load_module(parent_path, type, module_reference_name).should be_false
|
||||
end
|
||||
|
@ -583,7 +568,7 @@ describe Msf::Modules::Loader::Base do
|
|||
end
|
||||
|
||||
before(:each) do
|
||||
@namespace_module.stub(:metasploit_class => metasploit_class)
|
||||
@namespace_module.stub(:metasploit_class! => metasploit_class)
|
||||
end
|
||||
|
||||
it 'should check if it is usable' do
|
||||
|
|
|
@ -2,6 +2,126 @@ require 'spec_helper'
|
|||
require 'msf/core'
|
||||
require 'msf/core/modules/loader/directory'
|
||||
|
||||
describe Msf::Modules::Loader::Directory do
|
||||
require 'msf/core'
|
||||
|
||||
describe Msf::Modules::Loader::Directory do
|
||||
context 'instance methods' do
|
||||
include_context 'Msf::Modules::Loader::Base'
|
||||
|
||||
let(:module_manager) do
|
||||
mock('Module Manager')
|
||||
end
|
||||
|
||||
let(:module_path) do
|
||||
"#{parent_path}/exploits/#{module_reference_name}.rb"
|
||||
end
|
||||
|
||||
let(:type) do
|
||||
'exploit'
|
||||
end
|
||||
|
||||
subject do
|
||||
described_class.new(module_manager)
|
||||
end
|
||||
|
||||
context '#load_module' do
|
||||
context 'with existent module_path' do
|
||||
let(:framework) do
|
||||
framework = mock('Msf::Framework', :datastore => {})
|
||||
|
||||
events = mock('Events')
|
||||
events.stub(:on_module_load)
|
||||
events.stub(:on_module_created)
|
||||
framework.stub(:events => events)
|
||||
|
||||
framework
|
||||
end
|
||||
|
||||
let(:module_full_name) do
|
||||
"#{type}/#{module_reference_name}"
|
||||
end
|
||||
|
||||
let(:module_manager) do
|
||||
Msf::ModuleManager.new(framework)
|
||||
end
|
||||
|
||||
let(:module_reference_name) do
|
||||
'windows/smb/ms08_067_netapi'
|
||||
end
|
||||
|
||||
it 'should load a module that can be created' do
|
||||
subject.load_module(parent_path, type, module_reference_name).should be_true
|
||||
|
||||
created_module = module_manager.create(module_full_name)
|
||||
|
||||
created_module.name.should == 'Microsoft Server Service Relative Path Stack Corruption'
|
||||
end
|
||||
end
|
||||
|
||||
context 'without existent module_path' do
|
||||
let(:module_reference_name) do
|
||||
'osx/armle/safari_libtiff'
|
||||
end
|
||||
|
||||
let(:error) do
|
||||
Errno::ENOENT.new(module_path)
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
module_manager.stub(:file_changed? => true)
|
||||
module_manager.stub(:module_load_error_by_path => {})
|
||||
end
|
||||
|
||||
it 'should not raise an error' do
|
||||
File.exist?(module_path).should be_false
|
||||
|
||||
expect {
|
||||
subject.load_module(parent_path, type, module_reference_name)
|
||||
}.to_not raise_error
|
||||
end
|
||||
|
||||
it 'should return false' do
|
||||
File.exist?(module_path).should be_false
|
||||
|
||||
subject.load_module(parent_path, type, module_reference_name).should be_false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context '#read_module_content' do
|
||||
context 'with non-existent module_path' do
|
||||
let(:module_reference_name) do
|
||||
'osx/armle/safari_libtiff'
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
subject.stub(:load_error).with(module_path, kind_of(Errno::ENOENT))
|
||||
end
|
||||
|
||||
# this ensures that the File.exist?(module_path) checks are checking the same path as the code under test
|
||||
it 'should attempt to open the expected module_path' do
|
||||
File.should_receive(:open).with(module_path, 'rb')
|
||||
File.exist?(module_path).should be_false
|
||||
|
||||
subject.send(:read_module_content, parent_path, type, module_reference_name)
|
||||
end
|
||||
|
||||
it 'should not raise an error' do
|
||||
expect {
|
||||
subject.send(:read_module_content, parent_path, type, module_reference_name)
|
||||
}.to_not raise_error
|
||||
end
|
||||
|
||||
it 'should return an empty string' do
|
||||
subject.send(:read_module_content, parent_path, type, module_reference_name).should == ''
|
||||
end
|
||||
|
||||
it 'should record the load error' do
|
||||
subject.should_receive(:load_error).with(module_path, kind_of(Errno::ENOENT))
|
||||
|
||||
subject.send(:read_module_content, parent_path, type, module_reference_name).should == ''
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
require 'spec_helper'
|
||||
|
||||
require 'msf/core/modules/metasploit_class_compatibility_error'
|
||||
|
||||
describe Msf::Modules::MetasploitClassCompatibilityError do
|
||||
it_should_behave_like 'Msf::Modules::Error subclass #initialize'
|
||||
end
|
|
@ -0,0 +1,267 @@
|
|||
require 'spec_helper'
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/core/modules/namespace'
|
||||
|
||||
describe Msf::Modules::Namespace do
|
||||
let(:module_path) do
|
||||
"parent/path/type_directory/#{module_reference_name}.rb"
|
||||
end
|
||||
|
||||
let(:module_reference_name) do
|
||||
'module/reference/name'
|
||||
end
|
||||
|
||||
subject do
|
||||
mod = Module.new
|
||||
mod.extend described_class
|
||||
|
||||
mod
|
||||
end
|
||||
|
||||
context 'metasploit_class' do
|
||||
before(:each) do
|
||||
if major
|
||||
subject.const_set("Metasploit#{major}", Class.new)
|
||||
end
|
||||
end
|
||||
|
||||
context 'without Metasploit<n> constant defined' do
|
||||
let(:major) do
|
||||
nil
|
||||
end
|
||||
|
||||
it 'should not be defined' do
|
||||
metasploit_constants = subject.constants.select { |constant|
|
||||
constant.to_s =~ /Metasploit/
|
||||
}
|
||||
|
||||
metasploit_constants.should be_empty
|
||||
end
|
||||
end
|
||||
|
||||
context 'with Metasploit1 constant defined' do
|
||||
let(:major) do
|
||||
1
|
||||
end
|
||||
|
||||
it 'should be defined' do
|
||||
subject.const_defined?('Metasploit1').should be_true
|
||||
end
|
||||
|
||||
it 'should return the class' do
|
||||
subject.metasploit_class.should be_a Class
|
||||
end
|
||||
end
|
||||
|
||||
context 'with Metasploit2 constant defined' do
|
||||
let(:major) do
|
||||
2
|
||||
end
|
||||
|
||||
it 'should be defined' do
|
||||
subject.const_defined?('Metasploit2').should be_true
|
||||
end
|
||||
|
||||
it 'should return the class' do
|
||||
subject.metasploit_class.should be_a Class
|
||||
end
|
||||
end
|
||||
|
||||
context 'with Metasploit3 constant defined' do
|
||||
let(:major) do
|
||||
3
|
||||
end
|
||||
|
||||
it 'should be defined' do
|
||||
subject.const_defined?('Metasploit3').should be_true
|
||||
end
|
||||
|
||||
it 'should return the class' do
|
||||
subject.metasploit_class.should be_a Class
|
||||
end
|
||||
end
|
||||
|
||||
context 'with Metasploit4 constant defined' do
|
||||
let(:major) do
|
||||
4
|
||||
end
|
||||
|
||||
it 'should be defined' do
|
||||
subject.const_defined?('Metasploit4').should be_true
|
||||
end
|
||||
|
||||
it 'should return the class' do
|
||||
subject.metasploit_class.should be_a Class
|
||||
end
|
||||
end
|
||||
|
||||
context 'with Metasploit5 constant defined' do
|
||||
let(:major) do
|
||||
5
|
||||
end
|
||||
|
||||
it 'should be defined' do
|
||||
subject.const_defined?('Metasploit5').should be_true
|
||||
end
|
||||
|
||||
it 'should be newer than Msf::Framework::Major' do
|
||||
major.should > Msf::Framework::Major
|
||||
end
|
||||
|
||||
it 'should return nil' do
|
||||
subject.metasploit_class.should be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'metasploit_class!' do
|
||||
it 'should call metasploit_class' do
|
||||
subject.should_receive(:metasploit_class).and_return(Class.new)
|
||||
|
||||
subject.metasploit_class!(module_path, module_reference_name)
|
||||
end
|
||||
|
||||
context 'with metasploit_class' do
|
||||
let(:metasploit_class) do
|
||||
Class.new
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
subject.stub(:metasploit_class => metasploit_class)
|
||||
end
|
||||
|
||||
it 'should return the metasploit_class' do
|
||||
subject.metasploit_class!(module_path, module_reference_name).should == metasploit_class
|
||||
end
|
||||
end
|
||||
|
||||
context 'without metasploit_class' do
|
||||
before(:each) do
|
||||
subject.stub(:metasploit_class => nil)
|
||||
end
|
||||
|
||||
it 'should raise a Msf::Modules::MetasploitClassCompatibilityError' do
|
||||
expect {
|
||||
subject.metasploit_class!(module_path, module_reference_name)
|
||||
}.to raise_error(Msf::Modules::MetasploitClassCompatibilityError)
|
||||
end
|
||||
|
||||
context 'the Msf::Modules::MetasploitClassCompatibilityError' do
|
||||
it 'should include the module path' do
|
||||
error = nil
|
||||
|
||||
begin
|
||||
subject.metasploit_class!(module_path, module_reference_name)
|
||||
rescue Msf::Modules::MetasploitClassCompatibilityError => error
|
||||
end
|
||||
|
||||
error.should_not be_nil
|
||||
error.to_s.should include(module_path)
|
||||
end
|
||||
|
||||
it 'should include the module reference name' do
|
||||
error = nil
|
||||
|
||||
begin
|
||||
subject.metasploit_class!(module_path, module_reference_name)
|
||||
rescue Msf::Modules::MetasploitClassCompatibilityError => error
|
||||
end
|
||||
|
||||
error.should_not be_nil
|
||||
error.to_s.should include(module_reference_name)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'version_compatible!' do
|
||||
context 'without RequiredVersions' do
|
||||
it 'should not be defined' do
|
||||
subject.const_defined?('RequiredVersions').should be_false
|
||||
end
|
||||
|
||||
it 'should not raise an error' do
|
||||
expect {
|
||||
subject.version_compatible!(module_path, module_reference_name)
|
||||
}.to_not raise_error
|
||||
end
|
||||
end
|
||||
|
||||
context 'with RequiredVersions defined' do
|
||||
let(:minimum_api_version) do
|
||||
1
|
||||
end
|
||||
|
||||
let(:minimum_core_version) do
|
||||
1
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
subject.const_set(
|
||||
:RequiredVersions,
|
||||
[
|
||||
minimum_core_version,
|
||||
minimum_api_version
|
||||
]
|
||||
)
|
||||
end
|
||||
|
||||
context 'with minimum Core version' do
|
||||
it 'should be <= Msf::Framework::VersionCore' do
|
||||
minimum_core_version.should <= Msf::Framework::VersionCore
|
||||
end
|
||||
|
||||
context 'without minimum API version' do
|
||||
let(:minimum_api_version) do
|
||||
2
|
||||
end
|
||||
|
||||
it 'should be > Msf::Framework::VersionAPI' do
|
||||
minimum_api_version.should > Msf::Framework::VersionAPI
|
||||
end
|
||||
|
||||
it_should_behave_like 'Msf::Modules::VersionCompatibilityError'
|
||||
end
|
||||
|
||||
context 'with minimum API version' do
|
||||
it 'should not raise an error' do
|
||||
expect {
|
||||
subject.version_compatible!(module_path, module_reference_name)
|
||||
}.to_not raise_error(Msf::Modules::VersionCompatibilityError)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'without minimum Core version' do
|
||||
let(:minimum_core_version) do
|
||||
5
|
||||
end
|
||||
|
||||
it 'should be > Msf::Framework::VersionCore' do
|
||||
minimum_core_version.should > Msf::Framework::VersionCore
|
||||
end
|
||||
|
||||
context 'without minimum API version' do
|
||||
let(:minimum_api_version) do
|
||||
2
|
||||
end
|
||||
|
||||
it 'should be > Msf::Framework::VersionAPI' do
|
||||
minimum_api_version.should > Msf::Framework::VersionAPI
|
||||
end
|
||||
|
||||
it_should_behave_like 'Msf::Modules::VersionCompatibilityError'
|
||||
end
|
||||
|
||||
context 'with minimum API version' do
|
||||
it 'should be <= Msf::Framework::VersionAPI' do
|
||||
minimum_api_version <= Msf::Framework::VersionAPI
|
||||
end
|
||||
|
||||
it_should_behave_like 'Msf::Modules::VersionCompatibilityError'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,62 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Msf::Modules::VersionCompatibilityError do
|
||||
it_should_behave_like 'Msf::Modules::Error subclass #initialize' do
|
||||
let(:minimum_api_version) do
|
||||
1
|
||||
end
|
||||
|
||||
let(:minimum_core_version) do
|
||||
2
|
||||
end
|
||||
|
||||
it 'should say cause was version check' do
|
||||
subject.to_s.should match(/due to version check/)
|
||||
end
|
||||
|
||||
context 'with :minimum_api_version' do
|
||||
subject do
|
||||
described_class.new(
|
||||
:minimum_api_version => minimum_api_version
|
||||
)
|
||||
end
|
||||
|
||||
it 'should set minimum_api_version' do
|
||||
subject.minimum_api_version.should == minimum_api_version
|
||||
end
|
||||
|
||||
it 'should include minimum_api_version in error' do
|
||||
subject.to_s.should match(/due to version check \(requires API >= #{minimum_api_version}\)/)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with :minimum_api_version and :minimum_core_version' do
|
||||
subject do
|
||||
described_class.new(
|
||||
:minimum_api_version => minimum_api_version,
|
||||
:minimum_core_version => minimum_core_version
|
||||
)
|
||||
end
|
||||
|
||||
it 'should include minimum_api_version and minimum_core_version in error' do
|
||||
subject.to_s.should match(/due to version check \(requires API >= #{minimum_api_version} and Core >= #{minimum_core_version}\)/)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with :minimum_core_version' do
|
||||
subject do
|
||||
described_class.new(
|
||||
:minimum_core_version => minimum_core_version
|
||||
)
|
||||
end
|
||||
|
||||
it 'should set minimum_core_version' do
|
||||
subject.minimum_core_version.should == minimum_core_version
|
||||
end
|
||||
|
||||
it 'should include minimum_core_version in error' do
|
||||
subject.to_s.should match(/due to version check \(requires Core >= #{minimum_core_version}\)/)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -8,6 +8,11 @@ root_pathname = spec_pathname.join('..').expand_path
|
|||
lib_pathname = root_pathname.join('lib')
|
||||
$LOAD_PATH.unshift(lib_pathname.to_s)
|
||||
|
||||
# must be first require and started before any other requires so that it can measure coverage of all following required
|
||||
# code. It is after the rubygems and bundler only because Bundler.setup supplies the LOAD_PATH to simplecov.
|
||||
require 'simplecov'
|
||||
SimpleCov.start
|
||||
|
||||
require 'rspec/core'
|
||||
|
||||
# Requires supporting ruby files with custom matchers and macros, etc,
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
shared_context 'Msf::Modules::Error attributes' do
|
||||
let(:causal_message) do
|
||||
'rspec'
|
||||
end
|
||||
|
||||
let(:module_path) do
|
||||
"parent/path/type/#{module_reference_name}.rb"
|
||||
end
|
||||
|
||||
let(:module_reference_name) do
|
||||
'module/reference/name'
|
||||
end
|
||||
end
|
|
@ -0,0 +1,13 @@
|
|||
shared_context "Msf::Modules::Loader::Base" do
|
||||
let(:parent_path) do
|
||||
parent_pathname.to_s
|
||||
end
|
||||
|
||||
let(:parent_pathname) do
|
||||
root_pathname.join('modules')
|
||||
end
|
||||
|
||||
let(:root_pathname) do
|
||||
Pathname.new(Msf::Config.install_root)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,26 @@
|
|||
shared_examples_for 'Msf::Modules::Error subclass #initialize' do
|
||||
context 'instance methods' do
|
||||
context '#initialize' do
|
||||
include_context 'Msf::Modules::Error attributes'
|
||||
|
||||
subject do
|
||||
described_class.new(
|
||||
:module_path => module_path,
|
||||
:module_reference_name => module_reference_name
|
||||
)
|
||||
end
|
||||
|
||||
it 'should include causal message in error' do
|
||||
subject.to_s.should match(/due to .*/)
|
||||
end
|
||||
|
||||
it 'should set module_path' do
|
||||
subject.module_path.should == module_path
|
||||
end
|
||||
|
||||
it 'should set module_reference_name' do
|
||||
subject.module_reference_name.should == module_reference_name
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,32 @@
|
|||
shared_examples_for 'Msf::Modules::VersionCompatibilityError' do
|
||||
let(:error) do
|
||||
begin
|
||||
subject.version_compatible!(module_path, module_reference_name)
|
||||
rescue Msf::Modules::VersionCompatibilityError => error
|
||||
end
|
||||
|
||||
error
|
||||
end
|
||||
|
||||
it 'should be raised' do
|
||||
expect {
|
||||
subject.version_compatible!(module_path, module_reference_name)
|
||||
}.to raise_error(Msf::Modules::VersionCompatibilityError)
|
||||
end
|
||||
|
||||
it 'should include minimum API version' do
|
||||
error.to_s.should include(minimum_api_version.to_s)
|
||||
end
|
||||
|
||||
it 'should include minimum Core version' do
|
||||
error.to_s.should include(minimum_core_version.to_s)
|
||||
end
|
||||
|
||||
it 'should include module path' do
|
||||
error.to_s.should include(module_path)
|
||||
end
|
||||
|
||||
it 'should include module reference name' do
|
||||
error.to_s.should include(module_reference_name)
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue