Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/spec/tools/virustotal_spec.rb
Views: 11766
require 'spec_helper'12load Metasploit::Framework.root.join('tools/exploit/virustotal.rb').to_path34require 'msfenv'5require 'digest/sha2'67RSpec.describe VirusTotalUtility do89context "Classes" do10let(:api_key) do11'FAKE_API_KEY'12end1314let(:filename) do15'MALWARE.EXE'16end1718let(:malware_data) do19'DATA'20end2122describe VirusTotalUtility::ToolConfig do23context "Class methods" do2425let(:tool_config) do26VirusTotalUtility::ToolConfig.new27end2829context ".Initializer" do30it "should init the config file path as Metasploit's default config path" do31expect(tool_config.instance_variable_get(:@config_file)).to eq(Msf::Config.config_file)32end3334it "should init the group name as 'VirusTotal'" do35expect(tool_config.instance_variable_get(:@group_name)).to eq('VirusTotal')36end37end38end39end4041describe VirusTotalUtility::VirusTotal do42context "Class methods" do4344let(:malware_sha256) do45Digest::SHA256.hexdigest(malware_data)46end4748let(:sample) do49{50'filename' => filename,51'data' => malware_data,52'sha256' => malware_sha25653}54end5556let(:boundary) do57'THEREAREMANYLIKEITBUTTHISISMYDATA'58end5960let(:scan_sample_opts) do61opts = {62'boundary' => boundary,63'api_key' => api_key,64'filename' => filename,65'data' => malware_data66}6768return opts69end7071let(:retrieve_report_opts) do72opts = {73'uri' => '/vtapi/v2/file/report',74'method' => 'POST',75'vhost' => 'www.virustotal.com',76'vars_post' => {77'apikey' => api_key,78'resource' => malware_sha25679}80}8182return opts83end8485let(:vt) do86file = double(File, read: malware_data)87allow(File).to receive(:open).with(filename, 'rb') {|&block| block.yield file}88VirusTotalUtility::VirusTotal.new({'api_key'=>api_key, 'sample'=>filename})89end9091context ".Initializer" do92it "should have an API key" do93expect(vt.instance_variable_get(:@api_key)).to eq(api_key)94end9596it "should have a checksum for the malware sample" do97expect(vt.instance_variable_get(:@sample_info)['sha256']).to eq(malware_sha256)98end99end100101context "._load_sample" do102it "should contain sample info including data, filename, and sha256" do103expect(vt.send(:_load_sample, filename)).to eq(sample)104end105end106107context ".scan_sample" do108it "should return with data" do109expect(vt).to receive(:_execute_request).and_return('')110expect(vt.scan_sample).to eq('')111end112end113114context ".retrieve_report" do115it "should return with data" do116expect(vt).to receive(:_execute_request).and_return('')117expect(vt.retrieve_report).to eq('')118end119end120121context "._execute_request" do122it "should return status code 204" do123res = double(Rex::Proto::Http::Response)124expect(res).to receive(:code).and_return(204)125expect(vt).to receive(:send_request_cgi).with(scan_sample_opts).and_return(res)126expect { vt.send(:_execute_request, scan_sample_opts) }.to raise_error(RuntimeError)127end128129it "should return status code 403" do130res = double(Rex::Proto::Http::Response)131expect(res).to receive(:code).and_return(403)132expect(vt).to receive(:send_request_cgi).with(scan_sample_opts).and_return(res)133expect { vt.send(:_execute_request, scan_sample_opts) }.to raise_error(RuntimeError)134end135end136137context "._create_upload_data" do138139let(:form_opts) do140{141'boundary' => boundary,142'api_key' => api_key,143'filename' => filename,144'data' => malware_data145}146end147148before(:example) do149@upload_data = vt.send(:_create_upload_data, form_opts)150end151152it "should create form-data with a boundary" do153expect(@upload_data).to match(/#{boundary}/)154end155156it "should create form-data with the API key" do157expect(@upload_data).to match(/#{api_key}/)158end159160it "should create form-data with the malware filename" do161expect(@upload_data).to match(/#{filename}/)162end163164it "should create form-data with the malware data" do165expect(@upload_data).to match(/#{malware_data}/)166end167end168end169end170171172describe VirusTotalUtility::Driver do173before do174$stdin = StringIO.new("Y\n")175end176177after do178$stdin = STDIN179end180181let(:driver) do182argv = "-k #{api_key} -f #{filename}".split183options = {184'samples' => filename,185'api_key' => api_key,186'delay' => 60187}188189expect(VirusTotalUtility::OptsConsole).to receive(:parse).with(anything).and_return(options)190191tool_config = instance_double(192VirusTotalUtility::ToolConfig,193has_privacy_waiver?: true,194load_api_key: api_key,195save_api_key: nil,196save_privacy_waiver: nil197)198199expect(VirusTotalUtility::ToolConfig).to receive(:new).and_return(tool_config)200201d = nil202203get_stdout {204d = VirusTotalUtility::Driver.new205}206207d208end209210context ".Class methods" do211212context ".initialize" do213it "should return a Driver object" do214expect(driver.class).to eq(VirusTotalUtility::Driver)215end216end217218context ".ask_privacy" do219it "should have a link of VirusTotal's terms of service" do220tos = 'https://www.virustotal.com/en/about/terms-of-service'221out = get_stdout { driver.ack_privacy }222expect(out).to match(/#{tos}/)223end224end225226context ".generate_report" do227it "should show a report" do228res = {229"scans" => {230"Bkav" => { "detected" => false, "version" => "1.3.0.4613", "result" => nil, "update" => "20140107" }231},232"response_code" => 1233}234235out = get_stdout { driver.generate_report(res, filename) }236expect(out).to match(/#{res['scans']['Bkav']['version']}/)237end238end239end240end241end242end243244245