984 lines
33 KiB
Ruby
984 lines
33 KiB
Ruby
RSpec.shared_examples_for 'Msf::DBManager::Session' do
|
|
it { is_expected.to respond_to :get_session }
|
|
|
|
if ENV['REMOTE_DB']
|
|
before {skip("Awaiting sessions port")}
|
|
end
|
|
|
|
context '#report_session' do
|
|
let(:options) do
|
|
{}
|
|
end
|
|
|
|
subject(:report_session) do
|
|
db_manager.report_session(options)
|
|
end
|
|
|
|
context 'with active' do
|
|
let(:active) do
|
|
true
|
|
end
|
|
|
|
context 'with :session' do
|
|
before(:example) do
|
|
options[:session] = session
|
|
end
|
|
|
|
context 'with Msf::Session' do
|
|
include_context 'Metasploit::Framework::Spec::Constants cleaner'
|
|
|
|
let(:exploit_datastore) do
|
|
Msf::ModuleDataStore.new(module_instance).tap do |datastore|
|
|
datastore['ParentModule'] = parent_module_fullname
|
|
|
|
remote_port = rand(2 ** 16 - 1)
|
|
datastore['RPORT'] = remote_port
|
|
end
|
|
end
|
|
|
|
let(:host) do
|
|
FactoryBot.create(:mdm_host, :workspace => session_workspace)
|
|
end
|
|
|
|
let(:module_instance) do
|
|
name = 'multi/handler'
|
|
|
|
d = double(
|
|
'Msf::Exploit',
|
|
user_data: user_data,
|
|
fullname: "exploit/#{name}",
|
|
framework: framework,
|
|
name: name
|
|
)
|
|
d
|
|
end
|
|
|
|
let(:options_workspace) do
|
|
FactoryBot.create(:mdm_workspace)
|
|
end
|
|
|
|
let(:parent_module_fullname) do
|
|
"exploit/#{parent_module_name}"
|
|
end
|
|
|
|
let(:parent_module_name) do
|
|
'windows/smb/ms08_067_netapi'
|
|
end
|
|
|
|
let(:parent_path) do
|
|
Metasploit::Framework.root.join('modules').to_path
|
|
end
|
|
|
|
let(:session) do
|
|
session_class.new.tap do |session|
|
|
session.exploit = module_instance
|
|
session.exploit_datastore = exploit_datastore
|
|
session.info = 'Info'
|
|
session.platform = 'Platform'
|
|
session.session_host = host.address
|
|
session.sid = rand(100)
|
|
session.type = 'Session Type'
|
|
session.via_exploit = 'exploit/multi/handler'
|
|
session.via_payload = 'payload/single/windows/metsvc_bind_tcp'
|
|
session.workspace = session_workspace.name
|
|
end
|
|
end
|
|
|
|
let(:session_class) do
|
|
Class.new do
|
|
include Msf::Session
|
|
|
|
attr_accessor :arch
|
|
attr_accessor :exploit
|
|
attr_accessor :datastore
|
|
attr_accessor :platform
|
|
attr_accessor :type
|
|
attr_accessor :via_exploit
|
|
attr_accessor :via_payload
|
|
end
|
|
end
|
|
|
|
let(:session_workspace) do
|
|
FactoryBot.create(:mdm_workspace)
|
|
end
|
|
|
|
before(:example) do
|
|
reference_name = 'multi/handler'
|
|
path = File.join(parent_path, 'exploits', reference_name)
|
|
|
|
# fake cache data for exploit/multi/handler so it can be loaded
|
|
framework.modules.send(
|
|
:module_info_by_path=,
|
|
{
|
|
path =>
|
|
{
|
|
:parent_path => parent_path,
|
|
:reference_name => reference_name,
|
|
:type => 'exploit',
|
|
}
|
|
}
|
|
)
|
|
|
|
FactoryBot.create(
|
|
:mdm_module_detail,
|
|
:fullname => parent_module_fullname,
|
|
:name => parent_module_name
|
|
)
|
|
end
|
|
|
|
context 'with a run_id in user_data' do
|
|
before(:example) do
|
|
allow(db_manager).to receive(:create_match_for_vuln).and_return(nil)
|
|
end
|
|
|
|
let(:match_set) do
|
|
FactoryBot.create(:automatic_exploitation_match_set, user: session_workspace.owner,workspace:session_workspace)
|
|
end
|
|
|
|
let(:run) do
|
|
FactoryBot.create(:automatic_exploitation_run, workspace: session_workspace, match_set_id: match_set.id)
|
|
end
|
|
|
|
let(:user_data) do
|
|
{
|
|
run_id: run.id
|
|
}
|
|
end
|
|
|
|
context 'with :workspace' do
|
|
before(:example) do
|
|
options[:workspace] = options_workspace
|
|
end
|
|
|
|
it 'should not find workspace from session' do
|
|
expect(db_manager).not_to receive(:find_workspace)
|
|
|
|
expect { report_session }.to change(Mdm::Vuln, :count).by(1)
|
|
end
|
|
end
|
|
|
|
context 'without :workspace' do
|
|
it 'should find workspace from session' do
|
|
expect(db_manager).to receive(:find_workspace).with(session.workspace).and_call_original
|
|
|
|
report_session
|
|
end
|
|
|
|
it 'should pass session.workspace to #find_or_create_host' do
|
|
expect(db_manager).to receive(:find_or_create_host).with(
|
|
hash_including(
|
|
:workspace => session_workspace
|
|
)
|
|
).and_return(host)
|
|
|
|
expect { report_session }.to change(Mdm::Vuln, :count).by(1)
|
|
end
|
|
end
|
|
|
|
context 'with workspace from either :workspace or session' do
|
|
|
|
context 'with session responds to arch' do
|
|
let(:arch) do
|
|
FactoryBot.generate :mdm_host_arch
|
|
end
|
|
|
|
before(:example) do
|
|
allow(session).to receive(:arch).and_return(arch)
|
|
end
|
|
|
|
it 'should pass :arch to #find_or_create_host' do
|
|
expect(db_manager).to receive(:find_or_create_host).with(
|
|
hash_including(
|
|
:arch => arch
|
|
)
|
|
).and_call_original
|
|
|
|
expect { report_session }.to change(Mdm::Vuln, :count).by(1)
|
|
end
|
|
end
|
|
|
|
context 'without session responds to arch' do
|
|
it 'should not pass :arch to #find_or_create_host' do
|
|
expect(db_manager).to receive(:find_or_create_host).with(
|
|
hash_excluding(
|
|
:arch
|
|
)
|
|
).and_call_original
|
|
|
|
expect { report_session }.to change(Mdm::Vuln, :count).by(1)
|
|
end
|
|
end
|
|
|
|
it 'should create an Mdm::Session' do
|
|
expect {
|
|
report_session
|
|
}.to change(Mdm::Session, :count).by(1)
|
|
end
|
|
|
|
it { is_expected.to be_an Mdm::Session }
|
|
|
|
it 'should set session.db_record to created Mdm::Session' do
|
|
mdm_session = report_session
|
|
|
|
expect(session.db_record).to eq mdm_session
|
|
end
|
|
|
|
context 'with session.via_exploit' do
|
|
|
|
it 'should create Mdm::Vuln' do
|
|
expect {
|
|
report_session
|
|
}.to change(Mdm::Vuln, :count).by(1)
|
|
end
|
|
|
|
context 'created Mdm::Vuln' do
|
|
let(:mdm_session) do
|
|
Mdm::Session.last
|
|
end
|
|
|
|
let(:rport) do
|
|
nil
|
|
end
|
|
|
|
before(:example) do
|
|
Timecop.freeze
|
|
|
|
session.exploit_datastore['RPORT'] = rport
|
|
|
|
report_session
|
|
end
|
|
|
|
after(:example) do
|
|
Timecop.return
|
|
end
|
|
|
|
subject(:vuln) do
|
|
Mdm::Vuln.last
|
|
end
|
|
|
|
it { expect(subject.host).to eq(Mdm::Host.last) }
|
|
it { expect(subject.refs).to eq([]) }
|
|
it { expect(subject.exploited_at).to be_within(1.second).of(Time.now.utc) }
|
|
|
|
context "with session.via_exploit 'exploit/multi/handler'" do
|
|
context "with session.exploit_datastore['ParentModule']" do
|
|
it { expect(subject.info).to eq("Exploited by #{parent_module_fullname} to create Session #{mdm_session.id}") }
|
|
it { expect(subject.name).to eq(parent_module_name) }
|
|
end
|
|
end
|
|
|
|
context "without session.via_exploit 'exploit/multi/handler'" do
|
|
let(:reference_name) do
|
|
'windows/smb/ms08_067_netapi'
|
|
end
|
|
|
|
before(:example) do
|
|
path = File.join(
|
|
parent_path,
|
|
'exploits',
|
|
"#{reference_name}.rb"
|
|
)
|
|
type = 'exploit'
|
|
|
|
# fake cache data for ParentModule so it can be loaded
|
|
framework.modules.send(
|
|
:module_info_by_path=,
|
|
{
|
|
path =>
|
|
{
|
|
:parent_path => parent_path,
|
|
:reference_name => reference_name,
|
|
:type => type,
|
|
}
|
|
}
|
|
)
|
|
|
|
session.via_exploit = "#{type}/#{reference_name}"
|
|
end
|
|
|
|
it { expect(subject.info).to eq("Exploited by #{session.via_exploit} to create Session #{mdm_session.id}") }
|
|
it { expect(subject.name).to eq(reference_name) }
|
|
end
|
|
|
|
context 'with RPORT' do
|
|
let(:rport) do
|
|
# use service.port instead of having service use rport so
|
|
# that service is forced to exist before call to
|
|
# report_service, which happens right after using rport in
|
|
# outer context's before(:each)
|
|
service.port
|
|
end
|
|
|
|
let(:service) do
|
|
FactoryBot.create(
|
|
:mdm_service,
|
|
:host => host
|
|
)
|
|
end
|
|
|
|
it { expect(subject.service).to eq(service) }
|
|
end
|
|
|
|
context 'without RPORT' do
|
|
it { expect(subject.service).to be_nil }
|
|
end
|
|
end
|
|
|
|
context 'created Mdm::ExploitAttempt' do
|
|
let(:rport) do
|
|
nil
|
|
end
|
|
|
|
before(:example) do
|
|
Timecop.freeze
|
|
|
|
session.exploit_datastore['RPORT'] = rport
|
|
|
|
report_session
|
|
end
|
|
|
|
after(:example) do
|
|
Timecop.return
|
|
end
|
|
|
|
subject(:exploit_attempt) do
|
|
Mdm::ExploitAttempt.last
|
|
end
|
|
|
|
it { expect(subject.attempted_at).to be_within(1.second).of(Time.now.utc) }
|
|
# @todo https://www.pivotaltracker.com/story/show/48362615
|
|
it { expect(subject.session_id).to eq(Mdm::Session.last.id) }
|
|
it { expect(subject.exploited).to be_truthy }
|
|
# @todo https://www.pivotaltracker.com/story/show/48362615
|
|
it { expect(subject.vuln_id).to eq(Mdm::Vuln.last.id) }
|
|
|
|
context "with session.via_exploit 'exploit/multi/handler'" do
|
|
context "with session.datastore['ParentModule']" do
|
|
it { expect(subject.module).to eq(parent_module_fullname) }
|
|
end
|
|
end
|
|
|
|
context "without session.via_exploit 'exploit/multi/handler'" do
|
|
before(:example) do
|
|
session.via_exploit = parent_module_fullname
|
|
end
|
|
|
|
it { expect(subject.module).to eq(session.via_exploit) }
|
|
end
|
|
end
|
|
end
|
|
|
|
context 'returned Mdm::Session' do
|
|
before(:example) do
|
|
Timecop.freeze
|
|
end
|
|
|
|
after(:example) do
|
|
Timecop.return
|
|
end
|
|
|
|
subject(:mdm_session) do
|
|
report_session
|
|
end
|
|
|
|
#
|
|
# Ensure session has attributes present so its on mdm_session are
|
|
# not just comparing nils.
|
|
#
|
|
|
|
it 'should have session.info present' do
|
|
expect(session.info).to be_present
|
|
end
|
|
|
|
it 'should have session.sid present' do
|
|
expect(session.sid).to be_present
|
|
end
|
|
|
|
it 'should have session.platform present' do
|
|
expect(session.platform).to be_present
|
|
end
|
|
|
|
it 'should have session.type present' do
|
|
expect(session.type).to be_present
|
|
end
|
|
|
|
it 'should have session.via_exploit present' do
|
|
expect(session.via_exploit).to be_present
|
|
end
|
|
|
|
it 'should have session.via_payload present' do
|
|
expect(session.via_exploit).to be_present
|
|
end
|
|
|
|
it { expect(subject.datastore).to eq(session.exploit_datastore.to_h) }
|
|
it { expect(subject.desc).to eq(session.info) }
|
|
it { expect(subject.host_id).to eq(Mdm::Host.last.id) }
|
|
it { expect(subject.last_seen).to be_within(1.second).of(Time.now.utc) }
|
|
it { expect(subject.local_id).to eq(session.sid) }
|
|
it { expect(subject.opened_at).to be_within(1.second).of(Time.now.utc) }
|
|
it { expect(subject.platform).to eq(session.session_type) }
|
|
it { expect(subject.routes).to eq([]) }
|
|
it { expect(subject.stype).to eq(session.type) }
|
|
it { expect(subject.via_payload).to eq(session.via_payload) }
|
|
|
|
context "with session.via_exploit 'exploit/multi/handler'" do
|
|
it "should have session.via_exploit of 'exploit/multi/handler'" do
|
|
expect(session.via_exploit).to eq 'exploit/multi/handler'
|
|
end
|
|
|
|
context "with session.exploit_datastore['ParentModule']" do
|
|
it "should have session.exploit_datastore['ParentModule']" do
|
|
expect(session.exploit_datastore['ParentModule']).not_to be_nil
|
|
end
|
|
|
|
it { expect(subject.via_exploit).to eq(parent_module_fullname) }
|
|
end
|
|
end
|
|
|
|
context "without session.via_exploit 'exploit/multi/handler'" do
|
|
before(:example) do
|
|
reference_name = 'windows/smb/ms08_067_netapi'
|
|
path = File.join(
|
|
parent_path,
|
|
'exploits',
|
|
"#{reference_name}.rb"
|
|
)
|
|
type = 'exploit'
|
|
|
|
# fake cache data for ParentModule so it can be loaded
|
|
framework.modules.send(
|
|
:module_info_by_path=,
|
|
{
|
|
path =>
|
|
{
|
|
:parent_path => parent_path,
|
|
:reference_name => reference_name,
|
|
:type => type,
|
|
}
|
|
}
|
|
)
|
|
|
|
session.via_exploit = "#{type}/#{reference_name}"
|
|
end
|
|
|
|
it "should not have session.via_exploit of 'exploit/multi/handler'" do
|
|
expect(session.via_exploit).not_to eq 'exploit/multi/handler'
|
|
end
|
|
|
|
it { expect(subject.via_exploit).to eq(session.via_exploit) }
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
context 'without user_data' do
|
|
let(:user_data) { nil }
|
|
|
|
context 'with :workspace' do
|
|
before(:example) do
|
|
options[:workspace] = options_workspace
|
|
end
|
|
|
|
it 'should not find workspace from session' do
|
|
expect(db_manager).not_to receive(:find_workspace)
|
|
|
|
expect { report_session }.to change(Mdm::Vuln, :count).by(1)
|
|
end
|
|
end
|
|
|
|
context 'without :workspace' do
|
|
it 'should find workspace from session' do
|
|
expect(db_manager).to receive(:find_workspace).with(session.workspace).and_call_original
|
|
|
|
report_session
|
|
end
|
|
|
|
it 'should pass session.workspace to #find_or_create_host' do
|
|
expect(db_manager).to receive(:find_or_create_host).with(
|
|
hash_including(
|
|
:workspace => session_workspace
|
|
)
|
|
).and_return(host)
|
|
|
|
expect { report_session }.to change(Mdm::Vuln, :count).by(1)
|
|
end
|
|
end
|
|
|
|
context 'with workspace from either :workspace or session' do
|
|
|
|
context 'with session responds to arch' do
|
|
let(:arch) do
|
|
FactoryBot.generate :mdm_host_arch
|
|
end
|
|
|
|
before(:example) do
|
|
allow(session).to receive(:arch).and_return(arch)
|
|
end
|
|
|
|
it 'should pass :arch to #find_or_create_host' do
|
|
expect(db_manager).to receive(:find_or_create_host).with(
|
|
hash_including(
|
|
:arch => arch
|
|
)
|
|
).and_call_original
|
|
|
|
expect { report_session }.to change(Mdm::Vuln, :count).by(1)
|
|
end
|
|
end
|
|
|
|
context 'without session responds to arch' do
|
|
it 'should not pass :arch to #find_or_create_host' do
|
|
expect(db_manager).to receive(:find_or_create_host).with(
|
|
hash_excluding(
|
|
:arch
|
|
)
|
|
).and_call_original
|
|
|
|
expect { report_session }.to change(Mdm::Vuln, :count).by(1)
|
|
end
|
|
end
|
|
|
|
it 'should create an Mdm::Session' do
|
|
expect {
|
|
report_session
|
|
}.to change(Mdm::Session, :count).by(1)
|
|
end
|
|
|
|
it { is_expected.to be_an Mdm::Session }
|
|
|
|
it 'should set session.db_record to created Mdm::Session' do
|
|
mdm_session = report_session
|
|
|
|
expect(session.db_record).to eq mdm_session
|
|
end
|
|
|
|
context 'with session.via_exploit' do
|
|
|
|
it 'should create Mdm::Vuln' do
|
|
expect {
|
|
report_session
|
|
}.to change(Mdm::Vuln, :count).by(1)
|
|
end
|
|
|
|
context 'created Mdm::Vuln' do
|
|
let(:mdm_session) do
|
|
Mdm::Session.last
|
|
end
|
|
|
|
let(:rport) do
|
|
nil
|
|
end
|
|
|
|
before(:example) do
|
|
Timecop.freeze
|
|
|
|
session.exploit_datastore['RPORT'] = rport
|
|
|
|
report_session
|
|
end
|
|
|
|
after(:example) do
|
|
Timecop.return
|
|
end
|
|
|
|
subject(:vuln) do
|
|
Mdm::Vuln.last
|
|
end
|
|
|
|
it { expect(subject.host).to eq(Mdm::Host.last) }
|
|
it { expect(subject.refs).to eq([]) }
|
|
it { expect(subject.exploited_at).to be_within(1.second).of(Time.now.utc) }
|
|
|
|
context "with session.via_exploit 'exploit/multi/handler'" do
|
|
context "with session.exploit_datastore['ParentModule']" do
|
|
it { expect(subject.info).to eq("Exploited by #{parent_module_fullname} to create Session #{mdm_session.id}") }
|
|
it { expect(subject.name).to eq(parent_module_name) }
|
|
end
|
|
end
|
|
|
|
context "without session.via_exploit 'exploit/multi/handler'" do
|
|
let(:reference_name) do
|
|
'windows/smb/ms08_067_netapi'
|
|
end
|
|
|
|
before(:example) do
|
|
path = File.join(
|
|
parent_path,
|
|
'exploits',
|
|
"#{reference_name}.rb"
|
|
)
|
|
type = 'exploit'
|
|
|
|
# fake cache data for ParentModule so it can be loaded
|
|
framework.modules.send(
|
|
:module_info_by_path=,
|
|
{
|
|
path =>
|
|
{
|
|
:parent_path => parent_path,
|
|
:reference_name => reference_name,
|
|
:type => type,
|
|
}
|
|
}
|
|
)
|
|
|
|
session.via_exploit = "#{type}/#{reference_name}"
|
|
end
|
|
|
|
it { expect(subject.info).to eq("Exploited by #{session.via_exploit} to create Session #{mdm_session.id}") }
|
|
it { expect(subject.name).to eq(reference_name) }
|
|
end
|
|
|
|
context 'with RPORT' do
|
|
let(:rport) do
|
|
# use service.port instead of having service use rport so
|
|
# that service is forced to exist before call to
|
|
# report_service, which happens right after using rport in
|
|
# outer context's before(:each)
|
|
service.port
|
|
end
|
|
|
|
let(:service) do
|
|
FactoryBot.create(
|
|
:mdm_service,
|
|
:host => host
|
|
)
|
|
end
|
|
|
|
it { expect(subject.service).to eq(service) }
|
|
end
|
|
|
|
context 'without RPORT' do
|
|
it { expect(subject.service).to be_nil }
|
|
end
|
|
end
|
|
|
|
context 'created Mdm::ExploitAttempt' do
|
|
let(:rport) do
|
|
nil
|
|
end
|
|
|
|
before(:example) do
|
|
Timecop.freeze
|
|
|
|
session.exploit_datastore['RPORT'] = rport
|
|
|
|
report_session
|
|
end
|
|
|
|
after(:example) do
|
|
Timecop.return
|
|
end
|
|
|
|
subject(:exploit_attempt) do
|
|
Mdm::ExploitAttempt.last
|
|
end
|
|
|
|
it { expect(subject.attempted_at).to be_within(1.second).of(Time.now.utc) }
|
|
# @todo https://www.pivotaltracker.com/story/show/48362615
|
|
it { expect(subject.session_id).to eq(Mdm::Session.last.id) }
|
|
it { expect(subject.exploited).to be_truthy }
|
|
# @todo https://www.pivotaltracker.com/story/show/48362615
|
|
it { expect(subject.vuln_id).to eq(Mdm::Vuln.last.id) }
|
|
|
|
context "with session.via_exploit 'exploit/multi/handler'" do
|
|
context "with session.datastore['ParentModule']" do
|
|
it { expect(subject.module).to eq(parent_module_fullname) }
|
|
end
|
|
end
|
|
|
|
context "without session.via_exploit 'exploit/multi/handler'" do
|
|
before(:example) do
|
|
session.via_exploit = parent_module_fullname
|
|
end
|
|
|
|
it { expect(subject.module).to eq(session.via_exploit) }
|
|
end
|
|
end
|
|
end
|
|
|
|
context 'returned Mdm::Session' do
|
|
before(:example) do
|
|
Timecop.freeze
|
|
end
|
|
|
|
after(:example) do
|
|
Timecop.return
|
|
end
|
|
|
|
subject(:mdm_session) do
|
|
report_session
|
|
end
|
|
|
|
#
|
|
# Ensure session has attributes present so its on mdm_session are
|
|
# not just comparing nils.
|
|
#
|
|
|
|
it 'should have session.info present' do
|
|
expect(session.info).to be_present
|
|
end
|
|
|
|
it 'should have session.sid present' do
|
|
expect(session.sid).to be_present
|
|
end
|
|
|
|
it 'should have session.platform present' do
|
|
expect(session.platform).to be_present
|
|
end
|
|
|
|
it 'should have session.type present' do
|
|
expect(session.type).to be_present
|
|
end
|
|
|
|
it 'should have session.via_exploit present' do
|
|
expect(session.via_exploit).to be_present
|
|
end
|
|
|
|
it 'should have session.via_payload present' do
|
|
expect(session.via_exploit).to be_present
|
|
end
|
|
|
|
it { expect(subject.datastore).to eq(session.exploit_datastore.to_h) }
|
|
it { expect(subject.desc).to eq(session.info) }
|
|
it { expect(subject.host_id).to eq(Mdm::Host.last.id) }
|
|
it { expect(subject.last_seen).to be_within(1.second).of(Time.now.utc) }
|
|
it { expect(subject.local_id).to eq(session.sid) }
|
|
it { expect(subject.opened_at).to be_within(1.second).of(Time.now.utc) }
|
|
it { expect(subject.platform).to eq(session.session_type) }
|
|
it { expect(subject.routes).to eq([]) }
|
|
it { expect(subject.stype).to eq(session.type) }
|
|
it { expect(subject.via_payload).to eq(session.via_payload) }
|
|
|
|
context "with session.via_exploit 'exploit/multi/handler'" do
|
|
it "should have session.via_exploit of 'exploit/multi/handler'" do
|
|
expect(session.via_exploit).to eq 'exploit/multi/handler'
|
|
end
|
|
|
|
context "with session.exploit_datastore['ParentModule']" do
|
|
it "should have session.exploit_datastore['ParentModule']" do
|
|
expect(session.exploit_datastore['ParentModule']).not_to be_nil
|
|
end
|
|
|
|
it { expect(subject.via_exploit).to eq(parent_module_fullname) }
|
|
end
|
|
end
|
|
|
|
context "without session.via_exploit 'exploit/multi/handler'" do
|
|
before(:example) do
|
|
reference_name = 'windows/smb/ms08_067_netapi'
|
|
path = File.join(
|
|
parent_path,
|
|
'exploits',
|
|
"#{reference_name}.rb"
|
|
)
|
|
type = 'exploit'
|
|
|
|
# fake cache data for ParentModule so it can be loaded
|
|
framework.modules.send(
|
|
:module_info_by_path=,
|
|
{
|
|
path =>
|
|
{
|
|
:parent_path => parent_path,
|
|
:reference_name => reference_name,
|
|
:type => type,
|
|
}
|
|
}
|
|
)
|
|
|
|
session.via_exploit = "#{type}/#{reference_name}"
|
|
end
|
|
|
|
it "should not have session.via_exploit of 'exploit/multi/handler'" do
|
|
expect(session.via_exploit).not_to eq 'exploit/multi/handler'
|
|
end
|
|
|
|
it { expect(subject.via_exploit).to eq(session.via_exploit) }
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
context 'without Msf::Session' do
|
|
let(:session) do
|
|
double('Not a Msf::Session')
|
|
end
|
|
|
|
it 'should raise ArgumentError' do
|
|
expect {
|
|
report_session
|
|
}.to raise_error(ArgumentError, "Invalid :session, expected Msf::Session")
|
|
end
|
|
end
|
|
end
|
|
|
|
context 'without :session' do
|
|
context 'with :host' do
|
|
before(:example) do
|
|
options[:host] = host
|
|
end
|
|
|
|
context 'with Mdm::Host' do
|
|
let(:host) do
|
|
FactoryBot.create(:mdm_host)
|
|
end
|
|
|
|
context 'created Mdm::Session' do
|
|
let(:closed_at) do
|
|
nil
|
|
end
|
|
|
|
let(:close_reason) do
|
|
'Closed because...'
|
|
end
|
|
|
|
let(:description) do
|
|
'Session Description'
|
|
end
|
|
|
|
let(:exploit_full_name) do
|
|
'exploit/windows/smb/ms08_067_netapi'
|
|
end
|
|
|
|
let(:last_seen) do
|
|
nil
|
|
end
|
|
|
|
let(:opened_at) do
|
|
Time.now.utc - 5.minutes
|
|
end
|
|
|
|
let(:payload_full_name) do
|
|
'payload/singles/windows/metsvc_reverse_tcp'
|
|
end
|
|
|
|
let(:platform) do
|
|
'Host Platform'
|
|
end
|
|
|
|
let(:routes) do
|
|
nil
|
|
end
|
|
|
|
let(:session_type) do
|
|
'Session Type'
|
|
end
|
|
|
|
before(:example) do
|
|
options[:closed_at] = closed_at
|
|
options[:close_reason] = close_reason
|
|
options[:desc] = description
|
|
options[:last_seen] = last_seen
|
|
options[:opened_at] = opened_at
|
|
options[:platform] = platform
|
|
options[:routes] = routes
|
|
options[:stype] = session_type
|
|
options[:via_payload] = payload_full_name
|
|
options[:via_exploit] = exploit_full_name
|
|
end
|
|
|
|
subject(:mdm_session) do
|
|
report_session
|
|
end
|
|
|
|
it { expect(subject.close_reason).to eq(close_reason) }
|
|
it { expect(subject.desc).to eq(description) }
|
|
it { expect(subject.host).to eq(host) }
|
|
it { expect(subject.platform).to eq(platform) }
|
|
it { expect(subject.stype).to eq(session_type) }
|
|
it { expect(subject.via_exploit).to eq(exploit_full_name) }
|
|
it { expect(subject.via_payload).to eq(payload_full_name) }
|
|
|
|
context 'with :last_seen' do
|
|
let(:last_seen) do
|
|
opened_at
|
|
end
|
|
|
|
it { expect(subject.last_seen).to eq(last_seen) }
|
|
end
|
|
|
|
context 'with :closed_at' do
|
|
let(:closed_at) do
|
|
opened_at + 1.minute
|
|
end
|
|
|
|
it { expect(subject.closed_at).to eq(closed_at) }
|
|
end
|
|
|
|
context 'without :closed_at' do
|
|
it { expect(subject.closed_at).to be_nil }
|
|
end
|
|
|
|
context 'without :last_seen' do
|
|
context 'with :closed_at' do
|
|
let(:closed_at) do
|
|
opened_at + 1.minute
|
|
end
|
|
|
|
it { expect(subject.last_seen).to eq(closed_at) }
|
|
end
|
|
|
|
context 'without :closed_at' do
|
|
it { expect(subject.last_seen).to be_nil }
|
|
end
|
|
end
|
|
|
|
context 'with :routes' do
|
|
let(:routes) do
|
|
FactoryBot.build_list(
|
|
:mdm_route,
|
|
1,
|
|
:session => nil
|
|
)
|
|
end
|
|
|
|
it { expect(subject.routes.to_a).to eq(routes) }
|
|
end
|
|
|
|
context 'without :routes' do
|
|
it { expect(subject.routes).to eq([]) }
|
|
end
|
|
end
|
|
end
|
|
|
|
context 'without Mdm::Host' do
|
|
let(:host) do
|
|
'192.168.0.1'
|
|
end
|
|
|
|
it 'should raise ArgumentError' do
|
|
expect {
|
|
report_session
|
|
}.to raise_error(ArgumentError, "Invalid :host, expected Host object")
|
|
end
|
|
end
|
|
end
|
|
|
|
context 'without :host' do
|
|
it 'should raise ArgumentError' do
|
|
expect {
|
|
report_session
|
|
}.to raise_error(ArgumentError)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
context 'without active' do
|
|
let(:active) do
|
|
false
|
|
end
|
|
|
|
it { is_expected.to be_nil }
|
|
|
|
it 'should not create a connection' do
|
|
expect(ActiveRecord::Base.connection_pool).not_to receive(:with_connection)
|
|
|
|
report_session
|
|
end
|
|
end
|
|
end
|
|
end
|