uirusu 0.0.0 → 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|