CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/post/multi/gather/check_malware.rb
Views: 11784
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
)
25
)
26
27
register_options(
28
[
29
OptString.new('APIKEY', [true, 'VirusTotal API key', '501caf66349cc7357eb4398ac3298fdd03dec01a3e2f3ad576525aa7b57a1987']),
30
OptString.new('REMOTEFILE', [true, 'A file to check from the remote machine'])
31
32
]
33
)
34
end
35
36
def rhost
37
session.session_host
38
end
39
40
def get_report(api_key, checksum)
41
#
42
# We have to use Net::HTTP instead of HttpClient because of the following error:
43
# The supplied module name is ambiguous: undefined method `register_autofilter_ports'
44
#
45
url = URI.parse('https://www.virustotal.com/vtapi/v2/file/report')
46
req = Net::HTTP::Post.new(url.path, initheader = { 'Host' => 'www.virustotal.com' })
47
req.set_form_data({ 'apikey' => api_key, 'resource' => checksum })
48
http = Net::HTTP.new(url.host, url.port)
49
http.use_ssl = true
50
res = http.start { |http| http.request(req) }
51
52
unless res
53
print_error("#{rhost} - Connection timed out")
54
return ''
55
end
56
57
case res.code
58
when 204
59
print_error("#{rhost} - You have reached the request limit, please wait for one minute to try again")
60
return ''
61
when 403
62
print_error("#{rhost} - No privilege to execute this request probably due to an invalye API key")
63
return ''
64
end
65
66
body = ''
67
begin
68
body = JSON.parse(res.body)
69
rescue JSON::ParserError
70
print_error("#{rhost} - Unable to parse the response")
71
return body
72
end
73
74
body
75
end
76
77
def show_report(res, filename)
78
md5 = res['md5'] || ''
79
sha1 = res['sha1'] || ''
80
sha256 = res['sha256'] || ''
81
82
print_status("#{rhost} - MD5: #{md5}") unless md5.blank?
83
print_status("#{rhost} - SHA1: #{sha1}") unless sha1.blank?
84
print_status("#{rhost} - SHA256: #{sha256}") unless sha256.blank?
85
86
tbl = Rex::Text::Table.new(
87
'Header' => "Analysis Report: #{filename} (#{res['positives']} / #{res['total']}): #{res['sha256']}",
88
'Indent' => 1,
89
'Columns' => ['Antivirus', 'Detected', 'Version', 'Result', 'Update']
90
)
91
92
res['scans'].each do |result|
93
product = result[0]
94
detected = result[1]['detected'].to_s
95
version = result[1]['version'] || ''
96
sig_name = result[1]['result'] || ''
97
timestamp = result[1]['update'] || ''
98
99
tbl << [product, detected, version, sig_name, timestamp]
100
end
101
102
report_note({
103
host: session,
104
type: 'malware.sample',
105
data: tbl.to_csv
106
})
107
print_status tbl.to_s
108
end
109
110
def run
111
filename = datastore['REMOTEFILE']
112
api_key = datastore['APIKEY']
113
114
unless file?(filename)
115
print_error("#{rhost} - File not found: #{filename}")
116
return
117
end
118
119
checksum = file_remote_digestsha1(filename)
120
print_status("#{rhost} - Checking: #{filename}...")
121
report = get_report(api_key, checksum)
122
123
return if report.blank?
124
125
print_status("#{rhost} - VirusTotal message: #{report['verbose_msg']}")
126
if report['response_code'] == 1
127
show_report(report, File.basename(filename))
128
end
129
end
130
end
131
132