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