diff --git a/spec/lib/msf/core/exploit/remote/browser_profile_manager_spec.rb b/spec/lib/msf/core/exploit/remote/browser_profile_manager_spec.rb new file mode 100644 index 0000000000..c048fd0ef9 --- /dev/null +++ b/spec/lib/msf/core/exploit/remote/browser_profile_manager_spec.rb @@ -0,0 +1,158 @@ +require 'spec_helper' +require 'msf/core' + +describe Msf::Exploit::Remote::BrowserProfileManager do + + + def mock_report_note(args) + # args example: + # {:type=>"blLGFIlwYrxfvcY.new_tag", :data=>"\x81\xB7blLGFIlwYrxfvcY.new_tag\x80", :update=>:unique} + @notes.each do |note| + if note.ntype == args[:type] + allow(note).to receive(:data).and_return(args[:data]) + return + end + end + + # No profile found + note = create_fake_note(args[:type], args[:data]) + @notes << note + 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) + + note + 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 + + subject do + mod = Msf::Exploit::Remote.allocate + mod.extend Msf::Exploit::Remote::BrowserExploitServer + mod.extend described_class + mod.send(:initialize) + mod.send(:datastore=, {'NoteTypePrefix' => note_type_prefix}) + mod + end + + let(:framework) do + framework = double('Msf::Framework', datastore: {}) + + notes = [create_fake_note("#{note_type_prefix}.#{profile_tag}", profile_packed_data)] + @notes = notes + + db = double('db') + allow(db).to receive(:report_note).with(kind_of(Hash)) { |arg| mock_report_note(arg) } + allow(db).to receive(:notes).and_return(notes) + allow(framework).to receive(:db).and_return(db) + + framework + end + + before(:each) do + allow_any_instance_of(described_class).to receive(:framework).and_return(framework) + end + + describe '#note_type_prefix' do + context 'when note_type_prefix is used' do + it 'raises a NoMethodError exception' do + expect(subject.note_type_prefix).to eq(note_type_prefix) + end + end + end + + describe '#get_profile_info' do + + let(:found_profile) do + end + + context 'when profile is found' do + it 'returns a hash with the profile' do + found_profile = subject.get_profile_info(profile_tag) + found_profile_key = found_profile.keys.first + found_profile_data = found_profile[found_profile_key] + profile_data = MessagePack.unpack(profile_packed_data).values.first + expect(found_profile).to be_kind_of(Hash) + expect(found_profile_data).to eq(profile_data) + end + end + + context 'when a profile is not found' do + it 'returns an empty hash' do + bad_profile_tag = 'bad_profile_tag' + found_profile = subject.get_profile_info(bad_profile_tag) + expect(found_profile).to be_kind_of(Hash) + expect(found_profile).to be_empty + end + end + end + + describe '#update_profile' do + + let(:key_to_update) { 'os_name' } + + let(:os_value) { 'Windows 7' } + + context 'when no profile is on the database' do + let(:new_profile_tag) { 'new_tag' } + it 'creates a new profile' do + end + + it 'updates data to the new profile' do + subject.update_profile(new_profile_tag, key_to_update, os_value) + expect(subject.get_profile_info(new_profile_tag).keys.first).to eq("#{note_type_prefix}.#{new_profile_tag}") + expect(subject.get_profile_info(new_profile_tag).values.first).to eq({key_to_update => os_value}) + end + end + + context 'when the profile is found on the database' do + it 'updates the profile' do + expect(subject.get_profile_info(profile_tag).values.first[key_to_update]).to eq('Windows 8.1') + subject.update_profile(profile_tag, key_to_update, os_value) + expect(subject.get_profile_info(profile_tag).values.first[key_to_update]).to eq(os_value) + end + end + end + + describe '#init_profile' do + context 'creates a tag is provided' do + it 'creates a new profile' do + expect(@notes.length).to eq(1) + subject.init_profile('new') + expect(@notes.length).to eq(2) + end + end + end + +end \ No newline at end of file