Mirror of metasploit
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

check_malware.rb 3.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. ##
  2. # This module requires Metasploit: http://metasploit.com/download
  3. # Current source: https://github.com/rapid7/metasploit-framework
  4. ##
  5. require 'msf/core'
  6. require 'net/http'
  7. require 'uri'
  8. class MetasploitModule < Msf::Post
  9. include Msf::Post::File
  10. def initialize(info={})
  11. super( update_info( info,
  12. 'Name' => 'Multi Gather Malware Verifier',
  13. 'Description' => %q{
  14. This module will check a file for malware on VirusTotal based on the checksum.
  15. },
  16. 'License' => MSF_LICENSE,
  17. 'Author' => [ 'sinn3r'],
  18. 'Platform' => [ 'osx', 'win', 'linux' ],
  19. 'SessionTypes' => [ "shell", "meterpreter" ]
  20. ))
  21. register_options(
  22. [
  23. OptString.new('APIKEY', [true, "VirusTotal API key", '501caf66349cc7357eb4398ac3298fdd03dec01a3e2f3ad576525aa7b57a1987']),
  24. OptString.new('REMOTEFILE', [true, "A file to check from the remote machine"])
  25. ], self.class)
  26. end
  27. def rhost
  28. session.session_host
  29. end
  30. def get_report(api_key, checksum)
  31. #
  32. # We have to use Net::HTTP instead of HttpClient because of the following error:
  33. # The supplied module name is ambiguous: undefined method `register_autofilter_ports'
  34. #
  35. url = URI.parse("https://www.virustotal.com/vtapi/v2/file/report")
  36. req = Net::HTTP::Post.new(url.path, initheader={'Host'=>'www.virustotal.com'})
  37. req.set_form_data({'apikey'=>api_key, 'resource'=>checksum})
  38. http = Net::HTTP::new(url.host, url.port)
  39. http.use_ssl = true
  40. res = http.start {|http| http.request(req)}
  41. unless res
  42. print_error("#{rhost} - Connection timed out")
  43. return ''
  44. end
  45. case res.code
  46. when 204
  47. print_error("#{rhost} - You have reached the request limit, please wait for one minute to try again")
  48. return ''
  49. when 403
  50. print_error("#{rhost} - No privilege to execute this request probably due to an invalye API key")
  51. return ''
  52. end
  53. body = ''
  54. begin
  55. body = JSON.parse(res.body)
  56. rescue JSON::ParserError
  57. print_error("#{rhost} - Unable to parse the response")
  58. return body
  59. end
  60. body
  61. end
  62. def show_report(res, filename)
  63. md5 = res['md5'] || ''
  64. sha1 = res['sha1'] || ''
  65. sha256 = res['sha256'] || ''
  66. print_status("#{rhost} - MD5: #{md5}") unless md5.blank?
  67. print_status("#{rhost} - SHA1: #{sha1}") unless sha1.blank?
  68. print_status("#{rhost} - SHA256: #{sha256}") unless sha256.blank?
  69. tbl = Rex::Text::Table.new(
  70. 'Header' => "Analysis Report: #{filename} (#{res['positives']} / #{res['total']}): #{res['sha256']}",
  71. 'Indent' => 1,
  72. 'Columns' => ['Antivirus', 'Detected', 'Version', 'Result', 'Update']
  73. )
  74. res['scans'].each do |result|
  75. product = result[0]
  76. detected = result[1]['detected'].to_s
  77. version = result[1]['version'] || ''
  78. sig_name = result[1]['result'] || ''
  79. timestamp = result[1]['update'] || ''
  80. tbl << [product, detected, version, sig_name, timestamp]
  81. end
  82. report_note({
  83. :host => session,
  84. :type => 'malware.sample',
  85. :data => tbl.to_csv
  86. })
  87. print_status tbl.to_s
  88. end
  89. def run
  90. filename = datastore['REMOTEFILE']
  91. api_key = datastore['APIKEY']
  92. unless file?(filename)
  93. print_error("#{rhost} - File not found: #{filename}")
  94. return
  95. end
  96. checksum = file_remote_digestsha1(filename)
  97. print_status("#{rhost} - Checking: #{filename}...")
  98. report = get_report(api_key, checksum)
  99. return if report.blank?
  100. print_status("#{rhost} - VirusTotal message: #{report['verbose_msg']}")
  101. if report['response_code'] == 1
  102. show_report(report, File.basename(filename))
  103. end
  104. end
  105. end