uirusu 0.0.0 → 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/NEWS.markdown +1 -1
- data/README.markdown +42 -0
- data/Rakefile +3 -3
- data/bin/uirusu +7 -1
- data/lib/uirusu.rb +7 -1
- data/lib/uirusu/cli/application.rb +243 -0
- data/lib/uirusu/vtcomment.rb +41 -0
- data/lib/uirusu/vtfile.rb +66 -0
- data/lib/uirusu/vtresult.rb +132 -0
- data/lib/uirusu/vturl.rb +66 -0
- metadata +13 -9
data/NEWS.markdown
CHANGED
data/README.markdown
CHANGED
@@ -1,2 +1,44 @@
|
|
1
1
|
# uirusu
|
2
2
|
|
3
|
+
uirusu is [virustotal](http://www.virustotal.com) automation and convenience tool for hash, file and URL submission.
|
4
|
+
|
5
|
+
The current version is 0.0.1
|
6
|
+
|
7
|
+
## Requirements
|
8
|
+
|
9
|
+
* ruby
|
10
|
+
* rubygems
|
11
|
+
* json
|
12
|
+
* rest-client
|
13
|
+
|
14
|
+
* **public api key from [virustotal.com](http://www.virustotal.com)**
|
15
|
+
|
16
|
+
## Installation
|
17
|
+
|
18
|
+
% gem install uirusu
|
19
|
+
% uirusu [options]
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
### Searching a file of hashes
|
24
|
+
|
25
|
+
% uirusu -f <file_with_hashes_one_per_line>
|
26
|
+
|
27
|
+
### Searching a single hash
|
28
|
+
|
29
|
+
% uirusu -h FD287794107630FA3116800E617466A9
|
30
|
+
|
31
|
+
### Searching a file of hashes and outputting to XML
|
32
|
+
% uirusu -f <file_with_hashes_one_per_line> -x
|
33
|
+
|
34
|
+
### Upload a file to Virustotal and wait for analysis
|
35
|
+
% uirusu -u </path/to/file>
|
36
|
+
|
37
|
+
### Search for a single URL
|
38
|
+
% uirusu -s "http://www.google.com"
|
39
|
+
|
40
|
+
### Saving results to a file
|
41
|
+
% uirusu -s "http://www.google.com" --yaml-output > file.yaml
|
42
|
+
|
43
|
+
## Contact
|
44
|
+
You can reach me at Jacob[dot]Hammack[at]hammackj[dot]com or http://www.hammackj.com
|
data/Rakefile
CHANGED
@@ -19,10 +19,10 @@ task :clean do
|
|
19
19
|
system "rm -rf coverage"
|
20
20
|
end
|
21
21
|
|
22
|
-
task :default => [:
|
22
|
+
task :default => [:test]
|
23
23
|
|
24
|
-
Rake::TestTask.new("
|
24
|
+
Rake::TestTask.new("test") do |t|
|
25
25
|
t.libs << "test"
|
26
26
|
t.pattern = 'test/*/*_test.rb'
|
27
27
|
t.verbose = true
|
28
|
-
|
28
|
+
end
|
data/bin/uirusu
CHANGED
data/lib/uirusu.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module Uirusu
|
2
2
|
APP_NAME = "uirusu"
|
3
|
-
VERSION = "0.0.
|
3
|
+
VERSION = "0.0.1"
|
4
4
|
CONFIG_FILE = "~/.uirusu"
|
5
5
|
end
|
6
6
|
|
@@ -8,3 +8,9 @@ require 'json'
|
|
8
8
|
require 'rest_client'
|
9
9
|
require 'optparse'
|
10
10
|
require 'yaml'
|
11
|
+
|
12
|
+
require 'uirusu/vtfile'
|
13
|
+
require 'uirusu/vturl'
|
14
|
+
require 'uirusu/vtcomment'
|
15
|
+
require 'uirusu/vtresult'
|
16
|
+
require 'uirusu/cli/application'
|
@@ -0,0 +1,243 @@
|
|
1
|
+
module Uirusu
|
2
|
+
module CLI
|
3
|
+
class Application
|
4
|
+
|
5
|
+
# Creates a new instance of the [Application] class
|
6
|
+
#
|
7
|
+
def initialize
|
8
|
+
@options = {}
|
9
|
+
@config = {}
|
10
|
+
@hashes = Array.new
|
11
|
+
@files_of_hashes = Array.new
|
12
|
+
@sites = Array.new
|
13
|
+
@uploads = Array.new
|
14
|
+
end
|
15
|
+
|
16
|
+
# Parses the command the line options and returns the parsed options hash
|
17
|
+
#
|
18
|
+
# @return [Hash] of the parsed options
|
19
|
+
def parse_options(args)
|
20
|
+
begin
|
21
|
+
@options['output'] = :stdout
|
22
|
+
@options['verbose'] = false
|
23
|
+
|
24
|
+
opt = OptionParser.new do |opt|
|
25
|
+
opt.banner = "#{APP_NAME} v#{VERSION}\nJacob Hammack\nhttp://www.hammackj.com\n\n"
|
26
|
+
opt.banner << "Usage: #{APP_NAME} <options>"
|
27
|
+
opt.separator('')
|
28
|
+
opt.separator("File Options")
|
29
|
+
|
30
|
+
opt.on('-h HASH', '--search-hash HASH', 'Searches a single hash on virustotal.com') do |hash|
|
31
|
+
@hashes.push(hash)
|
32
|
+
end
|
33
|
+
|
34
|
+
opt.on('-f FILE', '--search-hash-file FILE', 'Searches a each hash in a file of hashes on virustotal.com') do |file|
|
35
|
+
if File.exists?(file)
|
36
|
+
puts "[+] Adding file #{file}" if @options["verbose"]
|
37
|
+
@files_of_hashes.push(file)
|
38
|
+
else
|
39
|
+
puts "[!] #{file} does not exist, please check your input!\n"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
opt.on('-u FILE', '--upload-file FILE', 'Uploads a file to virustotal.com for analysis') do |file|
|
44
|
+
if File.exists?(file)
|
45
|
+
puts "[+] Adding file #{file}" if @options["verbose"]
|
46
|
+
@uploads.push(file)
|
47
|
+
else
|
48
|
+
puts "[!] #{file} does not exist, please check your input!\n"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
opt.separator('')
|
53
|
+
opt.separator("Url Options")
|
54
|
+
|
55
|
+
opt.on('-s SITE', '--search-site SITE', 'Searches for a single url on virustotal.com') { |site|
|
56
|
+
@sites.push(site)
|
57
|
+
}
|
58
|
+
|
59
|
+
opt.separator('')
|
60
|
+
opt.separator('Output Options')
|
61
|
+
|
62
|
+
opt.on('-x', '--xml-output', 'Print results as xml to stdout') do
|
63
|
+
@options["output"] = :xml
|
64
|
+
end
|
65
|
+
|
66
|
+
opt.on('-y', '--yaml-output', 'Print results as yaml to stdout') do
|
67
|
+
@options['output'] = :yaml
|
68
|
+
end
|
69
|
+
|
70
|
+
opt.on('--stdout-output', 'Print results as normal text line to stdout, this is default') do
|
71
|
+
@options['output'] = :stdout
|
72
|
+
end
|
73
|
+
|
74
|
+
opt.separator ''
|
75
|
+
opt.separator 'Advanced Options'
|
76
|
+
|
77
|
+
opt.on('-c', '--create-config', 'Creates a skeleton config file to use') do
|
78
|
+
if File.exists?(File.expand_path(CONFIG_FILE)) == false
|
79
|
+
File.open(File.expand_path(CONFIG_FILE), 'w+') do |f|
|
80
|
+
f.write("virustotal: \n api-key: \n timeout: 25\n\n")
|
81
|
+
end
|
82
|
+
|
83
|
+
puts "[*] An empty #{File.expand_path(CONFIG_FILE)} has been created. Please edit and fill in the correct values."
|
84
|
+
exit
|
85
|
+
else
|
86
|
+
puts "[!] #{File.expand_path(CONFIG_FILE)} already exists. Please delete it if you wish to re-create it."
|
87
|
+
exit
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
opt.on('--[no-]verbose', 'Print verbose information') do |v|
|
92
|
+
@options["verbose"] = v
|
93
|
+
end
|
94
|
+
|
95
|
+
opt.separator ''
|
96
|
+
opt.separator 'Other Options'
|
97
|
+
|
98
|
+
opt.on('-v', '--version', "Shows application version information") do
|
99
|
+
puts "#{APP_NAME} - #{VERSION}"
|
100
|
+
exit
|
101
|
+
end
|
102
|
+
|
103
|
+
opt.on_tail("-?", "--help", "Show this message") { |help|
|
104
|
+
puts opt.to_s + "\n"
|
105
|
+
exit
|
106
|
+
}
|
107
|
+
end
|
108
|
+
|
109
|
+
if ARGV.length != 0
|
110
|
+
opt.parse!
|
111
|
+
else
|
112
|
+
puts opt.to_s + "\n"
|
113
|
+
exit
|
114
|
+
end
|
115
|
+
rescue OptionParser::MissingArgument => m
|
116
|
+
puts opt.to_s + "\n"
|
117
|
+
exit
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
# Loads the .uirusu config file for the api key
|
122
|
+
#
|
123
|
+
def load_config
|
124
|
+
if File.exists?(File.expand_path(CONFIG_FILE))
|
125
|
+
@config = YAML.load_file File.expand_path(CONFIG_FILE)
|
126
|
+
else
|
127
|
+
STDERR.puts "[!] #{CONFIG_FILE} does not exist. Please run #{APP_NAME} --create-config, to create it."
|
128
|
+
exit
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
# Submits a file/url and waits for analysis to be complete and returns the results.
|
133
|
+
#
|
134
|
+
# @param mod
|
135
|
+
# @param resource
|
136
|
+
# @param attempts
|
137
|
+
#
|
138
|
+
def scan_and_wait(mod, resource, attempts)
|
139
|
+
method = nil
|
140
|
+
retries = attempts
|
141
|
+
|
142
|
+
if mod.name == "Uirusu::VTFile"
|
143
|
+
method = mod.method :scan_file
|
144
|
+
else
|
145
|
+
method = mod.method :scan_url
|
146
|
+
end
|
147
|
+
|
148
|
+
begin
|
149
|
+
STDERR.puts "[*] Attempting to upload file #{resource}" if @options["verbose"]
|
150
|
+
result = method.call(@config["virustotal"]["api-key"], resource)
|
151
|
+
rescue => e
|
152
|
+
STDERR.puts "[!] An error has occured uploading the file. Retrying 60 seconds up #{retries} retries.\n" if @options["verbose"]
|
153
|
+
if retries >= 0
|
154
|
+
sleep 60
|
155
|
+
retry
|
156
|
+
retries = retries - 1
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
begin
|
161
|
+
if result['response_code'] == 1
|
162
|
+
results = mod.query_report(@config["virustotal"]["api-key"], result['resource'])
|
163
|
+
|
164
|
+
while results["response_code"] != 1
|
165
|
+
STDERR.puts "[*] File has not been analyized yet, waiting 60 seconds to try again" if @options["verbose"]
|
166
|
+
sleep 60
|
167
|
+
results = mod.query_report(@config["virustotal"]["api-key"], result['resource'])
|
168
|
+
end
|
169
|
+
|
170
|
+
return [result['resource'], results]
|
171
|
+
elsif result['response_code'] == -2
|
172
|
+
STDERR.puts "[!] Virustotal limits exceeded, ***do not edit the timeout values.***"
|
173
|
+
exit(1)
|
174
|
+
else
|
175
|
+
nil
|
176
|
+
end
|
177
|
+
rescue => e
|
178
|
+
STDERR.puts "[!] An error has occured retrieving the report. Retrying 60 seconds up #{retries} retries.\n" if @options["verbose"]
|
179
|
+
if retries >= 0
|
180
|
+
sleep 60
|
181
|
+
retry
|
182
|
+
retries = retries - 1
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
#
|
188
|
+
#
|
189
|
+
def main(args)
|
190
|
+
parse_options(args)
|
191
|
+
load_config
|
192
|
+
|
193
|
+
if @options['output'] == :stdout
|
194
|
+
output_method = :to_stdout
|
195
|
+
elsif @options['output'] == :yaml
|
196
|
+
output_method = :to_yaml
|
197
|
+
elsif @options['output'] == :xml
|
198
|
+
output_method = :to_xml
|
199
|
+
print "<results>\n"
|
200
|
+
end
|
201
|
+
|
202
|
+
if @files_of_hashes != nil
|
203
|
+
@files_of_hashes.each do |file|
|
204
|
+
f = File.open(file, 'r')
|
205
|
+
|
206
|
+
f.each do |hash|
|
207
|
+
hash.chomp!
|
208
|
+
@hashes.push hash
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
if @hashes != nil
|
214
|
+
@hashes.each do |hash|
|
215
|
+
results = Uirusu::VTFile.query_report(@config["virustotal"]["api-key"], hash)
|
216
|
+
result = Uirusu::VTResult.new(hash, results)
|
217
|
+
print result.send output_method if result != nil
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
if @sites != nil
|
222
|
+
@sites.each do |url|
|
223
|
+
results = scan_and_wait(Uirusu::VTUrl, url, 5)
|
224
|
+
result = Uirusu::VTResult.new(results[0], results[1])
|
225
|
+
print result.send output_method if result != nil
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
if @uploads != nil
|
230
|
+
@uploads.each do |upload|
|
231
|
+
results = scan_and_wait(Uirusu::VTFile, upload, 5)
|
232
|
+
result = Uirusu::VTResult.new(results[0], results[1])
|
233
|
+
print result.send output_method if result != nil
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
if @options['output'] == :xml
|
238
|
+
print "</results>\n"
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Uirusu
|
2
|
+
# Module for submiting comments to Virustotal.com resources using the
|
3
|
+
# Virustotal.com public API
|
4
|
+
module VTComment
|
5
|
+
POST_URL = "https://www.virustotal.com/vtapi/v2/comments/put"
|
6
|
+
|
7
|
+
# Submits a comment to Virustotal.com for a specific resource
|
8
|
+
#
|
9
|
+
# @param [String] api_key Virustotal.com API key
|
10
|
+
# @param [String] resource MD5/sha1/sha256/scan_id to search for
|
11
|
+
# @param [String] comment Comment to post to the resource
|
12
|
+
#
|
13
|
+
# @return [JSON] Parsed response
|
14
|
+
def self.post_comment(api_key, resource, comment)
|
15
|
+
if api_key == nil
|
16
|
+
raise "Invalid API Key"
|
17
|
+
end
|
18
|
+
|
19
|
+
if resource == nil
|
20
|
+
raise "Invalid resource, must be a valid url"
|
21
|
+
end
|
22
|
+
|
23
|
+
if comment == nil
|
24
|
+
raise "You must provide a comment to submit."
|
25
|
+
end
|
26
|
+
|
27
|
+
response = RestClient.post POST_URL, :apikey => api_key, :resource => resource, :comment => comment
|
28
|
+
|
29
|
+
case response.code
|
30
|
+
when 429
|
31
|
+
raise "Virustotal limit reached. Try again later."
|
32
|
+
when 403
|
33
|
+
raise "Invalid privileges, please check your API key."
|
34
|
+
when 200
|
35
|
+
JSON.parse(response)
|
36
|
+
else
|
37
|
+
raise "Unknown Server error."
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module Uirusu
|
2
|
+
# Module for Accessing the File scan and report functionalities of the
|
3
|
+
# Virustotal.com public API
|
4
|
+
module VTFile
|
5
|
+
SCAN_URL = "http://www.virustotal.com/vtapi/v2/file/scan"
|
6
|
+
REPORT_URL = "https://www.virustotal.com/vtapi/v2/file/report"
|
7
|
+
|
8
|
+
# Queries a report from Virustotal.com
|
9
|
+
#
|
10
|
+
# @param api_key Virustotal.com API key
|
11
|
+
# @param resource MD5/sha1/sha256/scan_id to search for
|
12
|
+
#
|
13
|
+
# @return [JSON] Parsed response
|
14
|
+
def VTFile.query_report(api_key, resource)
|
15
|
+
if api_key == nil
|
16
|
+
raise "Invalid API Key"
|
17
|
+
end
|
18
|
+
|
19
|
+
if resource == nil
|
20
|
+
raise "Invalid resource, must be MD5/sha1/sha256/scan_id"
|
21
|
+
end
|
22
|
+
|
23
|
+
response = RestClient.post REPORT_URL, :apikey => api_key, :resource => resource
|
24
|
+
|
25
|
+
case response.code
|
26
|
+
when 429
|
27
|
+
raise "Virustotal limit reached. Try again later."
|
28
|
+
when 403
|
29
|
+
raise "Invalid privileges, please check your API key."
|
30
|
+
when 200
|
31
|
+
JSON.parse(response)
|
32
|
+
when 500
|
33
|
+
nil
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Submits a file to Virustotal.com for analysis
|
38
|
+
#
|
39
|
+
# @param api_key Virustotal.com API key
|
40
|
+
# @param path_to_file Path to file on disk to upload
|
41
|
+
#
|
42
|
+
# @return [JSON] Parsed response
|
43
|
+
def self.scan_file(api_key, path_to_file)
|
44
|
+
if !File.exists?(path_to_file)
|
45
|
+
raise Errno::ENOENT
|
46
|
+
end
|
47
|
+
|
48
|
+
if api_key == nil
|
49
|
+
raise "Invalid API Key"
|
50
|
+
end
|
51
|
+
|
52
|
+
response = RestClient.post SCAN_URL, :apikey => api_key, :filename=> path_to_file, :file => File.new(path_to_file, 'rb')
|
53
|
+
|
54
|
+
case response.code
|
55
|
+
when 429
|
56
|
+
raise "Virustotal limit reached. Try again later."
|
57
|
+
when 403
|
58
|
+
raise "Invalid privileges, please check your API key."
|
59
|
+
when 200
|
60
|
+
JSON.parse(response)
|
61
|
+
else
|
62
|
+
raise "Unknown Server error."
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
module Uirusu
|
2
|
+
#
|
3
|
+
#
|
4
|
+
class VTResult
|
5
|
+
def initialize hash, result
|
6
|
+
if result == nil
|
7
|
+
return
|
8
|
+
end
|
9
|
+
|
10
|
+
@results = Array.new
|
11
|
+
|
12
|
+
if result["response_code"] == 0
|
13
|
+
res = Hash.new
|
14
|
+
res['hash'] = hash
|
15
|
+
res['scanner'] = '-'
|
16
|
+
res['md5'] = '-'
|
17
|
+
res['sha1'] = '-'
|
18
|
+
res['sha256'] = '-'
|
19
|
+
res['detected'] = '-'
|
20
|
+
res['version'] = '-'
|
21
|
+
res['result'] = '-'
|
22
|
+
res['update'] = '-'
|
23
|
+
res['permalink'] = '-'
|
24
|
+
res['result'] = result["verbose_msg"]
|
25
|
+
|
26
|
+
@results.push res
|
27
|
+
elsif result["response_code"] == 0
|
28
|
+
puts "[!] Invalid API KEY! Please correct this! Check ~/.uirusu"
|
29
|
+
exit
|
30
|
+
else
|
31
|
+
permalink = result["permalink"]
|
32
|
+
date = result["scan_date"]
|
33
|
+
md5 = result["md5"]
|
34
|
+
sha1 = result["sha1"]
|
35
|
+
sha256 = result["sha256"]
|
36
|
+
|
37
|
+
result["scans"].each do |scanner, value|
|
38
|
+
if value != ''
|
39
|
+
res = Hash.new
|
40
|
+
res['hash'] = hash
|
41
|
+
res['md5'] = md5
|
42
|
+
res['sha1'] = sha1
|
43
|
+
res['sha256'] = sha256
|
44
|
+
res['scanner'] = scanner
|
45
|
+
res['detected'] = value["detected"]
|
46
|
+
res['version'] = value["version"]
|
47
|
+
|
48
|
+
if value["result"] == nil
|
49
|
+
res['result'] = "Nothing detected"
|
50
|
+
else
|
51
|
+
res['result'] = value["result"]
|
52
|
+
end
|
53
|
+
|
54
|
+
res['update'] = value['update']
|
55
|
+
res['permalink'] = permalink unless permalink == nil
|
56
|
+
|
57
|
+
@results.push res
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
#if we didn't have any results let create a fake not found
|
63
|
+
if @results.size == 0
|
64
|
+
res = Hash.new
|
65
|
+
res['hash'] = hash
|
66
|
+
res['scanner'] = '-'
|
67
|
+
res['md5'] = '-'
|
68
|
+
res['sha1'] = '-'
|
69
|
+
res['sha256'] = '-'
|
70
|
+
res['permalink'] = '-'
|
71
|
+
res['detected'] = '-'
|
72
|
+
res['version'] = '-'
|
73
|
+
res['result'] = '-'
|
74
|
+
res['update'] = '-'
|
75
|
+
res['result'] = result["verbose_msg"]
|
76
|
+
@results.push res
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
#
|
81
|
+
#
|
82
|
+
def to_stdout
|
83
|
+
result_string = String.new
|
84
|
+
@results.each do |result|
|
85
|
+
result_string << "#{result['hash']}: Scanner: #{result['scanner']} Result: #{result['result']}\n"
|
86
|
+
end
|
87
|
+
|
88
|
+
print result_string
|
89
|
+
end
|
90
|
+
|
91
|
+
#
|
92
|
+
#
|
93
|
+
def to_yaml
|
94
|
+
result_string = String.new
|
95
|
+
@results.each do |result|
|
96
|
+
result_string << "vtresult:\n"
|
97
|
+
result_string << " hash: #{result['hash']}\n"
|
98
|
+
result_string << " md5: #{result['md5']}\n"
|
99
|
+
result_string << " sha1: #{result['sha1']}\n"
|
100
|
+
result_string << " sha256: #{result['sha256']}\n"
|
101
|
+
result_string << " scanner: #{result['scanner']}\n"
|
102
|
+
result_string << " detected: #{result['detected']}\n"
|
103
|
+
result_string << " date: #{result['date']}\n"
|
104
|
+
result_string << " permalink: #{result['permalink']}\n" unless result['permalink'] == nil
|
105
|
+
result_string << " result: #{result['result']}\n\n"
|
106
|
+
end
|
107
|
+
|
108
|
+
print result_string
|
109
|
+
end
|
110
|
+
|
111
|
+
#
|
112
|
+
#
|
113
|
+
def to_xml
|
114
|
+
result_string = String.new
|
115
|
+
@results.each do |result|
|
116
|
+
result_string << "\t<vtresult>\n"
|
117
|
+
result_string << "\t\t<hash>#{result['hash']}</hash>\n"
|
118
|
+
result_string << "\t\t<md5>#{result['md5']}</md5>\n"
|
119
|
+
result_string << "\t\t<sha1>#{result['sha1']}</sha1>\n"
|
120
|
+
result_string << "\t\t<sha256>#{result['sha256']}</sha256>\n"
|
121
|
+
result_string << "\t\t<scanner>#{result['scanner']}</scanner>\n"
|
122
|
+
result_string << "\t\t<detected>#{result['detected']}</detected>\n"
|
123
|
+
result_string << "\t\t<date>#{result['date']}</date>\n"
|
124
|
+
result_string << "\t\t<permalink>#{result['permalink']}</permalink>\n" unless result['permalink'] == nil
|
125
|
+
result_string << "\t\t<result>#{result['result']}</result>\n"
|
126
|
+
result_string << "\t</vtresult>\n"
|
127
|
+
end
|
128
|
+
|
129
|
+
print result_string
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
data/lib/uirusu/vturl.rb
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
module Uirusu
|
2
|
+
#
|
3
|
+
#
|
4
|
+
module VTUrl
|
5
|
+
SCAN_URL = "https://www.virustotal.com/vtapi/v2/url/scan"
|
6
|
+
REPORT_URL = "http://www.virustotal.com/vtapi/v2/url/report"
|
7
|
+
|
8
|
+
# Submits a URL to be scanned by Virustotal.com
|
9
|
+
#
|
10
|
+
# @param api_key Virustotal.com API key
|
11
|
+
# @param resource url to submit
|
12
|
+
#
|
13
|
+
# @return [JSON] Parsed response
|
14
|
+
def self.scan_url(api_key, resource)
|
15
|
+
if api_key == nil
|
16
|
+
raise "Invalid API Key"
|
17
|
+
end
|
18
|
+
|
19
|
+
if resource == nil
|
20
|
+
raise "Invalid resource, must be a valid url"
|
21
|
+
end
|
22
|
+
|
23
|
+
response = RestClient.post SCAN_URL, :apikey => api_key, :url => resource
|
24
|
+
|
25
|
+
case response.code
|
26
|
+
when 429
|
27
|
+
raise "Virustotal limit reached. Try again later."
|
28
|
+
when 403
|
29
|
+
raise "Invalid privileges, please check your API key."
|
30
|
+
when 200
|
31
|
+
JSON.parse(response)
|
32
|
+
else
|
33
|
+
raise "Unknown Server error."
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Searchs reports by URL from Virustotal.com
|
38
|
+
#
|
39
|
+
# @param api_key Virustotal.com API key
|
40
|
+
# @param resource url to search
|
41
|
+
#
|
42
|
+
# @return [JSON] Parsed response
|
43
|
+
def self.query_report(api_key, resource)
|
44
|
+
if api_key == nil
|
45
|
+
raise "Invalid API Key"
|
46
|
+
end
|
47
|
+
|
48
|
+
if resource == nil
|
49
|
+
raise "Invalid resource, must be a valid url"
|
50
|
+
end
|
51
|
+
|
52
|
+
response = RestClient.post REPORT_URL, :apikey => api_key, :resource => resource
|
53
|
+
|
54
|
+
case response.code
|
55
|
+
when 429
|
56
|
+
raise "Virustotal limit reached. Try again later."
|
57
|
+
when 403
|
58
|
+
raise "Invalid privileges, please check your API key."
|
59
|
+
when 200
|
60
|
+
JSON.parse(response)
|
61
|
+
else
|
62
|
+
raise "Unknown Server error."
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: uirusu
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-02
|
12
|
+
date: 2012-03-02 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: json
|
16
|
-
requirement: &
|
16
|
+
requirement: &70176306777160 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: 1.5.1
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70176306777160
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: rest-client
|
27
|
-
requirement: &
|
27
|
+
requirement: &70176306776280 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,7 +32,7 @@ dependencies:
|
|
32
32
|
version: 1.6.1
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70176306776280
|
36
36
|
description: uirusu is library for interacting with Virustotal.org
|
37
37
|
email: jacob.hammack@hammackj.com
|
38
38
|
executables:
|
@@ -49,10 +49,14 @@ files:
|
|
49
49
|
- Rakefile
|
50
50
|
- README.markdown
|
51
51
|
- TODO.markdown
|
52
|
+
- lib/uirusu/cli/application.rb
|
53
|
+
- lib/uirusu/vtcomment.rb
|
54
|
+
- lib/uirusu/vtfile.rb
|
55
|
+
- lib/uirusu/vtresult.rb
|
56
|
+
- lib/uirusu/vturl.rb
|
52
57
|
- lib/uirusu.rb
|
53
58
|
- uirusu.gemspec
|
54
|
-
-
|
55
|
-
YmluL3VpcnVzdQ==
|
59
|
+
- bin/uirusu
|
56
60
|
homepage: http://github.com/hammackj/uirusu/
|
57
61
|
licenses:
|
58
62
|
- BSD
|
@@ -74,7 +78,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
74
78
|
version: 1.8.16
|
75
79
|
requirements: []
|
76
80
|
rubyforge_project:
|
77
|
-
rubygems_version: 1.8.
|
81
|
+
rubygems_version: 1.8.6
|
78
82
|
signing_key:
|
79
83
|
specification_version: 3
|
80
84
|
summary: uirusu
|