This is how much rspec I have so far for browser_autopwnv2_spec.rb
parent
ed69e5f902
commit
089579e354
|
@ -0,0 +1,537 @@
|
|||
require 'msf/core'
|
||||
|
||||
describe Msf::Exploit::Remote::BrowserAutopwnv2 do
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Recreate the environment (framework, mixins, etc)
|
||||
#
|
||||
|
||||
|
||||
|
||||
def mock_note_destroy
|
||||
# The destory method doesn't pass the note as an argument like framework.jobs_stop_job.
|
||||
# So here's I'm just gonna clear them all, and that sort of mimics #destroy.
|
||||
framework = double('Msf::Framework', datastore: {})
|
||||
|
||||
# This empties it
|
||||
notes = []
|
||||
|
||||
db = double('db')
|
||||
allow(db).to receive(:notes).and_return(notes)
|
||||
allow(framework).to receive(:db).and_return(db)
|
||||
|
||||
allow(subject).to receive(:framework).and_return(framework)
|
||||
end
|
||||
|
||||
def create_fake_note(tag, data)
|
||||
note = double('note')
|
||||
|
||||
allow(note).to receive(:ntype).and_return(tag)
|
||||
allow(note).to receive(:data).and_return(data)
|
||||
allow(note).to receive(:destroy) { mock_note_destroy }
|
||||
|
||||
note
|
||||
end
|
||||
|
||||
def mock_stop_job(arg)
|
||||
framework = double('Msf::Framework', datastore: {})
|
||||
jobs = subject.framework.jobs.delete_if {|e| e.first == arg.to_s}
|
||||
allow(jobs).to receive(:stop_job) { |arg| mock_stop_job(arg) }
|
||||
allow(framework).to receive(:jobs).and_return(jobs)
|
||||
allow(subject).to receive(:framework).and_return(framework)
|
||||
end
|
||||
|
||||
def create_fake_job(id)
|
||||
[id.to_s, double('job')]
|
||||
end
|
||||
|
||||
def create_fake_exploit(opts={})
|
||||
full_name = opts[:full_name]
|
||||
rank = opts[:rank] || 400
|
||||
disclosure_date = opts[:disclosure_date] || 'Dec 21 2014'
|
||||
compat_payloads = opts[:compat_payloads] || []
|
||||
datastore_options = opts[:datastore_options] || {}
|
||||
|
||||
mod = Msf::Exploit.new
|
||||
mod.extend(Msf::Exploit::Remote::BrowserExploitServer)
|
||||
|
||||
allow(mod).to receive(:fullname).and_return(full_name)
|
||||
allow(mod).to receive(:rank).and_return(rank)
|
||||
allow(mod).to receive(:disclosure_date).and_return(disclosure_date)
|
||||
allow(mod).to receive(:compatible_payloads).and_return(compat_payloads)
|
||||
allow(mod).to receive(:datastore).and_return(datastore_options)
|
||||
|
||||
mod
|
||||
end
|
||||
|
||||
def create_fake_ms14_064
|
||||
compat_payloads = ['windows/meterpreter/reverse_tcp']
|
||||
|
||||
create_fake_exploit(
|
||||
full_name: 'windows/browser/ms14_064_ole_code_execution',
|
||||
rank: 600,
|
||||
disclosure_date: 'Nov 13 2014',
|
||||
compat_payloads: compat_payloads,
|
||||
datastore_options: {'URI'=>'/ms14_064'}
|
||||
)
|
||||
end
|
||||
|
||||
def create_fake_flash_net_connection_confusion
|
||||
compat_payloads = ['windows/meterpreter/reverse_tcp', 'linux/x86/meterpreter/reverse_tcp']
|
||||
|
||||
create_fake_exploit(
|
||||
full_name: 'multi/browser/adobe_flash_net_connection_confusion',
|
||||
rank: 500,
|
||||
disclosure_date: 'Mar 12 2015',
|
||||
compat_payloads: compat_payloads,
|
||||
datastore_options: {'URI'=>'/flash1'}
|
||||
)
|
||||
end
|
||||
|
||||
def create_fake_flash_uncompress_zlib_uaf
|
||||
compat_payloads = ['windows/meterpreter/reverse_tcp', 'linux/x86/meterpreter/reverse_tcp']
|
||||
|
||||
create_fake_exploit(
|
||||
full_name: 'multi/browser/adobe_flash_uncompress_zlib_uaf',
|
||||
rank: 500,
|
||||
disclosure_date: 'Apr 28 2014',
|
||||
compat_payloads: compat_payloads,
|
||||
datastore_options: {'URI'=>'/flash2'}
|
||||
)
|
||||
end
|
||||
|
||||
def create_fake_windows_meterpreter
|
||||
p = Msf::Payload.new
|
||||
p.platform.platforms << Msf::Module::Platform::Windows
|
||||
p.arch << 'x86'
|
||||
p.datastore['LPORT'] = '4444'
|
||||
allow(p).to receive(:fullname).and_return('windows/meterpreter/reverse_tcp')
|
||||
allow(p).to receive(:shortname).and_return('reverse_tcp')
|
||||
|
||||
p
|
||||
end
|
||||
|
||||
def create_fake_linux_meterpreter
|
||||
p = Msf::Payload.new
|
||||
p.platform.platforms << Msf::Module::Platform::Linux
|
||||
p.arch << 'x86'
|
||||
p.datastore['LPORT'] = '4445'
|
||||
allow(p).to receive(:fullname).and_return('linux/x86/meterpreter/reverse_tcp')
|
||||
allow(p).to receive(:shortname).and_return('reverse_tcp')
|
||||
|
||||
p
|
||||
end
|
||||
|
||||
def mock_payload_create(full_name)
|
||||
available_payloads.each do |p|
|
||||
return p if p.fullname == full_name
|
||||
end
|
||||
|
||||
nil
|
||||
end
|
||||
|
||||
def mock_exploit_create(full_name)
|
||||
available_exploits.each do |x|
|
||||
return x if x.fullname == full_name
|
||||
end
|
||||
|
||||
nil
|
||||
end
|
||||
|
||||
let(:available_exploits) do
|
||||
@exploits ||= lambda {
|
||||
exploits = []
|
||||
|
||||
exploits << create_fake_ms14_064
|
||||
exploits << create_fake_flash_uncompress_zlib_uaf
|
||||
exploits << create_fake_flash_net_connection_confusion
|
||||
|
||||
exploits
|
||||
}.call
|
||||
end
|
||||
|
||||
let(:available_payloads) do
|
||||
@payloads ||= lambda {
|
||||
payloads = []
|
||||
|
||||
payloads << create_fake_windows_meterpreter
|
||||
payloads << create_fake_linux_meterpreter
|
||||
|
||||
payloads
|
||||
}.call
|
||||
end
|
||||
|
||||
let(:fake_exploit_hash) do
|
||||
exploits = {}
|
||||
|
||||
available_exploits.each do |x|
|
||||
exploits[x.fullname.to_s] = '__SYMBOLIC__'
|
||||
end
|
||||
|
||||
exploits
|
||||
end
|
||||
|
||||
let(:autopwn_datastore_options) do
|
||||
{
|
||||
'SRVHOST' => '0.0.0.0',
|
||||
'SRVPORT' => 8080,
|
||||
'MaxExploits' => 20,
|
||||
'MaxSessions' => -1,
|
||||
'PAYLOAD_ANDROID' => 'android/meterpreter/reverse_tcp',
|
||||
'PAYLOAD_FIREFOX' => 'firefox/shell_reverse_tcp',
|
||||
'PAYLOAD_GENERIC' => 'generic/shell_reverse_tcp',
|
||||
'PAYLOAD_JAVA' => 'java/meterpreter/reverse_tcp',
|
||||
'PAYLOAD_LINUX' => 'linux/x86/meterpreter/reverse_tcp',
|
||||
'PAYLOAD_OSX' => 'osx/x86/shell_reverse_tcp',
|
||||
'PAYLOAD_UNIX' => 'cmd/unix/reverse',
|
||||
'PAYLOAD_WIN' => 'windows/meterpreter/reverse_tcp',
|
||||
'PAYLOAD_ANDROID_LPORT' => 4443,
|
||||
'PAYLOAD_FIREFOX_LPORT' => 4442,
|
||||
'PAYLOAD_GENERIC_LPORT' => 4459,
|
||||
'PAYLOAD_JAVA_LPORT' => 4448,
|
||||
'PAYLOAD_LINUX_LPORT' => 4445,
|
||||
'PAYLOAD_OSX_LPORT' => 4447,
|
||||
'PAYLOAD_UNIX_LPORT' => 4446,
|
||||
'PAYLOAD_WIN_LPORT' => 4444
|
||||
}
|
||||
end
|
||||
|
||||
# When unpacked, this gives us:
|
||||
# {
|
||||
# "BAP.1433806920.Client.blLGFIlwYrxfvcY" => {
|
||||
# "source" => "script",
|
||||
# "os_name" => "Windows 8.1",
|
||||
# "os_vendor" => "undefined",
|
||||
# "os_device" => "undefined",
|
||||
# "ua_name" => "Firefox",
|
||||
# "ua_ver" => "35.0",
|
||||
# "arch" => "x86",
|
||||
# "java" => "1.7",
|
||||
# "silverlight" => "false",
|
||||
# "flash" => "14.0",
|
||||
# "vuln_test" => "true",
|
||||
# "proxy" => false,
|
||||
# "language" => "en-US,en;q=0.5",
|
||||
# "tried" => true
|
||||
# }}
|
||||
let(:profile_packed_data) do
|
||||
"\x81\xD9%BAP.1433806920.Client.blLGFIlwYrxfvcY\x8E\xA6source\xA6script\xA7os_name\xABWindows 8.1\xA9os_vendor\xA9undefined\xA9os_device\xA9undefined\xA7ua_name\xA7Firefox\xA6ua_ver\xA435.0\xA4arch\xA3x86\xA4java\xA31.7\xABsilverlight\xA5false\xA5flash\xA414.0\xA9vuln_test\xA4true\xA5proxy\xC2\xA8language\xC4\x0Een-US,en;q=0.5\xA5tried\xC3"
|
||||
end
|
||||
|
||||
let(:profile_tag) do
|
||||
MessagePack.unpack(profile_packed_data).keys.first.split('.')[3]
|
||||
end
|
||||
|
||||
let(:note_type_prefix) do
|
||||
MessagePack.unpack(profile_packed_data).keys.first.split('.')[0,3] * "."
|
||||
end
|
||||
|
||||
|
||||
before(:each) do
|
||||
framework = double('Msf::Framework', datastore: {})
|
||||
|
||||
# Prepare fake notes
|
||||
notes = [create_fake_note("#{note_type_prefix}.#{profile_tag}", profile_packed_data)]
|
||||
|
||||
# Prepare framework.db
|
||||
db = double('db')
|
||||
allow(db).to receive(:report_note).with(kind_of(Hash)) { mock_report_note }
|
||||
allow(db).to receive(:notes).and_return(notes)
|
||||
allow(db).to receive(:active).and_return(true)
|
||||
allow(framework).to receive(:db).and_return(db)
|
||||
|
||||
# Prepare framework.exploits
|
||||
exploits = double('exploits')
|
||||
allow(exploits).to receive(:create) { |arg| mock_exploit_create(arg) }
|
||||
allow(exploits).to receive(:each_pair).and_yield(available_exploits[0].fullname, '__SYMBOLIC__').and_yield(available_exploits[1].fullname, '__SYMBOLIC__').and_yield(available_exploits[2].fullname, '__SYMBOLIC__')
|
||||
allow(framework).to receive(:exploits).and_return(exploits)
|
||||
|
||||
# Prepare jobs
|
||||
jobs = {'0' => create_fake_job(0)}
|
||||
allow(jobs).to receive(:stop_job) { |arg| mock_stop_job(arg) }
|
||||
allow(framework).to receive(:jobs).and_return(jobs)
|
||||
|
||||
# Prepare payloads
|
||||
payloads = {}
|
||||
available_payloads.each do |p|
|
||||
payloads[p.fullname] = "__SYMBOLIC__"
|
||||
end
|
||||
allow(payloads).to receive(:create) { |arg| mock_payload_create(arg) }
|
||||
allow(framework).to receive(:payloads).and_return(payloads)
|
||||
|
||||
allow_any_instance_of(described_class).to receive(:framework).and_return(framework)
|
||||
end
|
||||
|
||||
subject do
|
||||
mod = Msf::Exploit::Remote.allocate
|
||||
mod.extend described_class
|
||||
mod.send(:initialize)
|
||||
mod.send(:datastore=, autopwn_datastore_options)
|
||||
allow(mod).to receive(:fullname).and_return('multi/browser/autopwn')
|
||||
mod
|
||||
end
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Method testing starts here
|
||||
#
|
||||
|
||||
|
||||
|
||||
describe '#init_exploits' do
|
||||
before(:each) do
|
||||
allow(subject).to receive(:set_exploit_options)
|
||||
subject.instance_variable_set(:@bap_exploits, [])
|
||||
end
|
||||
|
||||
context 'when two exploits are loaded' do
|
||||
it 'saves two exploits in instance variable @bap_exploits' do
|
||||
subject.init_exploits
|
||||
expect(subject.instance_variable_get(:@bap_exploits).length).to eq(3)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#note_type_prefix' do
|
||||
it 'returns an unique note type' do
|
||||
expect(subject.note_type_prefix).to match(/^BAP\.\d+\.Client$/)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#rm_target_info_notes' do
|
||||
before(:each) do
|
||||
allow(subject).to receive(:note_type_prefix).and_return("#{note_type_prefix}.#{profile_tag}")
|
||||
end
|
||||
|
||||
it 'empties target_info_notes' do
|
||||
subject.rm_target_info_notes
|
||||
expect(subject.framework.db.notes).to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
context 'when removing jobs' do
|
||||
let(:job_ids) do
|
||||
ids = []
|
||||
|
||||
subject.framework.jobs.each do |job|
|
||||
ids << job.first.to_i
|
||||
end
|
||||
|
||||
ids
|
||||
end
|
||||
|
||||
describe '#rm_exploit_jobs' do
|
||||
before(:each) do
|
||||
subject.instance_variable_set(:@exploit_job_ids, job_ids)
|
||||
end
|
||||
|
||||
it 'empties jobs' do
|
||||
expect(subject.framework.jobs.length).to eq(1)
|
||||
subject.rm_exploit_jobs
|
||||
expect(subject.framework.jobs).to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
describe '#rm_payload_jobs' do
|
||||
before(:each) do
|
||||
subject.instance_variable_set(:@payload_job_ids, job_ids)
|
||||
end
|
||||
|
||||
it 'empties jobs' do
|
||||
expect(subject.framework.jobs.length).to eq(1)
|
||||
subject.rm_payload_jobs
|
||||
expect(subject.framework.jobs).to be_empty
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#set_exploit_options' do
|
||||
before(:each) do
|
||||
payload_info = {
|
||||
payload_name: 'windows/meterpreter/reverse_tcp',
|
||||
payload_lport: 4444
|
||||
}
|
||||
|
||||
allow(subject).to receive(:select_payload).and_return([payload_info])
|
||||
end
|
||||
|
||||
let(:xploit) do
|
||||
create_fake_ms14_064
|
||||
end
|
||||
|
||||
context 'when a module is given' do
|
||||
before(:each) do
|
||||
subject.instance_variable_set(:@bap_exploits, [])
|
||||
subject.init_exploits
|
||||
subject.set_exploit_options(xploit)
|
||||
end
|
||||
|
||||
it 'sets the datastore options' do
|
||||
expect(xploit.datastore['URIPATH']).to match(/^\/\w+/)
|
||||
end
|
||||
|
||||
it 'sets Msf::Exploit::Remote::BrowserAutopwnv2 as MODULEOWNER' do
|
||||
expect(xploit.datastore['MODULEOWNER']).to eq(Msf::Exploit::Remote::BrowserAutopwnv2)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#is_resource_taken?' do
|
||||
before(:each) do
|
||||
allow(subject).to receive(:set_exploit_options)
|
||||
subject.instance_variable_set(:@bap_exploits, [])
|
||||
subject.init_exploits
|
||||
end
|
||||
|
||||
let(:repeated_resource) { '/flash1' }
|
||||
|
||||
let(:non_repeated_resource) { '/unique' }
|
||||
|
||||
context 'when a resource is repeated' do
|
||||
it 'returns true' do
|
||||
expect(subject.is_resource_taken?(repeated_resource)).to be_truthy
|
||||
end
|
||||
end
|
||||
|
||||
context 'when a resource is not repeated' do
|
||||
it 'returns false' do
|
||||
expect(subject.is_resource_taken?(non_repeated_resource)).to be_falsey
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#assign_module_resource' do
|
||||
it 'returns a resource' do
|
||||
allow(subject).to receive(:is_resource_taken?).and_return(false)
|
||||
expect(subject.assign_module_resource).to match(/^\w+$/)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
context 'when sorting' do
|
||||
before(:each) do
|
||||
allow(subject).to receive(:set_exploit_options)
|
||||
subject.instance_variable_set(:@bap_exploits, [])
|
||||
subject.init_exploits
|
||||
end
|
||||
|
||||
let(:bap_groups) { subject.group_bap_modules }
|
||||
|
||||
describe '#sort_date_in_group' do
|
||||
it 'returns modules sorted by date' do
|
||||
unsorted_first = 'multi/browser/adobe_flash_uncompress_zlib_uaf'
|
||||
expect(bap_groups[500].first.fullname).to eq(unsorted_first)
|
||||
|
||||
sorted_first = 'multi/browser/adobe_flash_net_connection_confusion'
|
||||
expect(subject.sort_date_in_group(bap_groups)[500].first.fullname).to eq(sorted_first)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#sort_group_by_rank' do
|
||||
it 'returns modules sorted by rank' do
|
||||
unsorted_order = [0, 100, 200, 300, 400, 500, 600]
|
||||
sorted_order = [0, 100, 200, 300, 400, 500, 600].reverse
|
||||
|
||||
expect(bap_groups.keys).to eq(unsorted_order)
|
||||
expect(subject.sort_group_by_rank(bap_groups).keys).to eq(sorted_order)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#group_bap_modules' do
|
||||
it 'returns modules sorted by group' do
|
||||
group_order = [0, 100, 200, 300, 400, 500, 600]
|
||||
expect(bap_groups.keys).to eq(group_order)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#finalize_sorted_modules' do
|
||||
context 'when MaxExploits is 1' do
|
||||
it 'returns one exploit' do
|
||||
expect(subject.instance_variable_get(:@bap_exploits).length).to eq(3)
|
||||
|
||||
allow(subject).to receive(:datastore).and_return({'MaxExploits'=>1})
|
||||
subject.finalize_sorted_modules(bap_groups)
|
||||
expect(subject.instance_variable_get(:@bap_exploits).length).to eq(1)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#get_selected_payload_name' do
|
||||
context 'when windows platform is given' do
|
||||
it 'returns windows/meterpreter/reverse_tcp' do
|
||||
expect(subject.get_selected_payload_name('win')).to eq('windows/meterpreter/reverse_tcp')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#get_selected_payload_lport' do
|
||||
end
|
||||
|
||||
describe '#get_payload_lhost' do
|
||||
end
|
||||
|
||||
describe '#start_payload_listeners' do
|
||||
end
|
||||
|
||||
describe '#parse_rank' do
|
||||
end
|
||||
|
||||
describe '#is_payload_platform_compatible?' do
|
||||
end
|
||||
|
||||
describe '#is_payload_compatible?' do
|
||||
end
|
||||
|
||||
describe '#is_multi_platform_exploit?' do
|
||||
end
|
||||
|
||||
describe '#select_payload' do
|
||||
end
|
||||
|
||||
describe '#start_exploits' do
|
||||
end
|
||||
|
||||
describe '#show_ready_exploits' do
|
||||
end
|
||||
|
||||
describe '#start_service' do
|
||||
end
|
||||
|
||||
describe '#show_payloads' do
|
||||
end
|
||||
|
||||
describe '#set_payload' do
|
||||
end
|
||||
|
||||
describe '#get_suitable_exploits' do
|
||||
end
|
||||
|
||||
describe '#log_click' do
|
||||
end
|
||||
|
||||
describe '#show_real_list' do
|
||||
end
|
||||
|
||||
describe '#get_exploit_urls' do
|
||||
end
|
||||
|
||||
describe '#on_request_uri' do
|
||||
end
|
||||
|
||||
describe '#is_ip_targeted?' do
|
||||
end
|
||||
|
||||
describe '#session_count' do
|
||||
end
|
||||
|
||||
describe '#get_custom_404_url' do
|
||||
end
|
||||
|
||||
describe '#build_html' do
|
||||
end
|
||||
|
||||
end
|
Loading…
Reference in New Issue