Retab all the things (except external/)
This commit is contained in:
+17
-17
@@ -1,23 +1,23 @@
|
||||
shared_examples_for 'Msf::DBManager::Export#extract_module_detail_info module_detail child' do |child_node_name|
|
||||
attribute_name = child_node_name.underscore
|
||||
attribute_name = child_node_name.underscore
|
||||
|
||||
subject(:child_node) do
|
||||
module_detail_node.at_xpath(child_node_name)
|
||||
end
|
||||
subject(:child_node) do
|
||||
module_detail_node.at_xpath(child_node_name)
|
||||
end
|
||||
|
||||
let(:attribute) do
|
||||
module_detail.send(attribute_name)
|
||||
end
|
||||
let(:attribute) do
|
||||
module_detail.send(attribute_name)
|
||||
end
|
||||
|
||||
it "should not have Mdm::Module::Detail##{attribute_name} nil" do
|
||||
attribute.should_not be_nil
|
||||
end
|
||||
it "should not have Mdm::Module::Detail##{attribute_name} nil" do
|
||||
attribute.should_not be_nil
|
||||
end
|
||||
|
||||
it "should have Mdm::Module::Detail##{attribute_name} for #{child_node_name} content" do
|
||||
if attribute == false
|
||||
child_node.content.should be_blank
|
||||
else
|
||||
child_node.content.should == attribute.to_s
|
||||
end
|
||||
end
|
||||
it "should have Mdm::Module::Detail##{attribute_name} for #{child_node_name} content" do
|
||||
if attribute == false
|
||||
child_node.content.should be_blank
|
||||
else
|
||||
child_node.content.should == attribute.to_s
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -2,1173 +2,1173 @@
|
||||
require 'builder'
|
||||
|
||||
shared_examples_for 'Msf::DBManager::ImportMsfXml' do
|
||||
# Serialized format from pro/modules/auxiliary/pro/report.rb
|
||||
def serialize(object)
|
||||
# FIXME https://www.pivotaltracker.com/story/show/46578647
|
||||
marshalled = Marshal.dump(object)
|
||||
base64_encoded = [marshalled].pack('m')
|
||||
compact = base64_encoded.gsub(/\s+/, '')
|
||||
|
||||
compact
|
||||
end
|
||||
|
||||
def with_info
|
||||
db_manager.should_receive(:import_msf_web_element) do |*args, &specialization|
|
||||
info = specialization.call(element, options)
|
||||
|
||||
yield info
|
||||
end
|
||||
|
||||
subject
|
||||
end
|
||||
|
||||
let(:allow_yaml) do
|
||||
false
|
||||
end
|
||||
|
||||
let(:document) do
|
||||
REXML::Document.new(source)
|
||||
end
|
||||
|
||||
let(:element) do
|
||||
nil
|
||||
end
|
||||
|
||||
let(:host_attributes) do
|
||||
FactoryGirl.attributes_for(:mdm_host)
|
||||
end
|
||||
|
||||
let(:msf_web_text_element_names) do
|
||||
[
|
||||
'created-at',
|
||||
'host',
|
||||
'path',
|
||||
'port',
|
||||
'query',
|
||||
'ssl',
|
||||
'updated-at',
|
||||
'vhost'
|
||||
]
|
||||
end
|
||||
|
||||
let(:notifier) do
|
||||
lambda do |event, data|
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
let(:options) do
|
||||
{
|
||||
:allow_yaml => allow_yaml,
|
||||
:workspace => workspace
|
||||
}
|
||||
end
|
||||
|
||||
let(:service_attributes) do
|
||||
FactoryGirl.attributes_for(:web_service)
|
||||
end
|
||||
|
||||
let(:web_form_attributes) do
|
||||
FactoryGirl.attributes_for(:mdm_web_form, :exported)
|
||||
end
|
||||
|
||||
let(:web_page_attributes) do
|
||||
FactoryGirl.attributes_for(:mdm_web_page)
|
||||
end
|
||||
|
||||
let(:workspace) do
|
||||
nil
|
||||
end
|
||||
|
||||
let(:xml) do
|
||||
Builder::XmlMarkup.new(:indent => 2)
|
||||
end
|
||||
|
||||
it 'should include methods from module so method can be overridden easier in pro' do
|
||||
db_manager.should be_a Msf::DBManager::ImportMsfXml
|
||||
end
|
||||
|
||||
context 'CONSTANTS' do
|
||||
it 'should define MSF_WEB_PAGE_TEXT_ELEMENT_NAMES in any order' do
|
||||
described_class::MSF_WEB_PAGE_TEXT_ELEMENT_NAMES =~ [
|
||||
'auth',
|
||||
'body',
|
||||
'code',
|
||||
'cookie',
|
||||
'ctype',
|
||||
'location',
|
||||
'mtime'
|
||||
]
|
||||
end
|
||||
|
||||
it 'should define MSF_WEB_TEXT_ELEMENT_NAMES in any order' do
|
||||
described_class::MSF_WEB_TEXT_ELEMENT_NAMES =~ msf_web_text_element_names
|
||||
end
|
||||
|
||||
it 'should define MSF_WEB_VULN_TEXT_ELEMENT_NAMES in any order' do
|
||||
described_class::MSF_WEB_VULN_TEXT_ELEMENT_NAMES =~ [
|
||||
'blame',
|
||||
'category',
|
||||
'confidence',
|
||||
'description',
|
||||
'method',
|
||||
'name',
|
||||
'pname',
|
||||
'proof',
|
||||
'risk'
|
||||
]
|
||||
end
|
||||
end
|
||||
|
||||
context '#check_msf_xml_version!' do
|
||||
let(:root_tag) do
|
||||
'root'
|
||||
end
|
||||
|
||||
let(:source) do
|
||||
xml.tag!(root_tag)
|
||||
|
||||
xml.target!
|
||||
end
|
||||
|
||||
subject(:metadata) do
|
||||
db_manager.send(:check_msf_xml_version!, document)
|
||||
end
|
||||
|
||||
it_should_behave_like(
|
||||
'Msf::DBManager::ImportMsfXml#check_msf_xml_version! with root tag',
|
||||
'MetasploitExpressV1',
|
||||
:allow_yaml => true
|
||||
)
|
||||
|
||||
it_should_behave_like(
|
||||
'Msf::DBManager::ImportMsfXml#check_msf_xml_version! with root tag',
|
||||
'MetasploitExpressV2',
|
||||
:allow_yaml => true
|
||||
)
|
||||
|
||||
it_should_behave_like(
|
||||
'Msf::DBManager::ImportMsfXml#check_msf_xml_version! with root tag',
|
||||
'MetasploitExpressV3',
|
||||
:allow_yaml => false
|
||||
)
|
||||
|
||||
it_should_behave_like(
|
||||
'Msf::DBManager::ImportMsfXml#check_msf_xml_version! with root tag',
|
||||
'MetasploitExpressV4',
|
||||
:allow_yaml => false
|
||||
)
|
||||
|
||||
context 'with other' do
|
||||
it 'should raise DBImportError' do
|
||||
expect {
|
||||
metadata
|
||||
}.to raise_error(
|
||||
Msf::DBImportError,
|
||||
'Unsupported Metasploit XML document format'
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context '#import_msf_text_element' do
|
||||
let(:parent_element) do
|
||||
document.root
|
||||
end
|
||||
|
||||
let(:child_name) do
|
||||
'child'
|
||||
end
|
||||
|
||||
let(:child_sym) do
|
||||
child_name.to_sym
|
||||
end
|
||||
|
||||
subject(:info) do
|
||||
db_manager.send(:import_msf_text_element, parent_element, child_name)
|
||||
end
|
||||
|
||||
context 'with child element' do
|
||||
let(:source) do
|
||||
xml.parent do
|
||||
xml.tag!(child_name, text)
|
||||
end
|
||||
|
||||
xml.target!
|
||||
end
|
||||
|
||||
context 'with padded text' do
|
||||
let(:stripped) do
|
||||
'stripped'
|
||||
end
|
||||
|
||||
let(:text) do
|
||||
" #{stripped} "
|
||||
end
|
||||
|
||||
it 'should strip text' do
|
||||
info[:child].should == stripped
|
||||
end
|
||||
end
|
||||
|
||||
context 'with NULL text' do
|
||||
let(:text) do
|
||||
'NULL'
|
||||
end
|
||||
|
||||
it 'should have nil for child name in info' do
|
||||
# use have_key to verify info isn't just returning hash default of
|
||||
# `nil`.
|
||||
info.should have_key(child_sym)
|
||||
info[child_sym].should be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'without NULL text' do
|
||||
let(:text) do
|
||||
'some text'
|
||||
end
|
||||
|
||||
it 'should have text for child name in info' do
|
||||
info[child_sym].should == text
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'without child element' do
|
||||
let(:source) do
|
||||
xml.parent
|
||||
|
||||
xml.target!
|
||||
end
|
||||
|
||||
it 'should return an empty Hash' do
|
||||
info.should == {}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'import_msf_web_element' do
|
||||
let(:element) do
|
||||
document.root
|
||||
end
|
||||
|
||||
let(:options) do
|
||||
{}
|
||||
end
|
||||
|
||||
let(:specialization) do
|
||||
lambda { |element, options|
|
||||
{}
|
||||
}
|
||||
end
|
||||
|
||||
subject(:import_msf_web_element) do
|
||||
db_manager.send(
|
||||
:import_msf_web_element,
|
||||
element,
|
||||
options,
|
||||
&specialization
|
||||
)
|
||||
end
|
||||
|
||||
context 'with :type' do
|
||||
include_context 'DatabaseCleaner'
|
||||
|
||||
let(:source) do
|
||||
xml.tag!("web_#{type}") do
|
||||
web_site = web_vuln.web_site
|
||||
service = web_site.service
|
||||
|
||||
xml.host(service.host.address)
|
||||
xml.path(web_vuln.path)
|
||||
xml.port(service.port)
|
||||
xml.query(web_vuln.query)
|
||||
|
||||
ssl = false
|
||||
|
||||
if service.name == 'https'
|
||||
ssl = true
|
||||
end
|
||||
|
||||
xml.ssl(ssl)
|
||||
|
||||
xml.vhost(web_site.vhost)
|
||||
end
|
||||
|
||||
xml.target!
|
||||
end
|
||||
|
||||
let(:type) do
|
||||
:vuln
|
||||
end
|
||||
|
||||
let(:web_vuln) do
|
||||
FactoryGirl.create(:mdm_web_vuln)
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
db_manager.stub(
|
||||
:report_web_vuln
|
||||
).with(
|
||||
an_instance_of(Hash)
|
||||
)
|
||||
|
||||
options[:type] = type
|
||||
end
|
||||
|
||||
context 'with :workspace' do
|
||||
let(:workspace) do
|
||||
double(':workspace')
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
options[:workspace] = workspace
|
||||
end
|
||||
|
||||
it 'should not call Msf::DBManager#workspace' do
|
||||
db_manager.should_not_receive(:workspace)
|
||||
|
||||
import_msf_web_element
|
||||
end
|
||||
|
||||
it 'should pass :workspace to report_web_<:type>' do
|
||||
db_manager.should_receive(
|
||||
"report_web_#{type}"
|
||||
).with(
|
||||
hash_including(:workspace => workspace)
|
||||
)
|
||||
|
||||
import_msf_web_element
|
||||
end
|
||||
end
|
||||
|
||||
context 'without :workspace' do
|
||||
let(:workspace) do
|
||||
FactoryGirl.create(:mdm_workspace)
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
db_manager.workspace = workspace
|
||||
end
|
||||
|
||||
it 'should call Msf::DBManager#workspace' do
|
||||
db_manager.should_receive(:workspace).and_call_original
|
||||
|
||||
import_msf_web_element
|
||||
end
|
||||
|
||||
it 'should pass Msf::DBManager#workspace to report_web_<:type>' do
|
||||
db_manager.should_receive(
|
||||
"report_web_#{type}"
|
||||
).with(
|
||||
hash_including(:workspace => workspace)
|
||||
)
|
||||
|
||||
import_msf_web_element
|
||||
end
|
||||
end
|
||||
|
||||
it 'should import all elements in MSF_WEB_TEXT_ELEMENT_NAMES with #import_msf_text_element' do
|
||||
msf_web_text_element_names.each do |name|
|
||||
db_manager.should_receive(
|
||||
:import_msf_text_element
|
||||
).with(
|
||||
element,
|
||||
name
|
||||
).and_call_original
|
||||
end
|
||||
|
||||
import_msf_web_element
|
||||
end
|
||||
|
||||
context 'with non-empty Hash from #import_msf_text_element' do
|
||||
let(:returned_hash) do
|
||||
{
|
||||
:host => '192.168.0.1'
|
||||
}
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
db_manager.stub(:import_msf_text_element).and_return(returned_hash)
|
||||
end
|
||||
|
||||
it 'should pass returned Hash as part of Hash passed to report_web_<:type' do
|
||||
db_manager.should_receive(
|
||||
"report_web_#{type}"
|
||||
).with(
|
||||
hash_including(returned_hash)
|
||||
)
|
||||
|
||||
import_msf_web_element
|
||||
end
|
||||
end
|
||||
|
||||
context 'ssl element' do
|
||||
context 'without element' do
|
||||
let(:source) do
|
||||
xml.tag!("web_#{type}")
|
||||
|
||||
xml.target!
|
||||
end
|
||||
|
||||
it 'should pass false for :ssl to report_web_<:type>' do
|
||||
db_manager.should_receive(
|
||||
"report_web_#{type}"
|
||||
).with(
|
||||
hash_including(:ssl => false)
|
||||
)
|
||||
|
||||
import_msf_web_element
|
||||
end
|
||||
end
|
||||
|
||||
context 'with element' do
|
||||
let(:source) do
|
||||
xml.tag!("web_#{type}") do
|
||||
xml.ssl(ssl)
|
||||
end
|
||||
|
||||
xml.target!
|
||||
end
|
||||
|
||||
context "with 'true' text" do
|
||||
let(:ssl) do
|
||||
true
|
||||
end
|
||||
|
||||
it 'should pass true for :ssl to report_web_<:type>' do
|
||||
db_manager.should_receive(
|
||||
"report_web_#{type}"
|
||||
).with(
|
||||
hash_including(:ssl => true)
|
||||
)
|
||||
|
||||
import_msf_web_element
|
||||
end
|
||||
end
|
||||
|
||||
context "without 'true' text" do
|
||||
let(:ssl) do
|
||||
false
|
||||
end
|
||||
|
||||
it 'should pass false for :ssl to report_web_<:type>' do
|
||||
db_manager.should_receive(
|
||||
"report_web_#{type}"
|
||||
).with(
|
||||
hash_including(:ssl => false)
|
||||
)
|
||||
|
||||
import_msf_web_element
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'specialization block' do
|
||||
let(:returned_hash) do
|
||||
{
|
||||
:specialized => double('Value')
|
||||
}
|
||||
end
|
||||
|
||||
let(:specialization) do
|
||||
lambda { |element, option|
|
||||
returned_hash
|
||||
}
|
||||
end
|
||||
|
||||
it 'should be called with element and options' do
|
||||
actual_args = []
|
||||
|
||||
db_manager.send(
|
||||
:import_msf_web_element,
|
||||
element,
|
||||
options) do |*args|
|
||||
actual_args = args
|
||||
|
||||
returned_hash
|
||||
end
|
||||
|
||||
actual_args.should == [element, options]
|
||||
end
|
||||
|
||||
it 'should pass return Hash to report_web_<:type>' do
|
||||
db_manager.should_receive(
|
||||
"report_web_#{type}"
|
||||
).with(
|
||||
hash_including(returned_hash)
|
||||
)
|
||||
|
||||
import_msf_web_element
|
||||
end
|
||||
end
|
||||
|
||||
context 'notifier' do
|
||||
context 'with :notifier' do
|
||||
let(:event) do
|
||||
"web_#{type}".to_sym
|
||||
end
|
||||
|
||||
let(:notifier) do
|
||||
lambda do |*args|
|
||||
successive_args << args
|
||||
end
|
||||
end
|
||||
|
||||
let(:successive_args) do
|
||||
[]
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
options[:notifier] = notifier
|
||||
end
|
||||
|
||||
it 'should call :notifier with event and path' do
|
||||
import_msf_web_element
|
||||
|
||||
successive_args.length.should == 1
|
||||
|
||||
args = successive_args[0]
|
||||
|
||||
args.length.should == 2
|
||||
args[0].should == event
|
||||
args[1].should == web_vuln.path
|
||||
end
|
||||
end
|
||||
|
||||
context 'without :notifier' do
|
||||
it 'should not raise an error' do
|
||||
expect {
|
||||
import_msf_web_element
|
||||
}.to_not raise_error
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'without :type' do
|
||||
let(:element) do
|
||||
nil
|
||||
end
|
||||
|
||||
it 'should raise KeyError' do
|
||||
expect {
|
||||
import_msf_web_element
|
||||
}.to raise_error(KeyError, 'key not found: :type')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context '#import_msf_web_form_element' do
|
||||
let(:type) do
|
||||
:form
|
||||
end
|
||||
|
||||
subject(:import_msf_web_form_element) do
|
||||
db_manager.import_msf_web_form_element(
|
||||
element,
|
||||
options,
|
||||
¬ifier
|
||||
)
|
||||
end
|
||||
|
||||
context 'call to #import_msf_web_element' do
|
||||
it_should_behave_like 'Msf::DBManager::ImportMsfXml#import_msf_web_element specialization'
|
||||
|
||||
context 'specialization return' do
|
||||
let(:element) do
|
||||
document.root
|
||||
end
|
||||
|
||||
let(:source) do
|
||||
xml.web_form do
|
||||
xml.method(
|
||||
web_form_attributes.fetch(:method)
|
||||
)
|
||||
|
||||
serialized_params = serialize(
|
||||
web_form_attributes.fetch(:params)
|
||||
)
|
||||
xml.params(serialized_params)
|
||||
end
|
||||
|
||||
xml.target!
|
||||
end
|
||||
|
||||
it 'should be a Hash' do
|
||||
with_info do |info|
|
||||
info.should be_a Hash
|
||||
end
|
||||
end
|
||||
|
||||
it 'should include :method' do
|
||||
with_info do |info|
|
||||
info[:method].should == web_form_attributes[:method]
|
||||
end
|
||||
end
|
||||
|
||||
it 'should include :params' do
|
||||
with_info do |info|
|
||||
info[:params].should == web_form_attributes[:params]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with required attributes' do
|
||||
include_context 'DatabaseCleaner'
|
||||
|
||||
let(:element) do
|
||||
document.root
|
||||
end
|
||||
|
||||
let(:source) do
|
||||
xml.web_form do
|
||||
xml.host(
|
||||
host_attributes.fetch(:address)
|
||||
)
|
||||
xml.method(
|
||||
web_form_attributes.fetch(:method)
|
||||
)
|
||||
xml.path(
|
||||
web_form_attributes.fetch(:path)
|
||||
)
|
||||
xml.port(
|
||||
service_attributes.fetch(:port)
|
||||
)
|
||||
|
||||
ssl = false
|
||||
|
||||
if service_attributes[:name] == 'https'
|
||||
ssl = true
|
||||
end
|
||||
|
||||
xml.ssl(ssl)
|
||||
end
|
||||
|
||||
xml.target!
|
||||
end
|
||||
|
||||
it 'should create an Mdm::WebForm' do
|
||||
expect {
|
||||
import_msf_web_form_element
|
||||
}.to change(Mdm::WebForm, :count).by(1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context '#import_msf_web_page_element' do
|
||||
let(:type) do
|
||||
:page
|
||||
end
|
||||
|
||||
subject(:import_msf_web_page_element) do
|
||||
db_manager.import_msf_web_page_element(
|
||||
element,
|
||||
options,
|
||||
¬ifier
|
||||
)
|
||||
end
|
||||
|
||||
context 'call to #import_msf_web_element' do
|
||||
it_should_behave_like 'Msf::DBManager::ImportMsfXml#import_msf_web_element specialization'
|
||||
|
||||
context 'specialization return' do
|
||||
let(:element) do
|
||||
document.root
|
||||
end
|
||||
|
||||
let(:source) do
|
||||
xml.web_page do
|
||||
xml.auth(
|
||||
web_page_attributes.fetch(:auth)
|
||||
)
|
||||
xml.body(
|
||||
web_page_attributes.fetch(:body)
|
||||
)
|
||||
xml.code(
|
||||
web_page_attributes.fetch(:code)
|
||||
)
|
||||
xml.cookie(
|
||||
web_page_attributes.fetch(:cookie)
|
||||
)
|
||||
xml.ctype(
|
||||
web_page_attributes.fetch(:ctype)
|
||||
)
|
||||
|
||||
serialized_headers = serialize(
|
||||
web_page_attributes.fetch(:headers)
|
||||
)
|
||||
xml.headers(serialized_headers)
|
||||
|
||||
xml.location(
|
||||
web_page_attributes.fetch(:location)
|
||||
)
|
||||
xml.mtime(
|
||||
web_page_attributes.fetch(:mtime)
|
||||
)
|
||||
end
|
||||
|
||||
xml.target!
|
||||
end
|
||||
|
||||
it 'should be a Hash' do
|
||||
db_manager.should_receive(:import_msf_web_element) do |*args, &specialization|
|
||||
info = specialization.call(element, options)
|
||||
|
||||
info.should be_a Hash
|
||||
end
|
||||
|
||||
import_msf_web_page_element
|
||||
end
|
||||
|
||||
it 'should include :auth' do
|
||||
with_info do |info|
|
||||
info[:auth].should == web_page_attributes.fetch(:auth)
|
||||
end
|
||||
end
|
||||
|
||||
it 'should include :body' do
|
||||
with_info do |info|
|
||||
info[:body].should == web_page_attributes.fetch(:body)
|
||||
end
|
||||
end
|
||||
|
||||
it 'should include :code' do
|
||||
with_info do |info|
|
||||
info[:code].should == web_page_attributes.fetch(:code)
|
||||
end
|
||||
end
|
||||
|
||||
it 'should include :cookie' do
|
||||
with_info do |info|
|
||||
info[:cookie].should == web_page_attributes.fetch(:cookie)
|
||||
end
|
||||
end
|
||||
|
||||
it 'should include :ctype' do
|
||||
with_info do |info|
|
||||
info[:ctype].should == web_page_attributes.fetch(:ctype)
|
||||
end
|
||||
end
|
||||
|
||||
it 'should include :headers' do
|
||||
with_info do |info|
|
||||
info[:headers].should == web_page_attributes.fetch(:headers)
|
||||
end
|
||||
end
|
||||
|
||||
it 'should include :location' do
|
||||
with_info do |info|
|
||||
info[:location].should == web_page_attributes.fetch(:location)
|
||||
end
|
||||
end
|
||||
|
||||
it 'should include :mtime' do
|
||||
with_info do |info|
|
||||
info[:mtime].should == web_page_attributes.fetch(:mtime)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with required attributes' do
|
||||
include_context 'DatabaseCleaner'
|
||||
|
||||
let(:element) do
|
||||
document.root
|
||||
end
|
||||
|
||||
let(:source) do
|
||||
xml.web_page do
|
||||
xml.body(
|
||||
web_page_attributes.fetch(:body)
|
||||
)
|
||||
xml.code(
|
||||
web_page_attributes.fetch(:code)
|
||||
)
|
||||
|
||||
serialized_headers = serialize(
|
||||
web_page_attributes.fetch(:headers)
|
||||
)
|
||||
xml.headers(serialized_headers)
|
||||
|
||||
xml.host(
|
||||
host_attributes.fetch(:address)
|
||||
)
|
||||
xml.path(
|
||||
web_page_attributes.fetch(:headers)
|
||||
)
|
||||
xml.port(
|
||||
service_attributes.fetch(:port)
|
||||
)
|
||||
xml.query(
|
||||
web_page_attributes.fetch(:query)
|
||||
)
|
||||
|
||||
ssl = false
|
||||
|
||||
if service_attributes[:name] == 'https'
|
||||
ssl = true
|
||||
end
|
||||
|
||||
xml.ssl(ssl)
|
||||
end
|
||||
|
||||
xml.target!
|
||||
end
|
||||
|
||||
it 'should create an Mdm::WebPage' do
|
||||
expect {
|
||||
import_msf_web_page_element
|
||||
}.to change(Mdm::WebPage, :count).by(1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context '#import_msf_web_vuln_element' do
|
||||
let(:type) do
|
||||
:vuln
|
||||
end
|
||||
|
||||
let(:web_vuln_attributes) do
|
||||
FactoryGirl.attributes_for(:exported_web_vuln)
|
||||
end
|
||||
|
||||
subject(:import_msf_web_vuln_element) do
|
||||
db_manager.import_msf_web_vuln_element(
|
||||
element,
|
||||
options,
|
||||
¬ifier
|
||||
)
|
||||
end
|
||||
|
||||
context 'call to #import_msf_web_element' do
|
||||
it_should_behave_like 'Msf::DBManager::ImportMsfXml#import_msf_web_element specialization'
|
||||
|
||||
context 'specialization return' do
|
||||
let(:element) do
|
||||
document.root
|
||||
end
|
||||
|
||||
let(:source) do
|
||||
xml.web_vuln do
|
||||
xml.blame(
|
||||
web_vuln_attributes.fetch(:blame)
|
||||
)
|
||||
xml.category(
|
||||
web_vuln_attributes.fetch(:category)
|
||||
)
|
||||
xml.confidence(
|
||||
web_vuln_attributes.fetch(:confidence)
|
||||
)
|
||||
xml.description(
|
||||
web_vuln_attributes.fetch(:description)
|
||||
)
|
||||
xml.method(
|
||||
web_vuln_attributes.fetch(:method)
|
||||
)
|
||||
xml.name(
|
||||
web_vuln_attributes.fetch(:name)
|
||||
)
|
||||
xml.pname(
|
||||
web_vuln_attributes.fetch(:pname)
|
||||
)
|
||||
xml.proof(
|
||||
web_vuln_attributes.fetch(:proof)
|
||||
)
|
||||
xml.risk(
|
||||
web_vuln_attributes.fetch(:risk)
|
||||
)
|
||||
end
|
||||
|
||||
xml.target!
|
||||
end
|
||||
|
||||
it 'should be a Hash' do
|
||||
with_info do |info|
|
||||
info.should be_a Hash
|
||||
end
|
||||
|
||||
import_msf_web_vuln_element
|
||||
end
|
||||
|
||||
it 'should include :blame' do
|
||||
with_info do |info|
|
||||
info[:blame].should == web_vuln_attributes.fetch(:blame)
|
||||
end
|
||||
end
|
||||
|
||||
it 'should include :category' do
|
||||
with_info do |info|
|
||||
info[:category].should == web_vuln_attributes.fetch(:category)
|
||||
end
|
||||
end
|
||||
|
||||
it 'should include :confidence' do
|
||||
with_info do |info|
|
||||
info[:confidence].should == web_vuln_attributes.fetch(:confidence)
|
||||
end
|
||||
end
|
||||
|
||||
it 'should include :description' do
|
||||
with_info do |info|
|
||||
info[:description].should == web_vuln_attributes.fetch(:description)
|
||||
end
|
||||
end
|
||||
|
||||
it 'should include :method' do
|
||||
with_info do |info|
|
||||
info[:method].should == web_vuln_attributes.fetch(:method)
|
||||
end
|
||||
end
|
||||
|
||||
it 'should include :name' do
|
||||
with_info do |info|
|
||||
info[:name].should == web_vuln_attributes.fetch(:name)
|
||||
end
|
||||
end
|
||||
|
||||
it 'should include :pname' do
|
||||
with_info do |info|
|
||||
info[:pname].should == web_vuln_attributes.fetch(:pname)
|
||||
end
|
||||
end
|
||||
|
||||
it 'should include :proof' do
|
||||
with_info do |info|
|
||||
info[:proof].should == web_vuln_attributes.fetch(:proof)
|
||||
end
|
||||
end
|
||||
|
||||
it 'should include :risk' do
|
||||
with_info do |info|
|
||||
info[:risk].should == web_vuln_attributes.fetch(:risk)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with required attributes' do
|
||||
include_context 'DatabaseCleaner'
|
||||
|
||||
let(:element) do
|
||||
document.root
|
||||
end
|
||||
|
||||
let(:source) do
|
||||
xml.web_vuln do
|
||||
xml.category(
|
||||
web_vuln_attributes.fetch(:category)
|
||||
)
|
||||
xml.host(
|
||||
host_attributes.fetch(:address)
|
||||
)
|
||||
xml.method(
|
||||
web_vuln_attributes.fetch(:method)
|
||||
)
|
||||
xml.name(
|
||||
web_vuln_attributes.fetch(:name)
|
||||
)
|
||||
|
||||
serialized_params = serialize(
|
||||
web_vuln_attributes.fetch(:params)
|
||||
)
|
||||
xml.params(serialized_params)
|
||||
|
||||
xml.path(
|
||||
web_vuln_attributes.fetch(:path)
|
||||
)
|
||||
xml.pname(
|
||||
web_vuln_attributes.fetch(:pname)
|
||||
)
|
||||
xml.port(
|
||||
service_attributes.fetch(:port)
|
||||
)
|
||||
xml.proof(
|
||||
web_vuln_attributes.fetch(:proof)
|
||||
)
|
||||
xml.risk(
|
||||
web_vuln_attributes.fetch(:risk)
|
||||
)
|
||||
|
||||
ssl = false
|
||||
|
||||
if service_attributes[:name] == 'https'
|
||||
ssl = true
|
||||
end
|
||||
|
||||
xml.ssl(ssl)
|
||||
end
|
||||
|
||||
xml.target!
|
||||
end
|
||||
|
||||
it 'should create an Mdm::WebVuln' do
|
||||
expect {
|
||||
import_msf_web_vuln_element
|
||||
}.to change(Mdm::WebVuln, :count).by(1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context '#import_msf_xml' do
|
||||
let(:data) do
|
||||
'<MetasploitV4/>'
|
||||
end
|
||||
|
||||
subject(:import_msf_xml) do
|
||||
db_manager.import_msf_xml(:data => data)
|
||||
end
|
||||
|
||||
it 'should call #check_msf_xml_version!' do
|
||||
db_manager.should_receive(:check_msf_xml_version!).and_call_original
|
||||
|
||||
import_msf_xml
|
||||
end
|
||||
|
||||
context 'with web_forms/web_form elements' do
|
||||
include_context 'DatabaseCleaner'
|
||||
|
||||
let(:data) do
|
||||
xml.tag!('MetasploitV4') do
|
||||
xml.web_forms do
|
||||
xml.web_form do
|
||||
xml.host(
|
||||
host_attributes.fetch(:address)
|
||||
)
|
||||
xml.method(
|
||||
web_form_attributes.fetch(:method)
|
||||
)
|
||||
xml.path(
|
||||
web_form_attributes.fetch(:path)
|
||||
)
|
||||
xml.port(
|
||||
service_attributes.fetch(:port)
|
||||
)
|
||||
|
||||
ssl = false
|
||||
|
||||
if service_attributes[:name] == 'https'
|
||||
ssl = true
|
||||
end
|
||||
|
||||
xml.ssl(ssl)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
xml.target!
|
||||
end
|
||||
|
||||
it 'should call #import_msf_web_form_element' do
|
||||
db_manager.should_receive(:import_msf_web_form_element).and_call_original
|
||||
|
||||
import_msf_xml
|
||||
end
|
||||
end
|
||||
|
||||
context 'with web_pages/web_page elements' do
|
||||
include_context 'DatabaseCleaner'
|
||||
|
||||
let(:data) do
|
||||
xml.tag!('MetasploitV4') do
|
||||
xml.web_pages do
|
||||
xml.web_page do
|
||||
xml.body(
|
||||
web_page_attributes.fetch(:body)
|
||||
)
|
||||
xml.code(
|
||||
web_page_attributes.fetch(:code)
|
||||
)
|
||||
|
||||
serialized_headers = serialize(
|
||||
web_page_attributes.fetch(:headers)
|
||||
)
|
||||
xml.headers(serialized_headers)
|
||||
|
||||
xml.host(
|
||||
host_attributes.fetch(:address)
|
||||
)
|
||||
xml.path(
|
||||
web_page_attributes.fetch(:headers)
|
||||
)
|
||||
xml.port(
|
||||
service_attributes.fetch(:port)
|
||||
)
|
||||
xml.query(
|
||||
web_page_attributes.fetch(:query)
|
||||
)
|
||||
|
||||
ssl = false
|
||||
|
||||
if service_attributes[:name] == 'https'
|
||||
ssl = true
|
||||
end
|
||||
|
||||
xml.ssl(ssl)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
xml.target!
|
||||
end
|
||||
|
||||
it 'should call #import_msf_web_page_element' do
|
||||
db_manager.should_receive(:import_msf_web_page_element).and_call_original
|
||||
|
||||
import_msf_xml
|
||||
end
|
||||
end
|
||||
|
||||
context 'with web_vulns/web_vuln elements' do
|
||||
include_context 'DatabaseCleaner'
|
||||
|
||||
let(:data) do
|
||||
xml.tag!('MetasploitV4') do
|
||||
xml.web_vulns do
|
||||
xml.web_vuln do
|
||||
xml.category(web_vuln.category)
|
||||
|
||||
service = web_vuln.web_site.service
|
||||
xml.host(service.host.address)
|
||||
|
||||
xml.method(web_vuln.method)
|
||||
xml.name(web_vuln.name)
|
||||
|
||||
serialized_params = serialize(web_vuln.params)
|
||||
xml.params(serialized_params)
|
||||
|
||||
xml.path(web_vuln.path)
|
||||
xml.pname(web_vuln.pname)
|
||||
xml.port(service.port)
|
||||
xml.proof(web_vuln.proof)
|
||||
|
||||
ssl = false
|
||||
|
||||
if service.name == 'https'
|
||||
ssl = true
|
||||
end
|
||||
|
||||
xml.ssl(ssl)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
xml.target!
|
||||
end
|
||||
|
||||
let(:web_vuln) do
|
||||
FactoryGirl.create(:mdm_web_vuln)
|
||||
end
|
||||
|
||||
it 'should call #import_msf_web_vuln_element' do
|
||||
db_manager.should_receive(:import_msf_web_vuln_element).and_call_original
|
||||
|
||||
import_msf_xml
|
||||
end
|
||||
end
|
||||
end
|
||||
# Serialized format from pro/modules/auxiliary/pro/report.rb
|
||||
def serialize(object)
|
||||
# FIXME https://www.pivotaltracker.com/story/show/46578647
|
||||
marshalled = Marshal.dump(object)
|
||||
base64_encoded = [marshalled].pack('m')
|
||||
compact = base64_encoded.gsub(/\s+/, '')
|
||||
|
||||
compact
|
||||
end
|
||||
|
||||
def with_info
|
||||
db_manager.should_receive(:import_msf_web_element) do |*args, &specialization|
|
||||
info = specialization.call(element, options)
|
||||
|
||||
yield info
|
||||
end
|
||||
|
||||
subject
|
||||
end
|
||||
|
||||
let(:allow_yaml) do
|
||||
false
|
||||
end
|
||||
|
||||
let(:document) do
|
||||
REXML::Document.new(source)
|
||||
end
|
||||
|
||||
let(:element) do
|
||||
nil
|
||||
end
|
||||
|
||||
let(:host_attributes) do
|
||||
FactoryGirl.attributes_for(:mdm_host)
|
||||
end
|
||||
|
||||
let(:msf_web_text_element_names) do
|
||||
[
|
||||
'created-at',
|
||||
'host',
|
||||
'path',
|
||||
'port',
|
||||
'query',
|
||||
'ssl',
|
||||
'updated-at',
|
||||
'vhost'
|
||||
]
|
||||
end
|
||||
|
||||
let(:notifier) do
|
||||
lambda do |event, data|
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
let(:options) do
|
||||
{
|
||||
:allow_yaml => allow_yaml,
|
||||
:workspace => workspace
|
||||
}
|
||||
end
|
||||
|
||||
let(:service_attributes) do
|
||||
FactoryGirl.attributes_for(:web_service)
|
||||
end
|
||||
|
||||
let(:web_form_attributes) do
|
||||
FactoryGirl.attributes_for(:mdm_web_form, :exported)
|
||||
end
|
||||
|
||||
let(:web_page_attributes) do
|
||||
FactoryGirl.attributes_for(:mdm_web_page)
|
||||
end
|
||||
|
||||
let(:workspace) do
|
||||
nil
|
||||
end
|
||||
|
||||
let(:xml) do
|
||||
Builder::XmlMarkup.new(:indent => 2)
|
||||
end
|
||||
|
||||
it 'should include methods from module so method can be overridden easier in pro' do
|
||||
db_manager.should be_a Msf::DBManager::ImportMsfXml
|
||||
end
|
||||
|
||||
context 'CONSTANTS' do
|
||||
it 'should define MSF_WEB_PAGE_TEXT_ELEMENT_NAMES in any order' do
|
||||
described_class::MSF_WEB_PAGE_TEXT_ELEMENT_NAMES =~ [
|
||||
'auth',
|
||||
'body',
|
||||
'code',
|
||||
'cookie',
|
||||
'ctype',
|
||||
'location',
|
||||
'mtime'
|
||||
]
|
||||
end
|
||||
|
||||
it 'should define MSF_WEB_TEXT_ELEMENT_NAMES in any order' do
|
||||
described_class::MSF_WEB_TEXT_ELEMENT_NAMES =~ msf_web_text_element_names
|
||||
end
|
||||
|
||||
it 'should define MSF_WEB_VULN_TEXT_ELEMENT_NAMES in any order' do
|
||||
described_class::MSF_WEB_VULN_TEXT_ELEMENT_NAMES =~ [
|
||||
'blame',
|
||||
'category',
|
||||
'confidence',
|
||||
'description',
|
||||
'method',
|
||||
'name',
|
||||
'pname',
|
||||
'proof',
|
||||
'risk'
|
||||
]
|
||||
end
|
||||
end
|
||||
|
||||
context '#check_msf_xml_version!' do
|
||||
let(:root_tag) do
|
||||
'root'
|
||||
end
|
||||
|
||||
let(:source) do
|
||||
xml.tag!(root_tag)
|
||||
|
||||
xml.target!
|
||||
end
|
||||
|
||||
subject(:metadata) do
|
||||
db_manager.send(:check_msf_xml_version!, document)
|
||||
end
|
||||
|
||||
it_should_behave_like(
|
||||
'Msf::DBManager::ImportMsfXml#check_msf_xml_version! with root tag',
|
||||
'MetasploitExpressV1',
|
||||
:allow_yaml => true
|
||||
)
|
||||
|
||||
it_should_behave_like(
|
||||
'Msf::DBManager::ImportMsfXml#check_msf_xml_version! with root tag',
|
||||
'MetasploitExpressV2',
|
||||
:allow_yaml => true
|
||||
)
|
||||
|
||||
it_should_behave_like(
|
||||
'Msf::DBManager::ImportMsfXml#check_msf_xml_version! with root tag',
|
||||
'MetasploitExpressV3',
|
||||
:allow_yaml => false
|
||||
)
|
||||
|
||||
it_should_behave_like(
|
||||
'Msf::DBManager::ImportMsfXml#check_msf_xml_version! with root tag',
|
||||
'MetasploitExpressV4',
|
||||
:allow_yaml => false
|
||||
)
|
||||
|
||||
context 'with other' do
|
||||
it 'should raise DBImportError' do
|
||||
expect {
|
||||
metadata
|
||||
}.to raise_error(
|
||||
Msf::DBImportError,
|
||||
'Unsupported Metasploit XML document format'
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context '#import_msf_text_element' do
|
||||
let(:parent_element) do
|
||||
document.root
|
||||
end
|
||||
|
||||
let(:child_name) do
|
||||
'child'
|
||||
end
|
||||
|
||||
let(:child_sym) do
|
||||
child_name.to_sym
|
||||
end
|
||||
|
||||
subject(:info) do
|
||||
db_manager.send(:import_msf_text_element, parent_element, child_name)
|
||||
end
|
||||
|
||||
context 'with child element' do
|
||||
let(:source) do
|
||||
xml.parent do
|
||||
xml.tag!(child_name, text)
|
||||
end
|
||||
|
||||
xml.target!
|
||||
end
|
||||
|
||||
context 'with padded text' do
|
||||
let(:stripped) do
|
||||
'stripped'
|
||||
end
|
||||
|
||||
let(:text) do
|
||||
" #{stripped} "
|
||||
end
|
||||
|
||||
it 'should strip text' do
|
||||
info[:child].should == stripped
|
||||
end
|
||||
end
|
||||
|
||||
context 'with NULL text' do
|
||||
let(:text) do
|
||||
'NULL'
|
||||
end
|
||||
|
||||
it 'should have nil for child name in info' do
|
||||
# use have_key to verify info isn't just returning hash default of
|
||||
# `nil`.
|
||||
info.should have_key(child_sym)
|
||||
info[child_sym].should be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'without NULL text' do
|
||||
let(:text) do
|
||||
'some text'
|
||||
end
|
||||
|
||||
it 'should have text for child name in info' do
|
||||
info[child_sym].should == text
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'without child element' do
|
||||
let(:source) do
|
||||
xml.parent
|
||||
|
||||
xml.target!
|
||||
end
|
||||
|
||||
it 'should return an empty Hash' do
|
||||
info.should == {}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'import_msf_web_element' do
|
||||
let(:element) do
|
||||
document.root
|
||||
end
|
||||
|
||||
let(:options) do
|
||||
{}
|
||||
end
|
||||
|
||||
let(:specialization) do
|
||||
lambda { |element, options|
|
||||
{}
|
||||
}
|
||||
end
|
||||
|
||||
subject(:import_msf_web_element) do
|
||||
db_manager.send(
|
||||
:import_msf_web_element,
|
||||
element,
|
||||
options,
|
||||
&specialization
|
||||
)
|
||||
end
|
||||
|
||||
context 'with :type' do
|
||||
include_context 'DatabaseCleaner'
|
||||
|
||||
let(:source) do
|
||||
xml.tag!("web_#{type}") do
|
||||
web_site = web_vuln.web_site
|
||||
service = web_site.service
|
||||
|
||||
xml.host(service.host.address)
|
||||
xml.path(web_vuln.path)
|
||||
xml.port(service.port)
|
||||
xml.query(web_vuln.query)
|
||||
|
||||
ssl = false
|
||||
|
||||
if service.name == 'https'
|
||||
ssl = true
|
||||
end
|
||||
|
||||
xml.ssl(ssl)
|
||||
|
||||
xml.vhost(web_site.vhost)
|
||||
end
|
||||
|
||||
xml.target!
|
||||
end
|
||||
|
||||
let(:type) do
|
||||
:vuln
|
||||
end
|
||||
|
||||
let(:web_vuln) do
|
||||
FactoryGirl.create(:mdm_web_vuln)
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
db_manager.stub(
|
||||
:report_web_vuln
|
||||
).with(
|
||||
an_instance_of(Hash)
|
||||
)
|
||||
|
||||
options[:type] = type
|
||||
end
|
||||
|
||||
context 'with :workspace' do
|
||||
let(:workspace) do
|
||||
double(':workspace')
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
options[:workspace] = workspace
|
||||
end
|
||||
|
||||
it 'should not call Msf::DBManager#workspace' do
|
||||
db_manager.should_not_receive(:workspace)
|
||||
|
||||
import_msf_web_element
|
||||
end
|
||||
|
||||
it 'should pass :workspace to report_web_<:type>' do
|
||||
db_manager.should_receive(
|
||||
"report_web_#{type}"
|
||||
).with(
|
||||
hash_including(:workspace => workspace)
|
||||
)
|
||||
|
||||
import_msf_web_element
|
||||
end
|
||||
end
|
||||
|
||||
context 'without :workspace' do
|
||||
let(:workspace) do
|
||||
FactoryGirl.create(:mdm_workspace)
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
db_manager.workspace = workspace
|
||||
end
|
||||
|
||||
it 'should call Msf::DBManager#workspace' do
|
||||
db_manager.should_receive(:workspace).and_call_original
|
||||
|
||||
import_msf_web_element
|
||||
end
|
||||
|
||||
it 'should pass Msf::DBManager#workspace to report_web_<:type>' do
|
||||
db_manager.should_receive(
|
||||
"report_web_#{type}"
|
||||
).with(
|
||||
hash_including(:workspace => workspace)
|
||||
)
|
||||
|
||||
import_msf_web_element
|
||||
end
|
||||
end
|
||||
|
||||
it 'should import all elements in MSF_WEB_TEXT_ELEMENT_NAMES with #import_msf_text_element' do
|
||||
msf_web_text_element_names.each do |name|
|
||||
db_manager.should_receive(
|
||||
:import_msf_text_element
|
||||
).with(
|
||||
element,
|
||||
name
|
||||
).and_call_original
|
||||
end
|
||||
|
||||
import_msf_web_element
|
||||
end
|
||||
|
||||
context 'with non-empty Hash from #import_msf_text_element' do
|
||||
let(:returned_hash) do
|
||||
{
|
||||
:host => '192.168.0.1'
|
||||
}
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
db_manager.stub(:import_msf_text_element).and_return(returned_hash)
|
||||
end
|
||||
|
||||
it 'should pass returned Hash as part of Hash passed to report_web_<:type' do
|
||||
db_manager.should_receive(
|
||||
"report_web_#{type}"
|
||||
).with(
|
||||
hash_including(returned_hash)
|
||||
)
|
||||
|
||||
import_msf_web_element
|
||||
end
|
||||
end
|
||||
|
||||
context 'ssl element' do
|
||||
context 'without element' do
|
||||
let(:source) do
|
||||
xml.tag!("web_#{type}")
|
||||
|
||||
xml.target!
|
||||
end
|
||||
|
||||
it 'should pass false for :ssl to report_web_<:type>' do
|
||||
db_manager.should_receive(
|
||||
"report_web_#{type}"
|
||||
).with(
|
||||
hash_including(:ssl => false)
|
||||
)
|
||||
|
||||
import_msf_web_element
|
||||
end
|
||||
end
|
||||
|
||||
context 'with element' do
|
||||
let(:source) do
|
||||
xml.tag!("web_#{type}") do
|
||||
xml.ssl(ssl)
|
||||
end
|
||||
|
||||
xml.target!
|
||||
end
|
||||
|
||||
context "with 'true' text" do
|
||||
let(:ssl) do
|
||||
true
|
||||
end
|
||||
|
||||
it 'should pass true for :ssl to report_web_<:type>' do
|
||||
db_manager.should_receive(
|
||||
"report_web_#{type}"
|
||||
).with(
|
||||
hash_including(:ssl => true)
|
||||
)
|
||||
|
||||
import_msf_web_element
|
||||
end
|
||||
end
|
||||
|
||||
context "without 'true' text" do
|
||||
let(:ssl) do
|
||||
false
|
||||
end
|
||||
|
||||
it 'should pass false for :ssl to report_web_<:type>' do
|
||||
db_manager.should_receive(
|
||||
"report_web_#{type}"
|
||||
).with(
|
||||
hash_including(:ssl => false)
|
||||
)
|
||||
|
||||
import_msf_web_element
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'specialization block' do
|
||||
let(:returned_hash) do
|
||||
{
|
||||
:specialized => double('Value')
|
||||
}
|
||||
end
|
||||
|
||||
let(:specialization) do
|
||||
lambda { |element, option|
|
||||
returned_hash
|
||||
}
|
||||
end
|
||||
|
||||
it 'should be called with element and options' do
|
||||
actual_args = []
|
||||
|
||||
db_manager.send(
|
||||
:import_msf_web_element,
|
||||
element,
|
||||
options) do |*args|
|
||||
actual_args = args
|
||||
|
||||
returned_hash
|
||||
end
|
||||
|
||||
actual_args.should == [element, options]
|
||||
end
|
||||
|
||||
it 'should pass return Hash to report_web_<:type>' do
|
||||
db_manager.should_receive(
|
||||
"report_web_#{type}"
|
||||
).with(
|
||||
hash_including(returned_hash)
|
||||
)
|
||||
|
||||
import_msf_web_element
|
||||
end
|
||||
end
|
||||
|
||||
context 'notifier' do
|
||||
context 'with :notifier' do
|
||||
let(:event) do
|
||||
"web_#{type}".to_sym
|
||||
end
|
||||
|
||||
let(:notifier) do
|
||||
lambda do |*args|
|
||||
successive_args << args
|
||||
end
|
||||
end
|
||||
|
||||
let(:successive_args) do
|
||||
[]
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
options[:notifier] = notifier
|
||||
end
|
||||
|
||||
it 'should call :notifier with event and path' do
|
||||
import_msf_web_element
|
||||
|
||||
successive_args.length.should == 1
|
||||
|
||||
args = successive_args[0]
|
||||
|
||||
args.length.should == 2
|
||||
args[0].should == event
|
||||
args[1].should == web_vuln.path
|
||||
end
|
||||
end
|
||||
|
||||
context 'without :notifier' do
|
||||
it 'should not raise an error' do
|
||||
expect {
|
||||
import_msf_web_element
|
||||
}.to_not raise_error
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'without :type' do
|
||||
let(:element) do
|
||||
nil
|
||||
end
|
||||
|
||||
it 'should raise KeyError' do
|
||||
expect {
|
||||
import_msf_web_element
|
||||
}.to raise_error(KeyError, 'key not found: :type')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context '#import_msf_web_form_element' do
|
||||
let(:type) do
|
||||
:form
|
||||
end
|
||||
|
||||
subject(:import_msf_web_form_element) do
|
||||
db_manager.import_msf_web_form_element(
|
||||
element,
|
||||
options,
|
||||
¬ifier
|
||||
)
|
||||
end
|
||||
|
||||
context 'call to #import_msf_web_element' do
|
||||
it_should_behave_like 'Msf::DBManager::ImportMsfXml#import_msf_web_element specialization'
|
||||
|
||||
context 'specialization return' do
|
||||
let(:element) do
|
||||
document.root
|
||||
end
|
||||
|
||||
let(:source) do
|
||||
xml.web_form do
|
||||
xml.method(
|
||||
web_form_attributes.fetch(:method)
|
||||
)
|
||||
|
||||
serialized_params = serialize(
|
||||
web_form_attributes.fetch(:params)
|
||||
)
|
||||
xml.params(serialized_params)
|
||||
end
|
||||
|
||||
xml.target!
|
||||
end
|
||||
|
||||
it 'should be a Hash' do
|
||||
with_info do |info|
|
||||
info.should be_a Hash
|
||||
end
|
||||
end
|
||||
|
||||
it 'should include :method' do
|
||||
with_info do |info|
|
||||
info[:method].should == web_form_attributes[:method]
|
||||
end
|
||||
end
|
||||
|
||||
it 'should include :params' do
|
||||
with_info do |info|
|
||||
info[:params].should == web_form_attributes[:params]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with required attributes' do
|
||||
include_context 'DatabaseCleaner'
|
||||
|
||||
let(:element) do
|
||||
document.root
|
||||
end
|
||||
|
||||
let(:source) do
|
||||
xml.web_form do
|
||||
xml.host(
|
||||
host_attributes.fetch(:address)
|
||||
)
|
||||
xml.method(
|
||||
web_form_attributes.fetch(:method)
|
||||
)
|
||||
xml.path(
|
||||
web_form_attributes.fetch(:path)
|
||||
)
|
||||
xml.port(
|
||||
service_attributes.fetch(:port)
|
||||
)
|
||||
|
||||
ssl = false
|
||||
|
||||
if service_attributes[:name] == 'https'
|
||||
ssl = true
|
||||
end
|
||||
|
||||
xml.ssl(ssl)
|
||||
end
|
||||
|
||||
xml.target!
|
||||
end
|
||||
|
||||
it 'should create an Mdm::WebForm' do
|
||||
expect {
|
||||
import_msf_web_form_element
|
||||
}.to change(Mdm::WebForm, :count).by(1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context '#import_msf_web_page_element' do
|
||||
let(:type) do
|
||||
:page
|
||||
end
|
||||
|
||||
subject(:import_msf_web_page_element) do
|
||||
db_manager.import_msf_web_page_element(
|
||||
element,
|
||||
options,
|
||||
¬ifier
|
||||
)
|
||||
end
|
||||
|
||||
context 'call to #import_msf_web_element' do
|
||||
it_should_behave_like 'Msf::DBManager::ImportMsfXml#import_msf_web_element specialization'
|
||||
|
||||
context 'specialization return' do
|
||||
let(:element) do
|
||||
document.root
|
||||
end
|
||||
|
||||
let(:source) do
|
||||
xml.web_page do
|
||||
xml.auth(
|
||||
web_page_attributes.fetch(:auth)
|
||||
)
|
||||
xml.body(
|
||||
web_page_attributes.fetch(:body)
|
||||
)
|
||||
xml.code(
|
||||
web_page_attributes.fetch(:code)
|
||||
)
|
||||
xml.cookie(
|
||||
web_page_attributes.fetch(:cookie)
|
||||
)
|
||||
xml.ctype(
|
||||
web_page_attributes.fetch(:ctype)
|
||||
)
|
||||
|
||||
serialized_headers = serialize(
|
||||
web_page_attributes.fetch(:headers)
|
||||
)
|
||||
xml.headers(serialized_headers)
|
||||
|
||||
xml.location(
|
||||
web_page_attributes.fetch(:location)
|
||||
)
|
||||
xml.mtime(
|
||||
web_page_attributes.fetch(:mtime)
|
||||
)
|
||||
end
|
||||
|
||||
xml.target!
|
||||
end
|
||||
|
||||
it 'should be a Hash' do
|
||||
db_manager.should_receive(:import_msf_web_element) do |*args, &specialization|
|
||||
info = specialization.call(element, options)
|
||||
|
||||
info.should be_a Hash
|
||||
end
|
||||
|
||||
import_msf_web_page_element
|
||||
end
|
||||
|
||||
it 'should include :auth' do
|
||||
with_info do |info|
|
||||
info[:auth].should == web_page_attributes.fetch(:auth)
|
||||
end
|
||||
end
|
||||
|
||||
it 'should include :body' do
|
||||
with_info do |info|
|
||||
info[:body].should == web_page_attributes.fetch(:body)
|
||||
end
|
||||
end
|
||||
|
||||
it 'should include :code' do
|
||||
with_info do |info|
|
||||
info[:code].should == web_page_attributes.fetch(:code)
|
||||
end
|
||||
end
|
||||
|
||||
it 'should include :cookie' do
|
||||
with_info do |info|
|
||||
info[:cookie].should == web_page_attributes.fetch(:cookie)
|
||||
end
|
||||
end
|
||||
|
||||
it 'should include :ctype' do
|
||||
with_info do |info|
|
||||
info[:ctype].should == web_page_attributes.fetch(:ctype)
|
||||
end
|
||||
end
|
||||
|
||||
it 'should include :headers' do
|
||||
with_info do |info|
|
||||
info[:headers].should == web_page_attributes.fetch(:headers)
|
||||
end
|
||||
end
|
||||
|
||||
it 'should include :location' do
|
||||
with_info do |info|
|
||||
info[:location].should == web_page_attributes.fetch(:location)
|
||||
end
|
||||
end
|
||||
|
||||
it 'should include :mtime' do
|
||||
with_info do |info|
|
||||
info[:mtime].should == web_page_attributes.fetch(:mtime)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with required attributes' do
|
||||
include_context 'DatabaseCleaner'
|
||||
|
||||
let(:element) do
|
||||
document.root
|
||||
end
|
||||
|
||||
let(:source) do
|
||||
xml.web_page do
|
||||
xml.body(
|
||||
web_page_attributes.fetch(:body)
|
||||
)
|
||||
xml.code(
|
||||
web_page_attributes.fetch(:code)
|
||||
)
|
||||
|
||||
serialized_headers = serialize(
|
||||
web_page_attributes.fetch(:headers)
|
||||
)
|
||||
xml.headers(serialized_headers)
|
||||
|
||||
xml.host(
|
||||
host_attributes.fetch(:address)
|
||||
)
|
||||
xml.path(
|
||||
web_page_attributes.fetch(:headers)
|
||||
)
|
||||
xml.port(
|
||||
service_attributes.fetch(:port)
|
||||
)
|
||||
xml.query(
|
||||
web_page_attributes.fetch(:query)
|
||||
)
|
||||
|
||||
ssl = false
|
||||
|
||||
if service_attributes[:name] == 'https'
|
||||
ssl = true
|
||||
end
|
||||
|
||||
xml.ssl(ssl)
|
||||
end
|
||||
|
||||
xml.target!
|
||||
end
|
||||
|
||||
it 'should create an Mdm::WebPage' do
|
||||
expect {
|
||||
import_msf_web_page_element
|
||||
}.to change(Mdm::WebPage, :count).by(1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context '#import_msf_web_vuln_element' do
|
||||
let(:type) do
|
||||
:vuln
|
||||
end
|
||||
|
||||
let(:web_vuln_attributes) do
|
||||
FactoryGirl.attributes_for(:exported_web_vuln)
|
||||
end
|
||||
|
||||
subject(:import_msf_web_vuln_element) do
|
||||
db_manager.import_msf_web_vuln_element(
|
||||
element,
|
||||
options,
|
||||
¬ifier
|
||||
)
|
||||
end
|
||||
|
||||
context 'call to #import_msf_web_element' do
|
||||
it_should_behave_like 'Msf::DBManager::ImportMsfXml#import_msf_web_element specialization'
|
||||
|
||||
context 'specialization return' do
|
||||
let(:element) do
|
||||
document.root
|
||||
end
|
||||
|
||||
let(:source) do
|
||||
xml.web_vuln do
|
||||
xml.blame(
|
||||
web_vuln_attributes.fetch(:blame)
|
||||
)
|
||||
xml.category(
|
||||
web_vuln_attributes.fetch(:category)
|
||||
)
|
||||
xml.confidence(
|
||||
web_vuln_attributes.fetch(:confidence)
|
||||
)
|
||||
xml.description(
|
||||
web_vuln_attributes.fetch(:description)
|
||||
)
|
||||
xml.method(
|
||||
web_vuln_attributes.fetch(:method)
|
||||
)
|
||||
xml.name(
|
||||
web_vuln_attributes.fetch(:name)
|
||||
)
|
||||
xml.pname(
|
||||
web_vuln_attributes.fetch(:pname)
|
||||
)
|
||||
xml.proof(
|
||||
web_vuln_attributes.fetch(:proof)
|
||||
)
|
||||
xml.risk(
|
||||
web_vuln_attributes.fetch(:risk)
|
||||
)
|
||||
end
|
||||
|
||||
xml.target!
|
||||
end
|
||||
|
||||
it 'should be a Hash' do
|
||||
with_info do |info|
|
||||
info.should be_a Hash
|
||||
end
|
||||
|
||||
import_msf_web_vuln_element
|
||||
end
|
||||
|
||||
it 'should include :blame' do
|
||||
with_info do |info|
|
||||
info[:blame].should == web_vuln_attributes.fetch(:blame)
|
||||
end
|
||||
end
|
||||
|
||||
it 'should include :category' do
|
||||
with_info do |info|
|
||||
info[:category].should == web_vuln_attributes.fetch(:category)
|
||||
end
|
||||
end
|
||||
|
||||
it 'should include :confidence' do
|
||||
with_info do |info|
|
||||
info[:confidence].should == web_vuln_attributes.fetch(:confidence)
|
||||
end
|
||||
end
|
||||
|
||||
it 'should include :description' do
|
||||
with_info do |info|
|
||||
info[:description].should == web_vuln_attributes.fetch(:description)
|
||||
end
|
||||
end
|
||||
|
||||
it 'should include :method' do
|
||||
with_info do |info|
|
||||
info[:method].should == web_vuln_attributes.fetch(:method)
|
||||
end
|
||||
end
|
||||
|
||||
it 'should include :name' do
|
||||
with_info do |info|
|
||||
info[:name].should == web_vuln_attributes.fetch(:name)
|
||||
end
|
||||
end
|
||||
|
||||
it 'should include :pname' do
|
||||
with_info do |info|
|
||||
info[:pname].should == web_vuln_attributes.fetch(:pname)
|
||||
end
|
||||
end
|
||||
|
||||
it 'should include :proof' do
|
||||
with_info do |info|
|
||||
info[:proof].should == web_vuln_attributes.fetch(:proof)
|
||||
end
|
||||
end
|
||||
|
||||
it 'should include :risk' do
|
||||
with_info do |info|
|
||||
info[:risk].should == web_vuln_attributes.fetch(:risk)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with required attributes' do
|
||||
include_context 'DatabaseCleaner'
|
||||
|
||||
let(:element) do
|
||||
document.root
|
||||
end
|
||||
|
||||
let(:source) do
|
||||
xml.web_vuln do
|
||||
xml.category(
|
||||
web_vuln_attributes.fetch(:category)
|
||||
)
|
||||
xml.host(
|
||||
host_attributes.fetch(:address)
|
||||
)
|
||||
xml.method(
|
||||
web_vuln_attributes.fetch(:method)
|
||||
)
|
||||
xml.name(
|
||||
web_vuln_attributes.fetch(:name)
|
||||
)
|
||||
|
||||
serialized_params = serialize(
|
||||
web_vuln_attributes.fetch(:params)
|
||||
)
|
||||
xml.params(serialized_params)
|
||||
|
||||
xml.path(
|
||||
web_vuln_attributes.fetch(:path)
|
||||
)
|
||||
xml.pname(
|
||||
web_vuln_attributes.fetch(:pname)
|
||||
)
|
||||
xml.port(
|
||||
service_attributes.fetch(:port)
|
||||
)
|
||||
xml.proof(
|
||||
web_vuln_attributes.fetch(:proof)
|
||||
)
|
||||
xml.risk(
|
||||
web_vuln_attributes.fetch(:risk)
|
||||
)
|
||||
|
||||
ssl = false
|
||||
|
||||
if service_attributes[:name] == 'https'
|
||||
ssl = true
|
||||
end
|
||||
|
||||
xml.ssl(ssl)
|
||||
end
|
||||
|
||||
xml.target!
|
||||
end
|
||||
|
||||
it 'should create an Mdm::WebVuln' do
|
||||
expect {
|
||||
import_msf_web_vuln_element
|
||||
}.to change(Mdm::WebVuln, :count).by(1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context '#import_msf_xml' do
|
||||
let(:data) do
|
||||
'<MetasploitV4/>'
|
||||
end
|
||||
|
||||
subject(:import_msf_xml) do
|
||||
db_manager.import_msf_xml(:data => data)
|
||||
end
|
||||
|
||||
it 'should call #check_msf_xml_version!' do
|
||||
db_manager.should_receive(:check_msf_xml_version!).and_call_original
|
||||
|
||||
import_msf_xml
|
||||
end
|
||||
|
||||
context 'with web_forms/web_form elements' do
|
||||
include_context 'DatabaseCleaner'
|
||||
|
||||
let(:data) do
|
||||
xml.tag!('MetasploitV4') do
|
||||
xml.web_forms do
|
||||
xml.web_form do
|
||||
xml.host(
|
||||
host_attributes.fetch(:address)
|
||||
)
|
||||
xml.method(
|
||||
web_form_attributes.fetch(:method)
|
||||
)
|
||||
xml.path(
|
||||
web_form_attributes.fetch(:path)
|
||||
)
|
||||
xml.port(
|
||||
service_attributes.fetch(:port)
|
||||
)
|
||||
|
||||
ssl = false
|
||||
|
||||
if service_attributes[:name] == 'https'
|
||||
ssl = true
|
||||
end
|
||||
|
||||
xml.ssl(ssl)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
xml.target!
|
||||
end
|
||||
|
||||
it 'should call #import_msf_web_form_element' do
|
||||
db_manager.should_receive(:import_msf_web_form_element).and_call_original
|
||||
|
||||
import_msf_xml
|
||||
end
|
||||
end
|
||||
|
||||
context 'with web_pages/web_page elements' do
|
||||
include_context 'DatabaseCleaner'
|
||||
|
||||
let(:data) do
|
||||
xml.tag!('MetasploitV4') do
|
||||
xml.web_pages do
|
||||
xml.web_page do
|
||||
xml.body(
|
||||
web_page_attributes.fetch(:body)
|
||||
)
|
||||
xml.code(
|
||||
web_page_attributes.fetch(:code)
|
||||
)
|
||||
|
||||
serialized_headers = serialize(
|
||||
web_page_attributes.fetch(:headers)
|
||||
)
|
||||
xml.headers(serialized_headers)
|
||||
|
||||
xml.host(
|
||||
host_attributes.fetch(:address)
|
||||
)
|
||||
xml.path(
|
||||
web_page_attributes.fetch(:headers)
|
||||
)
|
||||
xml.port(
|
||||
service_attributes.fetch(:port)
|
||||
)
|
||||
xml.query(
|
||||
web_page_attributes.fetch(:query)
|
||||
)
|
||||
|
||||
ssl = false
|
||||
|
||||
if service_attributes[:name] == 'https'
|
||||
ssl = true
|
||||
end
|
||||
|
||||
xml.ssl(ssl)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
xml.target!
|
||||
end
|
||||
|
||||
it 'should call #import_msf_web_page_element' do
|
||||
db_manager.should_receive(:import_msf_web_page_element).and_call_original
|
||||
|
||||
import_msf_xml
|
||||
end
|
||||
end
|
||||
|
||||
context 'with web_vulns/web_vuln elements' do
|
||||
include_context 'DatabaseCleaner'
|
||||
|
||||
let(:data) do
|
||||
xml.tag!('MetasploitV4') do
|
||||
xml.web_vulns do
|
||||
xml.web_vuln do
|
||||
xml.category(web_vuln.category)
|
||||
|
||||
service = web_vuln.web_site.service
|
||||
xml.host(service.host.address)
|
||||
|
||||
xml.method(web_vuln.method)
|
||||
xml.name(web_vuln.name)
|
||||
|
||||
serialized_params = serialize(web_vuln.params)
|
||||
xml.params(serialized_params)
|
||||
|
||||
xml.path(web_vuln.path)
|
||||
xml.pname(web_vuln.pname)
|
||||
xml.port(service.port)
|
||||
xml.proof(web_vuln.proof)
|
||||
|
||||
ssl = false
|
||||
|
||||
if service.name == 'https'
|
||||
ssl = true
|
||||
end
|
||||
|
||||
xml.ssl(ssl)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
xml.target!
|
||||
end
|
||||
|
||||
let(:web_vuln) do
|
||||
FactoryGirl.create(:mdm_web_vuln)
|
||||
end
|
||||
|
||||
it 'should call #import_msf_web_vuln_element' do
|
||||
db_manager.should_receive(:import_msf_web_vuln_element).and_call_original
|
||||
|
||||
import_msf_xml
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
+18
-18
@@ -1,25 +1,25 @@
|
||||
# -*- coding:binary -*-
|
||||
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)
|
||||
options.assert_valid_keys(:allow_yaml)
|
||||
allow_yaml = options.fetch(:allow_yaml)
|
||||
|
||||
context "with #{root_tag}" do
|
||||
let(:root_tag) do
|
||||
root_tag
|
||||
end
|
||||
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]
|
||||
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_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
|
||||
it "should have #{root_tag} as root tag" do
|
||||
metadata[:root_tag].should == root_tag
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
+32
-32
@@ -1,42 +1,42 @@
|
||||
# -*- coding:binary -*-
|
||||
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)
|
||||
it 'should call #import_msf_web_element with element' do
|
||||
db_manager.should_receive(:import_msf_web_element).with(element, anything)
|
||||
|
||||
subject
|
||||
end
|
||||
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
|
||||
)
|
||||
)
|
||||
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
|
||||
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
|
||||
)
|
||||
)
|
||||
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
|
||||
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)
|
||||
)
|
||||
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
|
||||
subject
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,143 +1,143 @@
|
||||
shared_examples_for 'Msf::DBManager::Migration' do
|
||||
it { should be_a Msf::DBManager::Migration }
|
||||
it { should be_a Msf::DBManager::Migration }
|
||||
|
||||
context '#migrate' do
|
||||
def migrate
|
||||
db_manager.migrate
|
||||
end
|
||||
context '#migrate' do
|
||||
def migrate
|
||||
db_manager.migrate
|
||||
end
|
||||
|
||||
it 'should create a connection' do
|
||||
ActiveRecord::Base.connection_pool.should_receive(:with_connection).twice
|
||||
it 'should create a connection' do
|
||||
ActiveRecord::Base.connection_pool.should_receive(:with_connection).twice
|
||||
|
||||
migrate
|
||||
end
|
||||
migrate
|
||||
end
|
||||
|
||||
it 'should call ActiveRecord::Migrator.migrate' do
|
||||
ActiveRecord::Migrator.should_receive(:migrate).with(
|
||||
ActiveRecord::Migrator.migrations_paths
|
||||
)
|
||||
it 'should call ActiveRecord::Migrator.migrate' do
|
||||
ActiveRecord::Migrator.should_receive(:migrate).with(
|
||||
ActiveRecord::Migrator.migrations_paths
|
||||
)
|
||||
|
||||
migrate
|
||||
end
|
||||
migrate
|
||||
end
|
||||
|
||||
it 'should return migrations that were ran from ActiveRecord::Migrator.migrate' do
|
||||
migrations = [double('Migration 1')]
|
||||
ActiveRecord::Migrator.stub(:migrate => migrations)
|
||||
it 'should return migrations that were ran from ActiveRecord::Migrator.migrate' do
|
||||
migrations = [double('Migration 1')]
|
||||
ActiveRecord::Migrator.stub(:migrate => migrations)
|
||||
|
||||
migrate.should == migrations
|
||||
end
|
||||
migrate.should == migrations
|
||||
end
|
||||
|
||||
it 'should reset the column information' do
|
||||
db_manager.should_receive(:reset_column_information)
|
||||
it 'should reset the column information' do
|
||||
db_manager.should_receive(:reset_column_information)
|
||||
|
||||
migrate
|
||||
end
|
||||
migrate
|
||||
end
|
||||
|
||||
context 'with StandardError from ActiveRecord::Migration.migrate' do
|
||||
let(:error) do
|
||||
StandardError.new(message)
|
||||
end
|
||||
context 'with StandardError from ActiveRecord::Migration.migrate' do
|
||||
let(:error) do
|
||||
StandardError.new(message)
|
||||
end
|
||||
|
||||
let(:message) do
|
||||
"Error during migration"
|
||||
end
|
||||
let(:message) do
|
||||
"Error during migration"
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
ActiveRecord::Migrator.stub(:migrate).and_raise(error)
|
||||
end
|
||||
before(:each) do
|
||||
ActiveRecord::Migrator.stub(:migrate).and_raise(error)
|
||||
end
|
||||
|
||||
it 'should set Msf::DBManager#error' do
|
||||
migrate
|
||||
it 'should set Msf::DBManager#error' do
|
||||
migrate
|
||||
|
||||
db_manager.error.should == error
|
||||
end
|
||||
db_manager.error.should == error
|
||||
end
|
||||
|
||||
it 'should log error message at error level' do
|
||||
db_manager.should_receive(:elog) do |error_message|
|
||||
error_message.should include(error.to_s)
|
||||
end
|
||||
it 'should log error message at error level' do
|
||||
db_manager.should_receive(:elog) do |error_message|
|
||||
error_message.should include(error.to_s)
|
||||
end
|
||||
|
||||
migrate
|
||||
end
|
||||
migrate
|
||||
end
|
||||
|
||||
it 'should log error backtrace at debug level' do
|
||||
db_manager.should_receive(:dlog) do |debug_message|
|
||||
debug_message.should include('Call stack')
|
||||
end
|
||||
it 'should log error backtrace at debug level' do
|
||||
db_manager.should_receive(:dlog) do |debug_message|
|
||||
debug_message.should include('Call stack')
|
||||
end
|
||||
|
||||
migrate
|
||||
end
|
||||
end
|
||||
migrate
|
||||
end
|
||||
end
|
||||
|
||||
context 'with verbose' do
|
||||
def migrate
|
||||
db_manager.migrate(verbose)
|
||||
end
|
||||
context 'with verbose' do
|
||||
def migrate
|
||||
db_manager.migrate(verbose)
|
||||
end
|
||||
|
||||
context 'false' do
|
||||
let(:verbose) do
|
||||
false
|
||||
end
|
||||
context 'false' do
|
||||
let(:verbose) do
|
||||
false
|
||||
end
|
||||
|
||||
it 'should set ActiveRecord::Migration.verbose to false' do
|
||||
ActiveRecord::Migration.should_receive(:verbose=).with(verbose)
|
||||
it 'should set ActiveRecord::Migration.verbose to false' do
|
||||
ActiveRecord::Migration.should_receive(:verbose=).with(verbose)
|
||||
|
||||
migrate
|
||||
end
|
||||
end
|
||||
migrate
|
||||
end
|
||||
end
|
||||
|
||||
context 'true' do
|
||||
let(:verbose) do
|
||||
true
|
||||
end
|
||||
context 'true' do
|
||||
let(:verbose) do
|
||||
true
|
||||
end
|
||||
|
||||
it 'should set ActiveRecord::Migration.verbose to true' do
|
||||
ActiveRecord::Migration.should_receive(:verbose=).with(verbose)
|
||||
it 'should set ActiveRecord::Migration.verbose to true' do
|
||||
ActiveRecord::Migration.should_receive(:verbose=).with(verbose)
|
||||
|
||||
migrate
|
||||
end
|
||||
end
|
||||
end
|
||||
migrate
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'without verbose' do
|
||||
it 'should set ActiveRecord::Migration.verbose to false' do
|
||||
ActiveRecord::Migration.should_receive(:verbose=).with(false)
|
||||
context 'without verbose' do
|
||||
it 'should set ActiveRecord::Migration.verbose to false' do
|
||||
ActiveRecord::Migration.should_receive(:verbose=).with(false)
|
||||
|
||||
db_manager.migrate
|
||||
end
|
||||
end
|
||||
end
|
||||
db_manager.migrate
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context '#migrated' do
|
||||
it { should respond_to :migrated }
|
||||
it { should respond_to :migrated= }
|
||||
end
|
||||
context '#migrated' do
|
||||
it { should respond_to :migrated }
|
||||
it { should respond_to :migrated= }
|
||||
end
|
||||
|
||||
context '#reset_column_information' do
|
||||
def reset_column_information
|
||||
db_manager.send(:reset_column_information)
|
||||
end
|
||||
context '#reset_column_information' do
|
||||
def reset_column_information
|
||||
db_manager.send(:reset_column_information)
|
||||
end
|
||||
|
||||
it 'should use ActiveRecord::Base.descendants to find both direct and indirect subclasses' do
|
||||
ActiveRecord::Base.should_receive(:descendants).and_return([])
|
||||
it 'should use ActiveRecord::Base.descendants to find both direct and indirect subclasses' do
|
||||
ActiveRecord::Base.should_receive(:descendants).and_return([])
|
||||
|
||||
reset_column_information
|
||||
end
|
||||
reset_column_information
|
||||
end
|
||||
|
||||
it 'should reset column information on each descendant of ActiveRecord::Base' do
|
||||
descendants = []
|
||||
it 'should reset column information on each descendant of ActiveRecord::Base' do
|
||||
descendants = []
|
||||
|
||||
1.upto(2) do |i|
|
||||
descendants << double("Descendant #{i}")
|
||||
end
|
||||
1.upto(2) do |i|
|
||||
descendants << double("Descendant #{i}")
|
||||
end
|
||||
|
||||
ActiveRecord::Base.stub(:descendants => descendants)
|
||||
ActiveRecord::Base.stub(:descendants => descendants)
|
||||
|
||||
descendants.each do |descendant|
|
||||
descendant.should_receive(:reset_column_information)
|
||||
end
|
||||
descendants.each do |descendant|
|
||||
descendant.should_receive(:reset_column_information)
|
||||
end
|
||||
|
||||
reset_column_information
|
||||
end
|
||||
end
|
||||
reset_column_information
|
||||
end
|
||||
end
|
||||
end
|
||||
+38
-38
@@ -1,49 +1,49 @@
|
||||
shared_examples_for 'Msf::DBManager#search_modules Mdm::Module::Platform#name or Mdm::Module::Target#name keyword' do |keyword|
|
||||
context "with #{keyword} keyword" do
|
||||
let(:search_string) do
|
||||
"#{keyword}:#{name}"
|
||||
end
|
||||
context "with #{keyword} keyword" do
|
||||
let(:search_string) do
|
||||
"#{keyword}:#{name}"
|
||||
end
|
||||
|
||||
let!(:module_platform) do
|
||||
FactoryGirl.create(:mdm_module_platform)
|
||||
end
|
||||
let!(:module_platform) do
|
||||
FactoryGirl.create(:mdm_module_platform)
|
||||
end
|
||||
|
||||
let!(:module_target) do
|
||||
FactoryGirl.create(:mdm_module_target)
|
||||
end
|
||||
let!(:module_target) do
|
||||
FactoryGirl.create(:mdm_module_target)
|
||||
end
|
||||
|
||||
context 'with Mdm::Module::Platform#name' do
|
||||
let(:name) do
|
||||
# use inspect to quote spaces in string
|
||||
module_platform.name.inspect
|
||||
end
|
||||
context 'with Mdm::Module::Platform#name' do
|
||||
let(:name) do
|
||||
# use inspect to quote spaces in string
|
||||
module_platform.name.inspect
|
||||
end
|
||||
|
||||
it 'should find matching Mdm::Module::Platform#name' do
|
||||
module_details.count.should > 0
|
||||
it 'should find matching Mdm::Module::Platform#name' do
|
||||
module_details.count.should > 0
|
||||
|
||||
module_details.all? { |module_detail|
|
||||
module_detail.platforms.any? { |module_platform|
|
||||
module_platform.name == self.module_platform.name
|
||||
}
|
||||
}.should be_true
|
||||
end
|
||||
end
|
||||
module_details.all? { |module_detail|
|
||||
module_detail.platforms.any? { |module_platform|
|
||||
module_platform.name == self.module_platform.name
|
||||
}
|
||||
}.should be_true
|
||||
end
|
||||
end
|
||||
|
||||
context 'with Mdm::Module::Target#name' do
|
||||
let(:name) do
|
||||
context 'with Mdm::Module::Target#name' do
|
||||
let(:name) do
|
||||
# use inspect to quote spaces in string
|
||||
module_target.name.inspect
|
||||
end
|
||||
module_target.name.inspect
|
||||
end
|
||||
|
||||
it 'should find matching Mdm::Module::Target#name' do
|
||||
module_details.count.should > 0
|
||||
it 'should find matching Mdm::Module::Target#name' do
|
||||
module_details.count.should > 0
|
||||
|
||||
module_details.all? { |module_detail|
|
||||
module_detail.targets.any? { |module_target|
|
||||
module_target.name == self.module_target.name
|
||||
}
|
||||
}.should be_true
|
||||
end
|
||||
end
|
||||
end
|
||||
module_details.all? { |module_detail|
|
||||
module_detail.targets.any? { |module_target|
|
||||
module_target.name == self.module_target.name
|
||||
}
|
||||
}.should be_true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
+34
-34
@@ -1,44 +1,44 @@
|
||||
shared_examples_for 'Msf::DBManager#search_modules Mdm::Module::Ref#name keyword' do |keyword|
|
||||
context "with #{keyword} keyword" do
|
||||
let(keyword) do
|
||||
1
|
||||
end
|
||||
context "with #{keyword} keyword" do
|
||||
let(keyword) do
|
||||
1
|
||||
end
|
||||
|
||||
let(:name) do
|
||||
FactoryGirl.generate :mdm_module_ref_name
|
||||
end
|
||||
let(:name) do
|
||||
FactoryGirl.generate :mdm_module_ref_name
|
||||
end
|
||||
|
||||
let(:search_string) do
|
||||
"#{keyword}:#{send(keyword)}"
|
||||
end
|
||||
let(:search_string) do
|
||||
"#{keyword}:#{send(keyword)}"
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
FactoryGirl.create(:mdm_module_ref, :name => name)
|
||||
end
|
||||
before(:each) do
|
||||
FactoryGirl.create(:mdm_module_ref, :name => name)
|
||||
end
|
||||
|
||||
name_prefix = "#{keyword.to_s.upcase}-"
|
||||
context_suffix = "Mdm::Module::Ref#name starting with #{name_prefix.inspect}"
|
||||
name_prefix = "#{keyword.to_s.upcase}-"
|
||||
context_suffix = "Mdm::Module::Ref#name starting with #{name_prefix.inspect}"
|
||||
|
||||
context "with #{context_suffix}" do
|
||||
let(:name) do
|
||||
"#{name_prefix}#{send(keyword)}"
|
||||
end
|
||||
context "with #{context_suffix}" do
|
||||
let(:name) do
|
||||
"#{name_prefix}#{send(keyword)}"
|
||||
end
|
||||
|
||||
it 'should match Mdm::Module::Ref#name' do
|
||||
module_details.count.should > 0
|
||||
it 'should match Mdm::Module::Ref#name' do
|
||||
module_details.count.should > 0
|
||||
|
||||
module_details.all? { |module_detail|
|
||||
module_detail.refs.any? { |module_ref|
|
||||
module_ref.name == name
|
||||
}
|
||||
}.should be_true
|
||||
end
|
||||
end
|
||||
module_details.all? { |module_detail|
|
||||
module_detail.refs.any? { |module_ref|
|
||||
module_ref.name == name
|
||||
}
|
||||
}.should be_true
|
||||
end
|
||||
end
|
||||
|
||||
context "without #{context_suffix}" do
|
||||
it 'should not match Mdm::Module::Ref#name' do
|
||||
module_details.count.should == 0
|
||||
end
|
||||
end
|
||||
end
|
||||
context "without #{context_suffix}" do
|
||||
it 'should not match Mdm::Module::Ref#name' do
|
||||
module_details.count.should == 0
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,60 +1,60 @@
|
||||
shared_examples_for 'Msf::DBManager#update_all_module_details refresh' do
|
||||
|
||||
it 'should destroy Mdm::Module::Detail' do
|
||||
expect {
|
||||
update_all_module_details
|
||||
}.to change(Mdm::Module::Detail, :count).by(-1)
|
||||
end
|
||||
it 'should destroy Mdm::Module::Detail' do
|
||||
expect {
|
||||
update_all_module_details
|
||||
}.to change(Mdm::Module::Detail, :count).by(-1)
|
||||
end
|
||||
|
||||
context 'with cached module in Msf::ModuleSet' do
|
||||
let(:module_set) do
|
||||
framework.exploits
|
||||
end
|
||||
context 'with cached module in Msf::ModuleSet' do
|
||||
let(:module_set) do
|
||||
framework.exploits
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
module_set[module_detail.refname] = Msf::SymbolicModule
|
||||
before(:each) do
|
||||
module_set[module_detail.refname] = Msf::SymbolicModule
|
||||
|
||||
framework.modules.send(:module_info_by_path)[module_detail.file] = {
|
||||
:parent_path => Metasploit::Framework.root.join('modules').to_path,
|
||||
:reference_name => module_detail.refname,
|
||||
:type => type
|
||||
}
|
||||
end
|
||||
framework.modules.send(:module_info_by_path)[module_detail.file] = {
|
||||
:parent_path => Metasploit::Framework.root.join('modules').to_path,
|
||||
:reference_name => module_detail.refname,
|
||||
:type => type
|
||||
}
|
||||
end
|
||||
|
||||
it 'should create instance of module corresponding to Mdm::Module::Detail' do
|
||||
module_set.should_receive(:create).with(module_detail.refname)
|
||||
it 'should create instance of module corresponding to Mdm::Module::Detail' do
|
||||
module_set.should_receive(:create).with(module_detail.refname)
|
||||
|
||||
update_all_module_details
|
||||
end
|
||||
update_all_module_details
|
||||
end
|
||||
|
||||
it 'should call update_module_details to create a new Mdm::Module::Detail from the module instance returned by create' do
|
||||
db_manager.should_receive(:update_module_details) do |module_instance|
|
||||
module_instance.should be_a Msf::Module
|
||||
module_instance.type.should == module_detail.mtype
|
||||
module_instance.refname.should == module_detail.refname
|
||||
end
|
||||
it 'should call update_module_details to create a new Mdm::Module::Detail from the module instance returned by create' do
|
||||
db_manager.should_receive(:update_module_details) do |module_instance|
|
||||
module_instance.should be_a Msf::Module
|
||||
module_instance.type.should == module_detail.mtype
|
||||
module_instance.refname.should == module_detail.refname
|
||||
end
|
||||
|
||||
update_all_module_details
|
||||
end
|
||||
update_all_module_details
|
||||
end
|
||||
|
||||
context 'with exception raised by #update_module_details' do
|
||||
before(:each) do
|
||||
db_manager.stub(:update_module_details).and_raise(Exception)
|
||||
end
|
||||
context 'with exception raised by #update_module_details' do
|
||||
before(:each) do
|
||||
db_manager.stub(:update_module_details).and_raise(Exception)
|
||||
end
|
||||
|
||||
it 'should log error' do
|
||||
db_manager.should_receive(:elog)
|
||||
it 'should log error' do
|
||||
db_manager.should_receive(:elog)
|
||||
|
||||
update_all_module_details
|
||||
end
|
||||
end
|
||||
end
|
||||
update_all_module_details
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'without cached module in Msf::ModuleSet' do
|
||||
it 'should not call update_module_details' do
|
||||
db_manager.should_not_receive(:update_module_details)
|
||||
context 'without cached module in Msf::ModuleSet' do
|
||||
it 'should not call update_module_details' do
|
||||
db_manager.should_not_receive(:update_module_details)
|
||||
|
||||
update_all_module_details
|
||||
end
|
||||
end
|
||||
update_all_module_details
|
||||
end
|
||||
end
|
||||
end
|
||||
+19
-19
@@ -1,26 +1,26 @@
|
||||
shared_examples_for 'Msf::DBManager#update_module_details with module' do |options={}|
|
||||
options.assert_valid_keys(:reference_name, :type)
|
||||
options.assert_valid_keys(:reference_name, :type)
|
||||
|
||||
reference_name = options.fetch(:reference_name)
|
||||
type = options.fetch(:type)
|
||||
reference_name = options.fetch(:reference_name)
|
||||
type = options.fetch(:type)
|
||||
|
||||
context "with #{type.inspect}" do
|
||||
let(:module_reference_name) do
|
||||
reference_name
|
||||
end
|
||||
context "with #{type.inspect}" do
|
||||
let(:module_reference_name) do
|
||||
reference_name
|
||||
end
|
||||
|
||||
let(:module_type) do
|
||||
type
|
||||
end
|
||||
let(:module_type) do
|
||||
type
|
||||
end
|
||||
|
||||
it "should use module_instance with #{type.inspect} type" do
|
||||
module_instance.type.should == type
|
||||
end
|
||||
it "should use module_instance with #{type.inspect} type" do
|
||||
module_instance.type.should == type
|
||||
end
|
||||
|
||||
it 'should not raise error' do
|
||||
expect {
|
||||
update_module_details
|
||||
}.to_not raise_error
|
||||
end
|
||||
end
|
||||
it 'should not raise error' do
|
||||
expect {
|
||||
update_module_details
|
||||
}.to_not raise_error
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,480 +1,480 @@
|
||||
shared_examples_for 'Msf::ModuleManager::Cache' do
|
||||
let(:parent_path) do
|
||||
parent_pathname.to_path
|
||||
end
|
||||
|
||||
let(:parent_pathname) do
|
||||
Metasploit::Framework.root.join('modules')
|
||||
end
|
||||
|
||||
let(:reference_name) do
|
||||
'windows/smb/ms08_067_netapi'
|
||||
end
|
||||
|
||||
let(:type) do
|
||||
'exploit'
|
||||
end
|
||||
|
||||
let(:path) do
|
||||
pathname.to_path
|
||||
end
|
||||
|
||||
let(:pathname) do
|
||||
parent_pathname.join(
|
||||
'exploits',
|
||||
"#{reference_name}.rb"
|
||||
)
|
||||
end
|
||||
|
||||
let(:pathname_modification_time) do
|
||||
pathname.mtime
|
||||
end
|
||||
|
||||
context '#cache_empty?' do
|
||||
subject(:cache_empty?) do
|
||||
module_manager.cache_empty?
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
module_manager.send(:module_info_by_path=, module_info_by_path)
|
||||
end
|
||||
|
||||
context 'with empty' do
|
||||
let(:module_info_by_path) do
|
||||
{}
|
||||
end
|
||||
|
||||
it { should be_true }
|
||||
end
|
||||
|
||||
context 'without empty' do
|
||||
let(:module_info_by_path) do
|
||||
{
|
||||
'path/to/module' => {}
|
||||
}
|
||||
end
|
||||
|
||||
it { should be_false }
|
||||
end
|
||||
end
|
||||
|
||||
context '#cache_in_memory' do
|
||||
def cache_in_memory
|
||||
module_manager.cache_in_memory(
|
||||
class_or_module,
|
||||
:path => path,
|
||||
:reference_name => reference_name,
|
||||
:type => type
|
||||
)
|
||||
end
|
||||
|
||||
def module_info_by_path
|
||||
module_manager.send(:module_info_by_path)
|
||||
end
|
||||
|
||||
let(:class_or_module) do
|
||||
double('Class<Msf::Module> or Module', :parent => namespace_module)
|
||||
end
|
||||
|
||||
let(:namespace_module) do
|
||||
double('Msf::Modules::Namespace', :parent_path => parent_path)
|
||||
end
|
||||
|
||||
context 'with existing :path' do
|
||||
it 'should update module_info_by_path' do
|
||||
expect {
|
||||
cache_in_memory
|
||||
}.to change { module_info_by_path }
|
||||
end
|
||||
|
||||
context 'module_info_by_path' do
|
||||
subject(:module_info_by_path) do
|
||||
module_manager.send(:module_info_by_path)
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
cache_in_memory
|
||||
end
|
||||
|
||||
it 'should have entry for path' do
|
||||
module_info_by_path[path].should be_a Hash
|
||||
end
|
||||
|
||||
context 'value' do
|
||||
subject(:value) do
|
||||
module_info_by_path[path]
|
||||
end
|
||||
|
||||
it 'should have modification time of :path option for :modification_time' do
|
||||
value[:modification_time].should == pathname_modification_time
|
||||
end
|
||||
|
||||
it 'should have parent path from namespace module for :parent_path' do
|
||||
value[:parent_path].should == namespace_module.parent_path
|
||||
end
|
||||
|
||||
it 'should use :reference_name option' do
|
||||
value[:reference_name].should == reference_name
|
||||
end
|
||||
|
||||
it 'should use :type option' do
|
||||
value[:type].should == type
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'without existing :path' do
|
||||
let(:path) do
|
||||
'non/existent/path'
|
||||
end
|
||||
|
||||
it 'should not raise error' do
|
||||
expect {
|
||||
cache_in_memory
|
||||
}.to_not raise_error
|
||||
end
|
||||
|
||||
it 'should not update module_info_by_path' do
|
||||
expect {
|
||||
cache_in_memory
|
||||
}.to_not change { module_info_by_path }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context '#load_cached_module' do
|
||||
subject(:load_cached_module) do
|
||||
module_manager.load_cached_module(type, reference_name)
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
module_manager.send(:module_info_by_path=, module_info_by_path)
|
||||
end
|
||||
|
||||
context 'with module info in cache' do
|
||||
let(:module_info_by_path) do
|
||||
{
|
||||
'path/to/module' => {
|
||||
:parent_path => parent_path,
|
||||
:reference_name => reference_name,
|
||||
:type => type
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it 'should enumerate loaders until if it find the one where loadable?(parent_path) is true' do
|
||||
module_manager.send(:loaders).each do |loader|
|
||||
loader.should_receive(:loadable?).with(parent_path).and_call_original
|
||||
end
|
||||
|
||||
load_cached_module
|
||||
end
|
||||
|
||||
it 'should force load using #load_module on the loader' do
|
||||
Msf::Modules::Loader::Directory.any_instance.should_receive(
|
||||
:load_module
|
||||
).with(
|
||||
parent_path,
|
||||
type,
|
||||
reference_name,
|
||||
:force => true
|
||||
).and_call_original
|
||||
|
||||
load_cached_module
|
||||
end
|
||||
|
||||
context 'return from load_module' do
|
||||
before(:each) do
|
||||
module_manager.send(:loaders).each do |loader|
|
||||
loader.stub(:load_module => module_loaded)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with false' do
|
||||
let(:module_loaded) do
|
||||
false
|
||||
end
|
||||
|
||||
it { should be_false }
|
||||
end
|
||||
|
||||
context 'with true' do
|
||||
let(:module_loaded) do
|
||||
true
|
||||
end
|
||||
|
||||
it { should be_true }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'without module info in cache' do
|
||||
let(:module_info_by_path) do
|
||||
{}
|
||||
end
|
||||
|
||||
it { should be_false }
|
||||
end
|
||||
end
|
||||
|
||||
context '#refresh_cache_from_module_files' do
|
||||
before(:each) do
|
||||
module_manager.stub(:framework_migrated? => framework_migrated?)
|
||||
end
|
||||
|
||||
context 'with framework migrated' do
|
||||
let(:framework_migrated?) do
|
||||
true
|
||||
end
|
||||
|
||||
context 'with module argument' do
|
||||
def refresh_cache_from_module_files
|
||||
module_manager.refresh_cache_from_module_files(module_class_or_instance)
|
||||
end
|
||||
|
||||
let(:module_class_or_instance) do
|
||||
Class.new(Msf::Module)
|
||||
end
|
||||
|
||||
it 'should update database and then update in-memory cache from the database for the given module_class_or_instance' do
|
||||
framework.db.should_receive(:update_module_details).with(module_class_or_instance).ordered
|
||||
module_manager.should_receive(:refresh_cache_from_database).ordered
|
||||
|
||||
refresh_cache_from_module_files
|
||||
end
|
||||
end
|
||||
|
||||
context 'without module argument' do
|
||||
def refresh_cache_from_module_files
|
||||
module_manager.refresh_cache_from_module_files
|
||||
end
|
||||
|
||||
it 'should update database and then update in-memory cache from the database for all modules' do
|
||||
framework.db.should_receive(:update_all_module_details).ordered
|
||||
module_manager.should_receive(:refresh_cache_from_database)
|
||||
|
||||
refresh_cache_from_module_files
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'without framework migrated' do
|
||||
def refresh_cache_from_module_files
|
||||
module_manager.refresh_cache_from_module_files
|
||||
end
|
||||
|
||||
let(:framework_migrated?) do
|
||||
false
|
||||
end
|
||||
|
||||
it 'should not call Msf::DBManager#update_module_details' do
|
||||
framework.db.should_not_receive(:update_module_details)
|
||||
|
||||
refresh_cache_from_module_files
|
||||
end
|
||||
|
||||
it 'should not call Msf::DBManager#update_all_module_details' do
|
||||
framework.db.should_not_receive(:update_all_module_details)
|
||||
|
||||
refresh_cache_from_module_files
|
||||
end
|
||||
|
||||
it 'should not call #refresh_cache_from_database' do
|
||||
module_manager.should_not_receive(:refresh_cache_from_database)
|
||||
|
||||
refresh_cache_from_module_files
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context '#refresh_cache_from_database' do
|
||||
def refresh_cache_from_database
|
||||
module_manager.refresh_cache_from_database
|
||||
end
|
||||
|
||||
it 'should call #module_info_by_path_from_database!' do
|
||||
module_manager.should_receive(:module_info_by_path_from_database!)
|
||||
|
||||
refresh_cache_from_database
|
||||
end
|
||||
end
|
||||
|
||||
context '#framework_migrated?' do
|
||||
subject(:framework_migrated?) do
|
||||
module_manager.send(:framework_migrated?)
|
||||
end
|
||||
|
||||
context 'with framework database' do
|
||||
before(:each) do
|
||||
framework.db.stub(:migrated => migrated)
|
||||
end
|
||||
|
||||
context 'with migrated' do
|
||||
let(:migrated) do
|
||||
true
|
||||
end
|
||||
|
||||
it { should be_true }
|
||||
end
|
||||
|
||||
context 'without migrated' do
|
||||
let(:migrated) do
|
||||
false
|
||||
end
|
||||
|
||||
it { should be_false }
|
||||
end
|
||||
end
|
||||
|
||||
context 'without framework database' do
|
||||
before(:each) do
|
||||
framework.stub(:db => nil)
|
||||
end
|
||||
|
||||
it { should be_false }
|
||||
end
|
||||
end
|
||||
|
||||
context '#module_info_by_path' do
|
||||
it { should respond_to(:module_info_by_path) }
|
||||
end
|
||||
|
||||
context '#module_info_by_path=' do
|
||||
it { should respond_to(:module_info_by_path=) }
|
||||
end
|
||||
|
||||
context '#module_info_by_path_from_database!' do
|
||||
def module_info_by_path
|
||||
module_manager.send(:module_info_by_path)
|
||||
end
|
||||
|
||||
def module_info_by_path_from_database!
|
||||
module_manager.send(:module_info_by_path_from_database!)
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
module_manager.stub(:framework_migrated? => framework_migrated?)
|
||||
end
|
||||
|
||||
context 'with framework migrated' do
|
||||
include_context 'DatabaseCleaner'
|
||||
|
||||
let(:framework_migrated?) do
|
||||
true
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
configurations = Metasploit::Framework::Database.configurations
|
||||
spec = configurations[Metasploit::Framework.env]
|
||||
|
||||
# Need to connect or ActiveRecord::Base.connection_pool will raise an
|
||||
# error.
|
||||
framework.db.connect(spec)
|
||||
end
|
||||
|
||||
it 'should call ActiveRecord::Base.connection_pool.with_connection' do
|
||||
# 1st is from with_established_connection
|
||||
# 2nd is from module_info_by_path_from_database!
|
||||
ActiveRecord::Base.connection_pool.should_receive(:with_connection).at_least(2).times
|
||||
|
||||
module_info_by_path_from_database!
|
||||
end
|
||||
|
||||
it 'should use ActiveRecord::Batches#find_each to enumerate Mdm::Module::Details in batches' do
|
||||
Mdm::Module::Detail.should_receive(:find_each)
|
||||
|
||||
module_info_by_path_from_database!
|
||||
let(:parent_path) do
|
||||
parent_pathname.to_path
|
||||
end
|
||||
|
||||
let(:parent_pathname) do
|
||||
Metasploit::Framework.root.join('modules')
|
||||
end
|
||||
|
||||
let(:reference_name) do
|
||||
'windows/smb/ms08_067_netapi'
|
||||
end
|
||||
|
||||
let(:type) do
|
||||
'exploit'
|
||||
end
|
||||
|
||||
let(:path) do
|
||||
pathname.to_path
|
||||
end
|
||||
|
||||
let(:pathname) do
|
||||
parent_pathname.join(
|
||||
'exploits',
|
||||
"#{reference_name}.rb"
|
||||
)
|
||||
end
|
||||
|
||||
let(:pathname_modification_time) do
|
||||
pathname.mtime
|
||||
end
|
||||
|
||||
context '#cache_empty?' do
|
||||
subject(:cache_empty?) do
|
||||
module_manager.cache_empty?
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
module_manager.send(:module_info_by_path=, module_info_by_path)
|
||||
end
|
||||
|
||||
context 'with empty' do
|
||||
let(:module_info_by_path) do
|
||||
{}
|
||||
end
|
||||
|
||||
context 'with database cache' do
|
||||
#
|
||||
# Let!s (let + before(:each))
|
||||
#
|
||||
it { should be_true }
|
||||
end
|
||||
|
||||
let!(:mdm_module_detail) do
|
||||
FactoryGirl.create(:mdm_module_detail,
|
||||
:file => path,
|
||||
:mtype => type,
|
||||
:mtime => pathname.mtime,
|
||||
:refname => reference_name
|
||||
)
|
||||
end
|
||||
context 'without empty' do
|
||||
let(:module_info_by_path) do
|
||||
{
|
||||
'path/to/module' => {}
|
||||
}
|
||||
end
|
||||
|
||||
it 'should create cache entry for path' do
|
||||
module_info_by_path_from_database!
|
||||
it { should be_false }
|
||||
end
|
||||
end
|
||||
|
||||
module_info_by_path.should have_key(path)
|
||||
end
|
||||
context '#cache_in_memory' do
|
||||
def cache_in_memory
|
||||
module_manager.cache_in_memory(
|
||||
class_or_module,
|
||||
:path => path,
|
||||
:reference_name => reference_name,
|
||||
:type => type
|
||||
)
|
||||
end
|
||||
|
||||
it 'should use Msf::Modules::Loader::Base.typed_path to derive parent_path' do
|
||||
Msf::Modules::Loader::Base.should_receive(:typed_path).with(type, reference_name).and_call_original
|
||||
def module_info_by_path
|
||||
module_manager.send(:module_info_by_path)
|
||||
end
|
||||
|
||||
module_info_by_path_from_database!
|
||||
end
|
||||
let(:class_or_module) do
|
||||
double('Class<Msf::Module> or Module', :parent => namespace_module)
|
||||
end
|
||||
|
||||
context 'cache entry' do
|
||||
subject(:cache_entry) do
|
||||
module_info_by_path[path]
|
||||
end
|
||||
let(:namespace_module) do
|
||||
double('Msf::Modules::Namespace', :parent_path => parent_path)
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
module_info_by_path_from_database!
|
||||
end
|
||||
context 'with existing :path' do
|
||||
it 'should update module_info_by_path' do
|
||||
expect {
|
||||
cache_in_memory
|
||||
}.to change { module_info_by_path }
|
||||
end
|
||||
|
||||
its([:modification_time]) { should be_within(1.second).of(pathname_modification_time) }
|
||||
its([:parent_path]) { should == parent_path }
|
||||
its([:reference_name]) { should == reference_name }
|
||||
its([:type]) { should == type }
|
||||
end
|
||||
context 'module_info_by_path' do
|
||||
subject(:module_info_by_path) do
|
||||
module_manager.send(:module_info_by_path)
|
||||
end
|
||||
|
||||
context 'typed module set' do
|
||||
let(:typed_module_set) do
|
||||
module_manager.module_set(type)
|
||||
end
|
||||
before(:each) do
|
||||
cache_in_memory
|
||||
end
|
||||
|
||||
context 'with reference_name' do
|
||||
before(:each) do
|
||||
typed_module_set[reference_name] = double('Msf::Module')
|
||||
end
|
||||
it 'should have entry for path' do
|
||||
module_info_by_path[path].should be_a Hash
|
||||
end
|
||||
|
||||
it 'should not change reference_name value' do
|
||||
expect {
|
||||
module_info_by_path_from_database!
|
||||
}.to_not change {
|
||||
typed_module_set[reference_name]
|
||||
}
|
||||
end
|
||||
end
|
||||
context 'value' do
|
||||
subject(:value) do
|
||||
module_info_by_path[path]
|
||||
end
|
||||
|
||||
context 'without reference_name' do
|
||||
it 'should set reference_name value to Msf::SymbolicModule' do
|
||||
module_info_by_path_from_database!
|
||||
it 'should have modification time of :path option for :modification_time' do
|
||||
value[:modification_time].should == pathname_modification_time
|
||||
end
|
||||
|
||||
# have to use fetch because [] will trigger de-symbolization and
|
||||
# instantiation.
|
||||
typed_module_set.fetch(reference_name).should == Msf::SymbolicModule
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
it 'should have parent path from namespace module for :parent_path' do
|
||||
value[:parent_path].should == namespace_module.parent_path
|
||||
end
|
||||
|
||||
context 'without framework migrated' do
|
||||
let(:framework_migrated?) do
|
||||
false
|
||||
end
|
||||
it 'should use :reference_name option' do
|
||||
value[:reference_name].should == reference_name
|
||||
end
|
||||
|
||||
it { should_not query_the_database.when_calling(:module_info_by_path_from_database!) }
|
||||
it 'should use :type option' do
|
||||
value[:type].should == type
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it 'should reset #module_info_by_path' do
|
||||
# pre-fill module_info_by_path so change can be detected
|
||||
module_manager.send(:module_info_by_path=, double('In-memory Cache'))
|
||||
context 'without existing :path' do
|
||||
let(:path) do
|
||||
'non/existent/path'
|
||||
end
|
||||
|
||||
module_info_by_path_from_database!
|
||||
it 'should not raise error' do
|
||||
expect {
|
||||
cache_in_memory
|
||||
}.to_not raise_error
|
||||
end
|
||||
|
||||
module_info_by_path.should be_empty
|
||||
end
|
||||
end
|
||||
end
|
||||
it 'should not update module_info_by_path' do
|
||||
expect {
|
||||
cache_in_memory
|
||||
}.to_not change { module_info_by_path }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context '#load_cached_module' do
|
||||
subject(:load_cached_module) do
|
||||
module_manager.load_cached_module(type, reference_name)
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
module_manager.send(:module_info_by_path=, module_info_by_path)
|
||||
end
|
||||
|
||||
context 'with module info in cache' do
|
||||
let(:module_info_by_path) do
|
||||
{
|
||||
'path/to/module' => {
|
||||
:parent_path => parent_path,
|
||||
:reference_name => reference_name,
|
||||
:type => type
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it 'should enumerate loaders until if it find the one where loadable?(parent_path) is true' do
|
||||
module_manager.send(:loaders).each do |loader|
|
||||
loader.should_receive(:loadable?).with(parent_path).and_call_original
|
||||
end
|
||||
|
||||
load_cached_module
|
||||
end
|
||||
|
||||
it 'should force load using #load_module on the loader' do
|
||||
Msf::Modules::Loader::Directory.any_instance.should_receive(
|
||||
:load_module
|
||||
).with(
|
||||
parent_path,
|
||||
type,
|
||||
reference_name,
|
||||
:force => true
|
||||
).and_call_original
|
||||
|
||||
load_cached_module
|
||||
end
|
||||
|
||||
context 'return from load_module' do
|
||||
before(:each) do
|
||||
module_manager.send(:loaders).each do |loader|
|
||||
loader.stub(:load_module => module_loaded)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with false' do
|
||||
let(:module_loaded) do
|
||||
false
|
||||
end
|
||||
|
||||
it { should be_false }
|
||||
end
|
||||
|
||||
context 'with true' do
|
||||
let(:module_loaded) do
|
||||
true
|
||||
end
|
||||
|
||||
it { should be_true }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'without module info in cache' do
|
||||
let(:module_info_by_path) do
|
||||
{}
|
||||
end
|
||||
|
||||
it { should be_false }
|
||||
end
|
||||
end
|
||||
|
||||
context '#refresh_cache_from_module_files' do
|
||||
before(:each) do
|
||||
module_manager.stub(:framework_migrated? => framework_migrated?)
|
||||
end
|
||||
|
||||
context 'with framework migrated' do
|
||||
let(:framework_migrated?) do
|
||||
true
|
||||
end
|
||||
|
||||
context 'with module argument' do
|
||||
def refresh_cache_from_module_files
|
||||
module_manager.refresh_cache_from_module_files(module_class_or_instance)
|
||||
end
|
||||
|
||||
let(:module_class_or_instance) do
|
||||
Class.new(Msf::Module)
|
||||
end
|
||||
|
||||
it 'should update database and then update in-memory cache from the database for the given module_class_or_instance' do
|
||||
framework.db.should_receive(:update_module_details).with(module_class_or_instance).ordered
|
||||
module_manager.should_receive(:refresh_cache_from_database).ordered
|
||||
|
||||
refresh_cache_from_module_files
|
||||
end
|
||||
end
|
||||
|
||||
context 'without module argument' do
|
||||
def refresh_cache_from_module_files
|
||||
module_manager.refresh_cache_from_module_files
|
||||
end
|
||||
|
||||
it 'should update database and then update in-memory cache from the database for all modules' do
|
||||
framework.db.should_receive(:update_all_module_details).ordered
|
||||
module_manager.should_receive(:refresh_cache_from_database)
|
||||
|
||||
refresh_cache_from_module_files
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'without framework migrated' do
|
||||
def refresh_cache_from_module_files
|
||||
module_manager.refresh_cache_from_module_files
|
||||
end
|
||||
|
||||
let(:framework_migrated?) do
|
||||
false
|
||||
end
|
||||
|
||||
it 'should not call Msf::DBManager#update_module_details' do
|
||||
framework.db.should_not_receive(:update_module_details)
|
||||
|
||||
refresh_cache_from_module_files
|
||||
end
|
||||
|
||||
it 'should not call Msf::DBManager#update_all_module_details' do
|
||||
framework.db.should_not_receive(:update_all_module_details)
|
||||
|
||||
refresh_cache_from_module_files
|
||||
end
|
||||
|
||||
it 'should not call #refresh_cache_from_database' do
|
||||
module_manager.should_not_receive(:refresh_cache_from_database)
|
||||
|
||||
refresh_cache_from_module_files
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context '#refresh_cache_from_database' do
|
||||
def refresh_cache_from_database
|
||||
module_manager.refresh_cache_from_database
|
||||
end
|
||||
|
||||
it 'should call #module_info_by_path_from_database!' do
|
||||
module_manager.should_receive(:module_info_by_path_from_database!)
|
||||
|
||||
refresh_cache_from_database
|
||||
end
|
||||
end
|
||||
|
||||
context '#framework_migrated?' do
|
||||
subject(:framework_migrated?) do
|
||||
module_manager.send(:framework_migrated?)
|
||||
end
|
||||
|
||||
context 'with framework database' do
|
||||
before(:each) do
|
||||
framework.db.stub(:migrated => migrated)
|
||||
end
|
||||
|
||||
context 'with migrated' do
|
||||
let(:migrated) do
|
||||
true
|
||||
end
|
||||
|
||||
it { should be_true }
|
||||
end
|
||||
|
||||
context 'without migrated' do
|
||||
let(:migrated) do
|
||||
false
|
||||
end
|
||||
|
||||
it { should be_false }
|
||||
end
|
||||
end
|
||||
|
||||
context 'without framework database' do
|
||||
before(:each) do
|
||||
framework.stub(:db => nil)
|
||||
end
|
||||
|
||||
it { should be_false }
|
||||
end
|
||||
end
|
||||
|
||||
context '#module_info_by_path' do
|
||||
it { should respond_to(:module_info_by_path) }
|
||||
end
|
||||
|
||||
context '#module_info_by_path=' do
|
||||
it { should respond_to(:module_info_by_path=) }
|
||||
end
|
||||
|
||||
context '#module_info_by_path_from_database!' do
|
||||
def module_info_by_path
|
||||
module_manager.send(:module_info_by_path)
|
||||
end
|
||||
|
||||
def module_info_by_path_from_database!
|
||||
module_manager.send(:module_info_by_path_from_database!)
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
module_manager.stub(:framework_migrated? => framework_migrated?)
|
||||
end
|
||||
|
||||
context 'with framework migrated' do
|
||||
include_context 'DatabaseCleaner'
|
||||
|
||||
let(:framework_migrated?) do
|
||||
true
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
configurations = Metasploit::Framework::Database.configurations
|
||||
spec = configurations[Metasploit::Framework.env]
|
||||
|
||||
# Need to connect or ActiveRecord::Base.connection_pool will raise an
|
||||
# error.
|
||||
framework.db.connect(spec)
|
||||
end
|
||||
|
||||
it 'should call ActiveRecord::Base.connection_pool.with_connection' do
|
||||
# 1st is from with_established_connection
|
||||
# 2nd is from module_info_by_path_from_database!
|
||||
ActiveRecord::Base.connection_pool.should_receive(:with_connection).at_least(2).times
|
||||
|
||||
module_info_by_path_from_database!
|
||||
end
|
||||
|
||||
it 'should use ActiveRecord::Batches#find_each to enumerate Mdm::Module::Details in batches' do
|
||||
Mdm::Module::Detail.should_receive(:find_each)
|
||||
|
||||
module_info_by_path_from_database!
|
||||
end
|
||||
|
||||
context 'with database cache' do
|
||||
#
|
||||
# Let!s (let + before(:each))
|
||||
#
|
||||
|
||||
let!(:mdm_module_detail) do
|
||||
FactoryGirl.create(:mdm_module_detail,
|
||||
:file => path,
|
||||
:mtype => type,
|
||||
:mtime => pathname.mtime,
|
||||
:refname => reference_name
|
||||
)
|
||||
end
|
||||
|
||||
it 'should create cache entry for path' do
|
||||
module_info_by_path_from_database!
|
||||
|
||||
module_info_by_path.should have_key(path)
|
||||
end
|
||||
|
||||
it 'should use Msf::Modules::Loader::Base.typed_path to derive parent_path' do
|
||||
Msf::Modules::Loader::Base.should_receive(:typed_path).with(type, reference_name).and_call_original
|
||||
|
||||
module_info_by_path_from_database!
|
||||
end
|
||||
|
||||
context 'cache entry' do
|
||||
subject(:cache_entry) do
|
||||
module_info_by_path[path]
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
module_info_by_path_from_database!
|
||||
end
|
||||
|
||||
its([:modification_time]) { should be_within(1.second).of(pathname_modification_time) }
|
||||
its([:parent_path]) { should == parent_path }
|
||||
its([:reference_name]) { should == reference_name }
|
||||
its([:type]) { should == type }
|
||||
end
|
||||
|
||||
context 'typed module set' do
|
||||
let(:typed_module_set) do
|
||||
module_manager.module_set(type)
|
||||
end
|
||||
|
||||
context 'with reference_name' do
|
||||
before(:each) do
|
||||
typed_module_set[reference_name] = double('Msf::Module')
|
||||
end
|
||||
|
||||
it 'should not change reference_name value' do
|
||||
expect {
|
||||
module_info_by_path_from_database!
|
||||
}.to_not change {
|
||||
typed_module_set[reference_name]
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
context 'without reference_name' do
|
||||
it 'should set reference_name value to Msf::SymbolicModule' do
|
||||
module_info_by_path_from_database!
|
||||
|
||||
# have to use fetch because [] will trigger de-symbolization and
|
||||
# instantiation.
|
||||
typed_module_set.fetch(reference_name).should == Msf::SymbolicModule
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'without framework migrated' do
|
||||
let(:framework_migrated?) do
|
||||
false
|
||||
end
|
||||
|
||||
it { should_not query_the_database.when_calling(:module_info_by_path_from_database!) }
|
||||
|
||||
it 'should reset #module_info_by_path' do
|
||||
# pre-fill module_info_by_path so change can be detected
|
||||
module_manager.send(:module_info_by_path=, double('In-memory Cache'))
|
||||
|
||||
module_info_by_path_from_database!
|
||||
|
||||
module_info_by_path.should be_empty
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,162 +1,162 @@
|
||||
shared_examples_for 'Msf::ModuleManager::Loading' do
|
||||
context '#file_changed?' do
|
||||
let(:module_basename) do
|
||||
[basename_prefix, '.rb']
|
||||
end
|
||||
context '#file_changed?' do
|
||||
let(:module_basename) do
|
||||
[basename_prefix, '.rb']
|
||||
end
|
||||
|
||||
it 'should return true if module info is not cached' do
|
||||
Tempfile.open(module_basename) do |tempfile|
|
||||
module_path = tempfile.path
|
||||
it 'should return true if module info is not cached' do
|
||||
Tempfile.open(module_basename) do |tempfile|
|
||||
module_path = tempfile.path
|
||||
|
||||
subject.send(:module_info_by_path)[module_path].should be_nil
|
||||
subject.file_changed?(module_path).should be_true
|
||||
end
|
||||
end
|
||||
subject.send(:module_info_by_path)[module_path].should be_nil
|
||||
subject.file_changed?(module_path).should be_true
|
||||
end
|
||||
end
|
||||
|
||||
it 'should return true if the cached type is Msf::MODULE_PAYLOAD' do
|
||||
Tempfile.open(module_basename) do |tempfile|
|
||||
module_path = tempfile.path
|
||||
modification_time = File.mtime(module_path)
|
||||
it 'should return true if the cached type is Msf::MODULE_PAYLOAD' do
|
||||
Tempfile.open(module_basename) do |tempfile|
|
||||
module_path = tempfile.path
|
||||
modification_time = File.mtime(module_path)
|
||||
|
||||
subject.send(:module_info_by_path)[module_path] = {
|
||||
# :modification_time must match so that it is the :type that is causing the `true` and not the
|
||||
# :modification_time causing the `true`.
|
||||
:modification_time => modification_time,
|
||||
:type => Msf::MODULE_PAYLOAD
|
||||
}
|
||||
subject.send(:module_info_by_path)[module_path] = {
|
||||
# :modification_time must match so that it is the :type that is causing the `true` and not the
|
||||
# :modification_time causing the `true`.
|
||||
:modification_time => modification_time,
|
||||
:type => Msf::MODULE_PAYLOAD
|
||||
}
|
||||
|
||||
subject.file_changed?(module_path).should be_true
|
||||
end
|
||||
end
|
||||
subject.file_changed?(module_path).should be_true
|
||||
end
|
||||
end
|
||||
|
||||
context 'with cache module info and not a payload module' do
|
||||
it 'should return true if the file does not exist on the file system' do
|
||||
tempfile = Tempfile.new(module_basename)
|
||||
module_path = tempfile.path
|
||||
modification_time = File.mtime(module_path).to_i
|
||||
context 'with cache module info and not a payload module' do
|
||||
it 'should return true if the file does not exist on the file system' do
|
||||
tempfile = Tempfile.new(module_basename)
|
||||
module_path = tempfile.path
|
||||
modification_time = File.mtime(module_path).to_i
|
||||
|
||||
subject.send(:module_info_by_path)[module_path] = {
|
||||
:modification_time => modification_time
|
||||
}
|
||||
subject.send(:module_info_by_path)[module_path] = {
|
||||
:modification_time => modification_time
|
||||
}
|
||||
|
||||
tempfile.unlink
|
||||
tempfile.unlink
|
||||
|
||||
File.exist?(module_path).should be_false
|
||||
subject.file_changed?(module_path).should be_true
|
||||
end
|
||||
File.exist?(module_path).should be_false
|
||||
subject.file_changed?(module_path).should be_true
|
||||
end
|
||||
|
||||
it 'should return true if modification time does not match the cached modification time' do
|
||||
Tempfile.open(module_basename) do |tempfile|
|
||||
module_path = tempfile.path
|
||||
modification_time = File.mtime(module_path).to_i
|
||||
cached_modification_time = (modification_time * rand).to_i
|
||||
it 'should return true if modification time does not match the cached modification time' do
|
||||
Tempfile.open(module_basename) do |tempfile|
|
||||
module_path = tempfile.path
|
||||
modification_time = File.mtime(module_path).to_i
|
||||
cached_modification_time = (modification_time * rand).to_i
|
||||
|
||||
subject.send(:module_info_by_path)[module_path] = {
|
||||
:modification_time => cached_modification_time
|
||||
}
|
||||
subject.send(:module_info_by_path)[module_path] = {
|
||||
:modification_time => cached_modification_time
|
||||
}
|
||||
|
||||
cached_modification_time.should_not == modification_time
|
||||
subject.file_changed?(module_path).should be_true
|
||||
end
|
||||
end
|
||||
cached_modification_time.should_not == modification_time
|
||||
subject.file_changed?(module_path).should be_true
|
||||
end
|
||||
end
|
||||
|
||||
it 'should return false if modification time does match the cached modification time' do
|
||||
Tempfile.open(module_basename) do |tempfile|
|
||||
module_path = tempfile.path
|
||||
modification_time = File.mtime(module_path).to_i
|
||||
cached_modification_time = modification_time
|
||||
it 'should return false if modification time does match the cached modification time' do
|
||||
Tempfile.open(module_basename) do |tempfile|
|
||||
module_path = tempfile.path
|
||||
modification_time = File.mtime(module_path).to_i
|
||||
cached_modification_time = modification_time
|
||||
|
||||
subject.send(:module_info_by_path)[module_path] = {
|
||||
:modification_time => cached_modification_time
|
||||
}
|
||||
subject.send(:module_info_by_path)[module_path] = {
|
||||
:modification_time => cached_modification_time
|
||||
}
|
||||
|
||||
cached_modification_time.should == modification_time
|
||||
subject.file_changed?(module_path).should be_false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
cached_modification_time.should == modification_time
|
||||
subject.file_changed?(module_path).should be_false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context '#on_module_load' do
|
||||
def on_module_load
|
||||
module_manager.on_module_load(klass, type, reference_name, options)
|
||||
end
|
||||
context '#on_module_load' do
|
||||
def on_module_load
|
||||
module_manager.on_module_load(klass, type, reference_name, options)
|
||||
end
|
||||
|
||||
let(:klass) do
|
||||
Class.new(Msf::Auxiliary)
|
||||
end
|
||||
let(:klass) do
|
||||
Class.new(Msf::Auxiliary)
|
||||
end
|
||||
|
||||
let(:module_set) do
|
||||
module_manager.module_set(type)
|
||||
end
|
||||
let(:module_set) do
|
||||
module_manager.module_set(type)
|
||||
end
|
||||
|
||||
let(:namespace_module) do
|
||||
double('Namespace Module', :parent_path => parent_path)
|
||||
end
|
||||
let(:namespace_module) do
|
||||
double('Namespace Module', :parent_path => parent_path)
|
||||
end
|
||||
|
||||
let(:options) do
|
||||
{
|
||||
'files' => [
|
||||
path
|
||||
],
|
||||
'paths' => [
|
||||
reference_name
|
||||
],
|
||||
'type' => type
|
||||
}
|
||||
end
|
||||
let(:options) do
|
||||
{
|
||||
'files' => [
|
||||
path
|
||||
],
|
||||
'paths' => [
|
||||
reference_name
|
||||
],
|
||||
'type' => type
|
||||
}
|
||||
end
|
||||
|
||||
let(:parent_path) do
|
||||
Metasploit::Framework.root.join('modules')
|
||||
end
|
||||
let(:parent_path) do
|
||||
Metasploit::Framework.root.join('modules')
|
||||
end
|
||||
|
||||
let(:path) do
|
||||
type_directory = Mdm::Module::Detail::DIRECTORY_BY_TYPE[type]
|
||||
let(:path) do
|
||||
type_directory = Mdm::Module::Detail::DIRECTORY_BY_TYPE[type]
|
||||
|
||||
File.join(parent_path, type_directory, "#{reference_name}.rb")
|
||||
end
|
||||
File.join(parent_path, type_directory, "#{reference_name}.rb")
|
||||
end
|
||||
|
||||
let(:reference_name) do
|
||||
'admin/2wire/xslt_password_reset'
|
||||
end
|
||||
let(:reference_name) do
|
||||
'admin/2wire/xslt_password_reset'
|
||||
end
|
||||
|
||||
let(:type) do
|
||||
klass.type
|
||||
end
|
||||
let(:type) do
|
||||
klass.type
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
klass.stub(:parent => namespace_module)
|
||||
end
|
||||
before(:each) do
|
||||
klass.stub(:parent => namespace_module)
|
||||
end
|
||||
|
||||
it "should add module to type's module_set" do
|
||||
module_set.should_receive(:add_module).with(
|
||||
klass,
|
||||
reference_name,
|
||||
options
|
||||
)
|
||||
it "should add module to type's module_set" do
|
||||
module_set.should_receive(:add_module).with(
|
||||
klass,
|
||||
reference_name,
|
||||
options
|
||||
)
|
||||
|
||||
on_module_load
|
||||
end
|
||||
on_module_load
|
||||
end
|
||||
|
||||
it 'should call cache_in_memory' do
|
||||
module_manager.should_receive(:cache_in_memory)
|
||||
it 'should call cache_in_memory' do
|
||||
module_manager.should_receive(:cache_in_memory)
|
||||
|
||||
on_module_load
|
||||
end
|
||||
on_module_load
|
||||
end
|
||||
|
||||
it 'should pass class to #auto_subscribe_module' do
|
||||
module_manager.should_receive(:auto_subscribe_module).with(klass)
|
||||
it 'should pass class to #auto_subscribe_module' do
|
||||
module_manager.should_receive(:auto_subscribe_module).with(klass)
|
||||
|
||||
on_module_load
|
||||
end
|
||||
on_module_load
|
||||
end
|
||||
|
||||
it 'should fire on_module_load event with class' do
|
||||
framework.events.should_receive(:on_module_load).with(
|
||||
reference_name,
|
||||
klass
|
||||
)
|
||||
it 'should fire on_module_load event with class' do
|
||||
framework.events.should_receive(:on_module_load).with(
|
||||
reference_name,
|
||||
klass
|
||||
)
|
||||
|
||||
on_module_load
|
||||
end
|
||||
end
|
||||
on_module_load
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,77 +1,77 @@
|
||||
shared_examples_for 'Msf::ModuleManager::ModulePaths' do
|
||||
def module_paths
|
||||
module_manager.send(:module_paths)
|
||||
end
|
||||
def module_paths
|
||||
module_manager.send(:module_paths)
|
||||
end
|
||||
|
||||
context '#add_module_path' do
|
||||
it 'should strip trailing File::SEPARATOR from the path' do
|
||||
Dir.mktmpdir do |path|
|
||||
path_with_trailing_separator = path + File::SEPARATOR
|
||||
module_manager.add_module_path(path_with_trailing_separator)
|
||||
context '#add_module_path' do
|
||||
it 'should strip trailing File::SEPARATOR from the path' do
|
||||
Dir.mktmpdir do |path|
|
||||
path_with_trailing_separator = path + File::SEPARATOR
|
||||
module_manager.add_module_path(path_with_trailing_separator)
|
||||
|
||||
module_paths.should_not include(path_with_trailing_separator)
|
||||
module_paths.should include(path)
|
||||
end
|
||||
end
|
||||
module_paths.should_not include(path_with_trailing_separator)
|
||||
module_paths.should include(path)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with Fastlib archive' do
|
||||
it 'should raise an ArgumentError unless the File exists' do
|
||||
file = Tempfile.new(archive_basename)
|
||||
# unlink will clear path, so copy it to a variable
|
||||
path = file.path
|
||||
file.unlink
|
||||
context 'with Fastlib archive' do
|
||||
it 'should raise an ArgumentError unless the File exists' do
|
||||
file = Tempfile.new(archive_basename)
|
||||
# unlink will clear path, so copy it to a variable
|
||||
path = file.path
|
||||
file.unlink
|
||||
|
||||
File.exist?(path).should be_false
|
||||
File.exist?(path).should be_false
|
||||
|
||||
expect {
|
||||
module_manager.add_module_path(path)
|
||||
}.to raise_error(ArgumentError, "The path supplied does not exist")
|
||||
end
|
||||
expect {
|
||||
module_manager.add_module_path(path)
|
||||
}.to raise_error(ArgumentError, "The path supplied does not exist")
|
||||
end
|
||||
|
||||
it 'should add the path to #module_paths if the File exists' do
|
||||
Tempfile.open(archive_basename) do |temporary_file|
|
||||
path = temporary_file.path
|
||||
it 'should add the path to #module_paths if the File exists' do
|
||||
Tempfile.open(archive_basename) do |temporary_file|
|
||||
path = temporary_file.path
|
||||
|
||||
File.exist?(path).should be_true
|
||||
File.exist?(path).should be_true
|
||||
|
||||
module_manager.add_module_path(path)
|
||||
module_manager.add_module_path(path)
|
||||
|
||||
module_paths.should include(path)
|
||||
end
|
||||
end
|
||||
end
|
||||
module_paths.should include(path)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with directory' do
|
||||
it 'should add path to #module_paths' do
|
||||
Dir.mktmpdir do |path|
|
||||
module_manager.add_module_path(path)
|
||||
context 'with directory' do
|
||||
it 'should add path to #module_paths' do
|
||||
Dir.mktmpdir do |path|
|
||||
module_manager.add_module_path(path)
|
||||
|
||||
module_paths.should include(path)
|
||||
end
|
||||
end
|
||||
module_paths.should include(path)
|
||||
end
|
||||
end
|
||||
|
||||
context 'containing Fastlib archives' do
|
||||
it 'should add each Fastlib archive to #module_paths' do
|
||||
Dir.mktmpdir do |directory|
|
||||
Tempfile.open(archive_basename, directory) do |file|
|
||||
module_manager.add_module_path(directory)
|
||||
context 'containing Fastlib archives' do
|
||||
it 'should add each Fastlib archive to #module_paths' do
|
||||
Dir.mktmpdir do |directory|
|
||||
Tempfile.open(archive_basename, directory) do |file|
|
||||
module_manager.add_module_path(directory)
|
||||
|
||||
module_paths.should include(directory)
|
||||
module_paths.should include(file.path)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
module_paths.should include(directory)
|
||||
module_paths.should include(file.path)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with other file' do
|
||||
it 'should raise ArgumentError' do
|
||||
Tempfile.open(basename_prefix) do |file|
|
||||
expect {
|
||||
subject.add_module_path(file.path)
|
||||
}.to raise_error(ArgumentError, 'The path supplied is not a valid directory.')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
context 'with other file' do
|
||||
it 'should raise ArgumentError' do
|
||||
Tempfile.open(basename_prefix) do |file|
|
||||
expect {
|
||||
subject.add_module_path(file.path)
|
||||
}.to raise_error(ArgumentError, 'The path supplied is not a valid directory.')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,27 +1,27 @@
|
||||
# -*- coding:binary -*-
|
||||
shared_examples_for 'Msf::Modules::Error subclass #initialize' do
|
||||
context 'instance methods' do
|
||||
context '#initialize' do
|
||||
include_context 'Msf::Modules::Error attributes'
|
||||
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
|
||||
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 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_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
|
||||
it 'should set module_reference_name' do
|
||||
subject.module_reference_name.should == module_reference_name
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
# -*- coding:binary -*-
|
||||
shared_examples_for 'Msf::Modules::Loader::Archive#read_module_content' do
|
||||
it 'should be able to read the module content' do
|
||||
archived_module_content = subject.send(:read_module_content, @parent_path, type, module_reference_name)
|
||||
unarchived_module_content = ''
|
||||
it 'should be able to read the module content' do
|
||||
archived_module_content = subject.send(:read_module_content, @parent_path, type, module_reference_name)
|
||||
unarchived_module_content = ''
|
||||
|
||||
File.open(unarchived_path) do |f|
|
||||
unarchived_module_content = f.read
|
||||
end
|
||||
File.open(unarchived_path) do |f|
|
||||
unarchived_module_content = f.read
|
||||
end
|
||||
|
||||
unarchived_module_content.should_not be_empty
|
||||
archived_module_content.should == unarchived_module_content
|
||||
end
|
||||
unarchived_module_content.should_not be_empty
|
||||
archived_module_content.should == unarchived_module_content
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,33 +1,33 @@
|
||||
# -*- coding:binary -*-
|
||||
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
|
||||
let(:error) do
|
||||
begin
|
||||
subject.version_compatible!(module_path, module_reference_name)
|
||||
rescue Msf::Modules::VersionCompatibilityError => error
|
||||
end
|
||||
|
||||
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 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 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 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 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
|
||||
it 'should include module reference name' do
|
||||
error.to_s.should include(module_reference_name)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,99 +1,99 @@
|
||||
shared_examples_for 'Msf::Simple::Framework::ModulePaths' do
|
||||
it { should be_a Msf::Simple::Framework::ModulePaths }
|
||||
it { should be_a Msf::Simple::Framework::ModulePaths }
|
||||
|
||||
context '#init_module_paths' do
|
||||
def init_module_paths
|
||||
framework.init_module_paths
|
||||
end
|
||||
context '#init_module_paths' do
|
||||
def init_module_paths
|
||||
framework.init_module_paths
|
||||
end
|
||||
|
||||
let(:module_directory) do
|
||||
nil
|
||||
end
|
||||
let(:module_directory) do
|
||||
nil
|
||||
end
|
||||
|
||||
let(:user_module_directory) do
|
||||
nil
|
||||
end
|
||||
let(:user_module_directory) do
|
||||
nil
|
||||
end
|
||||
|
||||
let(:options) do
|
||||
{}
|
||||
end
|
||||
let(:options) do
|
||||
{}
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
# create the framework first so that it's initialization's call
|
||||
# to init_module_paths doesn't get captured.
|
||||
framework
|
||||
before(:each) do
|
||||
# create the framework first so that it's initialization's call
|
||||
# to init_module_paths doesn't get captured.
|
||||
framework
|
||||
|
||||
Msf::Config.stub(:module_directory => module_directory)
|
||||
Msf::Config.stub(:user_module_directory => user_module_directory)
|
||||
end
|
||||
Msf::Config.stub(:module_directory => module_directory)
|
||||
Msf::Config.stub(:user_module_directory => user_module_directory)
|
||||
end
|
||||
|
||||
it 'should refresh module cache from database' do
|
||||
framework.modules.should_receive(:refresh_cache_from_database)
|
||||
it 'should refresh module cache from database' do
|
||||
framework.modules.should_receive(:refresh_cache_from_database)
|
||||
|
||||
init_module_paths
|
||||
end
|
||||
init_module_paths
|
||||
end
|
||||
|
||||
context 'Msf::Config' do
|
||||
context 'module_directory' do
|
||||
context 'without nil' do
|
||||
let(:module_directory) do
|
||||
'modules'
|
||||
end
|
||||
context 'Msf::Config' do
|
||||
context 'module_directory' do
|
||||
context 'without nil' do
|
||||
let(:module_directory) do
|
||||
'modules'
|
||||
end
|
||||
|
||||
it 'should add Msf::Config.module_directory to module paths' do
|
||||
framework.modules.should_receive(:add_module_path).with(
|
||||
module_directory,
|
||||
options
|
||||
)
|
||||
it 'should add Msf::Config.module_directory to module paths' do
|
||||
framework.modules.should_receive(:add_module_path).with(
|
||||
module_directory,
|
||||
options
|
||||
)
|
||||
|
||||
init_module_paths
|
||||
end
|
||||
end
|
||||
end
|
||||
init_module_paths
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'user_module_directory' do
|
||||
context 'without nil' do
|
||||
let(:user_module_directory) do
|
||||
'user/modules'
|
||||
end
|
||||
context 'user_module_directory' do
|
||||
context 'without nil' do
|
||||
let(:user_module_directory) do
|
||||
'user/modules'
|
||||
end
|
||||
|
||||
it 'should add Msf::Config.user_module_directory to module paths' do
|
||||
framework.modules.should_receive(:add_module_path).with(
|
||||
user_module_directory,
|
||||
options
|
||||
)
|
||||
it 'should add Msf::Config.user_module_directory to module paths' do
|
||||
framework.modules.should_receive(:add_module_path).with(
|
||||
user_module_directory,
|
||||
options
|
||||
)
|
||||
|
||||
init_module_paths
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
init_module_paths
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'datastore' do
|
||||
context 'MsfModulePaths' do
|
||||
let(:module_paths) do
|
||||
module_paths = []
|
||||
context 'datastore' do
|
||||
context 'MsfModulePaths' do
|
||||
let(:module_paths) do
|
||||
module_paths = []
|
||||
|
||||
1.upto(2) do |i|
|
||||
module_paths << "msf/#{i}/modules"
|
||||
end
|
||||
1.upto(2) do |i|
|
||||
module_paths << "msf/#{i}/modules"
|
||||
end
|
||||
|
||||
module_paths
|
||||
end
|
||||
module_paths
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
msf_module_paths = module_paths.join(';')
|
||||
framework.datastore['MsfModulePaths'] = msf_module_paths
|
||||
end
|
||||
before(:each) do
|
||||
msf_module_paths = module_paths.join(';')
|
||||
framework.datastore['MsfModulePaths'] = msf_module_paths
|
||||
end
|
||||
|
||||
it 'should add each module path' do
|
||||
module_paths.each do |module_path|
|
||||
framework.modules.should_receive(:add_module_path).with(module_path, options)
|
||||
end
|
||||
it 'should add each module path' do
|
||||
module_paths.each do |module_path|
|
||||
framework.modules.should_receive(:add_module_path).with(module_path, options)
|
||||
end
|
||||
|
||||
init_module_paths
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
init_module_paths
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -26,33 +26,33 @@ shared_examples_for "an option" do |valid_values, invalid_values, type|
|
||||
|
||||
context "with valid values" do
|
||||
valid_values.each do |vhash|
|
||||
valid_value = vhash[:value]
|
||||
normalized_value = vhash[:normalized]
|
||||
valid_value = vhash[:value]
|
||||
normalized_value = vhash[:normalized]
|
||||
|
||||
it "should be valid and normalize appropriately: #{valid_value}" do
|
||||
block = Proc.new {
|
||||
subject.normalize(valid_value).should == normalized_value
|
||||
subject.valid?(valid_value).should be_true
|
||||
}
|
||||
if vhash[:pending]
|
||||
pending(vhash[:pending], &block)
|
||||
else
|
||||
block.call
|
||||
end
|
||||
block = Proc.new {
|
||||
subject.normalize(valid_value).should == normalized_value
|
||||
subject.valid?(valid_value).should be_true
|
||||
}
|
||||
if vhash[:pending]
|
||||
pending(vhash[:pending], &block)
|
||||
else
|
||||
block.call
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "with invalid values" do
|
||||
invalid_values.each do |vhash|
|
||||
invalid_value = vhash[:value]
|
||||
invalid_value = vhash[:value]
|
||||
it "should not be valid: #{invalid_value}" do
|
||||
block = Proc.new { subject.valid?(invalid_value).should be_false }
|
||||
if vhash[:pending]
|
||||
pending(vhash[:pending], &block)
|
||||
else
|
||||
block.call
|
||||
end
|
||||
if vhash[:pending]
|
||||
pending(vhash[:pending], &block)
|
||||
else
|
||||
block.call
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
# -*- coding:binary -*-
|
||||
shared_examples_for 'typed_path' do |map|
|
||||
map ||= {}
|
||||
if map.length < 1
|
||||
raise ArgumentError,
|
||||
"type_path shared example requires a hash mapping the type constant name to the directory name: " \
|
||||
"it_should_behave_like 'type_path', 'Msf::Auxiliary' => 'auxiliary'"
|
||||
end
|
||||
map ||= {}
|
||||
if map.length < 1
|
||||
raise ArgumentError,
|
||||
"type_path shared example requires a hash mapping the type constant name to the directory name: " \
|
||||
"it_should_behave_like 'type_path', 'Msf::Auxiliary' => 'auxiliary'"
|
||||
end
|
||||
|
||||
if map.length > 1
|
||||
raise ArgumentError,
|
||||
"only one constant to directory mapping should be passed to each shared example, not #{map.length}"
|
||||
end
|
||||
if map.length > 1
|
||||
raise ArgumentError,
|
||||
"only one constant to directory mapping should be passed to each shared example, not #{map.length}"
|
||||
end
|
||||
|
||||
type_constant_name, directory = map.shift
|
||||
type_constant_name, directory = map.shift
|
||||
|
||||
context "with #{type_constant_name} type" do
|
||||
let(:type_constant) do
|
||||
type_constant_name.constantize
|
||||
end
|
||||
context "with #{type_constant_name} type" do
|
||||
let(:type_constant) do
|
||||
type_constant_name.constantize
|
||||
end
|
||||
|
||||
it "should start with #{directory} directory" do
|
||||
typed_path = described_class.typed_path(type_constant, module_reference_name)
|
||||
first_directory = typed_path.split(File::SEPARATOR).first
|
||||
it "should start with #{directory} directory" do
|
||||
typed_path = described_class.typed_path(type_constant, module_reference_name)
|
||||
first_directory = typed_path.split(File::SEPARATOR).first
|
||||
|
||||
first_directory.should == directory
|
||||
end
|
||||
end
|
||||
first_directory.should == directory
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,37 +1,37 @@
|
||||
# -*- coding: binary -*-
|
||||
shared_examples_for 'an xor encoder' do |keysize|
|
||||
|
||||
it "should encode one block" do
|
||||
# Yup it returns one of its arguments in an array... Because spoon.
|
||||
encoded, key = described_class.encode("A"*keysize, "A"*keysize)
|
||||
encoded.should eql("\x00"*keysize)
|
||||
it "should encode one block" do
|
||||
# Yup it returns one of its arguments in an array... Because spoon.
|
||||
encoded, key = described_class.encode("A"*keysize, "A"*keysize)
|
||||
encoded.should eql("\x00"*keysize)
|
||||
|
||||
encoded, key = described_class.encode("\x0f"*keysize, "\xf0"*keysize)
|
||||
encoded.should eql("\xff"*keysize)
|
||||
encoded, key = described_class.encode("\x0f"*keysize, "\xf0"*keysize)
|
||||
encoded.should eql("\xff"*keysize)
|
||||
|
||||
encoded, key = described_class.encode("\xf7"*keysize, "\x7f"*keysize)
|
||||
encoded.should eql("\x88"*keysize)
|
||||
end
|
||||
encoded, key = described_class.encode("\xf7"*keysize, "\x7f"*keysize)
|
||||
encoded.should eql("\x88"*keysize)
|
||||
end
|
||||
|
||||
it "should encode multiple blocks" do
|
||||
2.upto 50 do |count|
|
||||
encoded, key = described_class.encode("\xf7"*keysize*count, "\x7f"*keysize)
|
||||
encoded.should eql("\x88"*keysize*count)
|
||||
end
|
||||
end
|
||||
it "should encode multiple blocks" do
|
||||
2.upto 50 do |count|
|
||||
encoded, key = described_class.encode("\xf7"*keysize*count, "\x7f"*keysize)
|
||||
encoded.should eql("\x88"*keysize*count)
|
||||
end
|
||||
end
|
||||
|
||||
if keysize > 1
|
||||
it "should deal with input lengths that aren't a multiple of keysize" do
|
||||
lambda {
|
||||
encoded, key = described_class.encode("A"*(keysize+1), "A"*keysize)
|
||||
encoded.should eql("\x00"*(keysize+1))
|
||||
}.should_not raise_error
|
||||
if keysize > 1
|
||||
it "should deal with input lengths that aren't a multiple of keysize" do
|
||||
lambda {
|
||||
encoded, key = described_class.encode("A"*(keysize+1), "A"*keysize)
|
||||
encoded.should eql("\x00"*(keysize+1))
|
||||
}.should_not raise_error
|
||||
|
||||
lambda {
|
||||
encoded, key = described_class.encode("A"*(keysize-1), "A"*keysize)
|
||||
encoded.should eql("\x00"*(keysize-1))
|
||||
}.should_not raise_error
|
||||
end
|
||||
end
|
||||
lambda {
|
||||
encoded, key = described_class.encode("A"*(keysize-1), "A"*keysize)
|
||||
encoded.should eql("\x00"*(keysize-1))
|
||||
}.should_not raise_error
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user