Path: blob/master/modules/post/multi/gather/check_malware.rb
19566 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45require 'net/http'6require 'uri'78class MetasploitModule < Msf::Post9include Msf::Post::File1011def initialize(info = {})12super(13update_info(14info,15'Name' => 'Multi Gather Malware Verifier',16'Description' => %q{17This module will check a file for malware on VirusTotal based on the checksum.18},19'License' => MSF_LICENSE,20'Author' => [ 'sinn3r'],21'Platform' => [ 'osx', 'win', 'linux' ],22'SessionTypes' => [ 'shell', 'meterpreter' ],23'Notes' => {24'Stability' => [CRASH_SAFE],25'SideEffects' => [],26'Reliability' => []27}28)29)3031register_options(32[33OptString.new('APIKEY', [true, 'VirusTotal API key', '501caf66349cc7357eb4398ac3298fdd03dec01a3e2f3ad576525aa7b57a1987']),34OptString.new('REMOTEFILE', [true, 'A file to check from the remote machine'])35]36)37end3839def rhost40session.session_host41end4243def get_report(api_key, checksum)44#45# We have to use Net::HTTP instead of HttpClient because of the following error:46# The supplied module name is ambiguous: undefined method `register_autofilter_ports'47#48url = URI.parse('https://www.virustotal.com/vtapi/v2/file/report')49req = Net::HTTP::Post.new(url.path, { 'Host' => 'www.virustotal.com' })50req.set_form_data({ 'apikey' => api_key, 'resource' => checksum })51http = Net::HTTP.new(url.host, url.port)52http.use_ssl = true53res = http.start { |h| h.request(req) }5455unless res56print_error("#{rhost} - Connection timed out")57return ''58end5960case res.code61when 20462print_error("#{rhost} - You have reached the request limit, please wait for one minute to try again")63return ''64when 40365print_error("#{rhost} - No privilege to execute this request probably due to an invalye API key")66return ''67end6869body = ''70begin71body = JSON.parse(res.body)72rescue JSON::ParserError73print_error("#{rhost} - Unable to parse the response")74return body75end7677body78end7980def show_report(res, filename)81md5 = res['md5'] || ''82sha1 = res['sha1'] || ''83sha256 = res['sha256'] || ''8485print_status("#{rhost} - MD5: #{md5}") unless md5.blank?86print_status("#{rhost} - SHA1: #{sha1}") unless sha1.blank?87print_status("#{rhost} - SHA256: #{sha256}") unless sha256.blank?8889tbl = Rex::Text::Table.new(90'Header' => "Analysis Report: #{filename} (#{res['positives']} / #{res['total']}): #{res['sha256']}",91'Indent' => 1,92'Columns' => ['Antivirus', 'Detected', 'Version', 'Result', 'Update']93)9495res['scans'].each do |result|96product = result[0]97detected = result[1]['detected'].to_s98version = result[1]['version'] || ''99sig_name = result[1]['result'] || ''100timestamp = result[1]['update'] || ''101102tbl << [product, detected, version, sig_name, timestamp]103end104105report_note({106host: session,107type: 'malware.sample',108data: { :csv_table => tbl.to_csv }109})110print_status tbl.to_s111end112113def run114filename = datastore['REMOTEFILE']115api_key = datastore['APIKEY']116117unless file?(filename)118print_error("#{rhost} - File not found: #{filename}")119return120end121122checksum = file_remote_digestsha1(filename)123print_status("#{rhost} - Checking: #{filename}...")124report = get_report(api_key, checksum)125126return if report.blank?127128print_status("#{rhost} - VirusTotal message: #{report['verbose_msg']}")129if report['response_code'] == 1130show_report(report, File.basename(filename))131end132end133end134135136