shadowserver 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +22 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +47 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/bin/shadowserver_asn +63 -0
- data/bin/shadowserver_malware +23 -0
- data/bin/shadowserver_whitelist +21 -0
- data/lib/shadowserver.rb +3 -0
- data/lib/shadowserver/asn.rb +49 -0
- data/lib/shadowserver/malware.rb +68 -0
- data/lib/shadowserver/whitelist.rb +47 -0
- data/test/helper.rb +18 -0
- data/test/notepad.exe +0 -0
- data/test/test_shadowserver.rb +54 -0
- metadata +176 -0
data/.document
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
# Add dependencies required to use your gem here.
|
3
|
+
gem "json", ">= 1.4.3"
|
4
|
+
|
5
|
+
# Add dependencies to develop your gem here.
|
6
|
+
# Include everything needed to run rake, tests, features, etc.
|
7
|
+
group :development do
|
8
|
+
gem "shoulda", ">= 0"
|
9
|
+
gem "bundler", "~> 1.0.0"
|
10
|
+
gem "jeweler", "~> 1.5.2"
|
11
|
+
gem "rcov", ">= 0"
|
12
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
git (1.2.5)
|
5
|
+
jeweler (1.5.2)
|
6
|
+
bundler (~> 1.0.0)
|
7
|
+
git (>= 1.2.5)
|
8
|
+
rake
|
9
|
+
json (1.5.1)
|
10
|
+
rake (0.8.7)
|
11
|
+
rcov (0.9.9)
|
12
|
+
shoulda (2.11.3)
|
13
|
+
|
14
|
+
PLATFORMS
|
15
|
+
ruby
|
16
|
+
|
17
|
+
DEPENDENCIES
|
18
|
+
bundler (~> 1.0.0)
|
19
|
+
jeweler (~> 1.5.2)
|
20
|
+
json (>= 1.4.3)
|
21
|
+
rcov
|
22
|
+
shoulda
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Chris Lee
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
= shadowserver
|
2
|
+
|
3
|
+
The Shadowserver Foundation is an all volunteer watchdog group of security professionals that gather, track, and report on malware, botnet activity, and electronic fraud. It is the mission of the Shadowserver Foundation to improve the security of the Internet by raising awareness of the presence of compromised servers, malicious attackers, and the spread of malware.
|
4
|
+
|
5
|
+
This rubygem aueries various Shadowserver services for ASN information, malware hash lookups, and whitelist hash lookups
|
6
|
+
|
7
|
+
== Usage
|
8
|
+
|
9
|
+
=== Whitelist
|
10
|
+
w = Shadowserver::Whitelist.by_hash("0E53C14A3E48D94FF596A2824307B492")
|
11
|
+
{"source_version"=>"$version", "language"=>"English", "os_name"=>"Windows NT", "mfg_name"=>"Corel Corporation", "filesize"=>"2226", "os_version"=>"Generic", "product_name"=>"Gallery", "filename"=>"00br2026.gif", "crc32"=>"AA6A7B16", "application_type"=>"Graphic/Drawing", "source"=>"NIST", "os_mfg"=>"Microsoft", "product_version"=>"750,000"}
|
12
|
+
|
13
|
+
w = Shadowserver::Whitelist.by_filename("test/notepad.exe")
|
14
|
+
{"source_version"=>"$version", "language"=>"English", "os_name"=>"Unknown", "mfg_name"=>"Sony", "filesize"=>"66048", "os_version"=>"Unknown", "product_name"=>"VAIO Computer Quick Start", "filename"=>"NOTEPAD.EXE", "crc32"=>"0BE7841C", "application_type"=>"System Software,System restoration", "source"=>"NIST", "os_mfg"=>"Unknown", "product_version"=>"Version G186.0"}
|
15
|
+
|
16
|
+
w = Shadowserver::Whitelist.by_string(File.new("test/notepad.exe").read)
|
17
|
+
{"source_version"=>"$version", "language"=>"English", "os_name"=>"Unknown", "mfg_name"=>"Sony", "filesize"=>"66048", "os_version"=>"Unknown", "product_name"=>"VAIO Computer Quick Start", "filename"=>"NOTEPAD.EXE", "crc32"=>"0BE7841C", "application_type"=>"System Software,System restoration", "source"=>"NIST", "os_mfg"=>"Unknown", "product_version"=>"Version G186.0"}
|
18
|
+
|
19
|
+
=== Malware Query
|
20
|
+
mr = Shadowserver::Malware.query("aca4aad254280d25e74c82d440b76f79")
|
21
|
+
{"first_seen"=>"2010-06-15 03:09:41", "filetype"=>"exe", "avresults"=>{"TrendMicro"=>"TROJ_DLOADR.SMM", "AntiVir"=>"WORM/VB.NVA", "VirusBuster"=>"Worm.VB.FMYJ", "QuickHeal"=>"Worm.VB.at", "Clam"=>"Trojan.Downloader-50691", "VBA32"=>"Trojan.VBO.011858", "Sophos"=>"Troj/DwnLdr-HQY", "NOD32"=>"Win32/AutoRun.VB.JP", "Kaspersky"=>"Trojan.Win32.Cosmu.nyl", "Panda"=>"W32/OverDoom.A", "Vexira"=>"Trojan.DL.VB.EEDT", "G-Data"=>"Trojan.Generic.2609117", "Ikarus"=>"Trojan-Downloader.Win32.VB", "Norman"=>"Suspicious_Gen2.SKLJ", "McAfee"=>"Generic", "AVG7"=>"Downloader.Generic9.URM", "F-Secure"=>"Worm:W32/Revois.gen!A", "F-Prot6"=>"W32/Worm.BAOX", "DrWeb"=>"Win32.HLLW.Autoruner.6014", "Avast-Commercial"=>"Win32:Zbot-LRA"}, "ssdeep"=>"12288:gOqOB0v2eZJys73dOvXDpNjNe8NuMpX4aBaa48L/93zKnP6ppgg2HFZlxVPbZX:sOA2eZJ8NI8Nah8L/4PqmTVPlX", "sha1"=>"6fe80e56ad4de610304bab1675ce84d16ab6988e", "last_seen"=>"2010-06-15 03:09:41", "md5"=>"aca4aad254280d25e74c82d440b76f79"}
|
22
|
+
|
23
|
+
=== ASN Query
|
24
|
+
a = Shadowserver::ASN.origin("4.2.2.5")
|
25
|
+
{"cc"=>"US", "domain"=>"LEVEL3.NET", "isp"=>"LEVEL 3 COMMUNICATIONS INC", "asn"=>3356, "asname"=>"LEVEL3", "cidr"=>"4.0.0.0/9"}
|
26
|
+
|
27
|
+
a = Shadowserver::ASN.peer("4.2.2.5")
|
28
|
+
{"cc"=>"US", "prefix"=>"4.0.0.0/9", "domain"=>"LEVEL3.NET", "isp"=>"LEVEL 3 COMMUNICATIONS INC", "asn"=>3356, "asname"=>"LEVEL3", "peers"=>[701, 1239]}
|
29
|
+
|
30
|
+
a = Shadowserver::ASN.prefix(2637)
|
31
|
+
["128.61.0.0/19", "128.61.32.0/19", "128.61.64.0/18", "128.61.128.0/17", "130.207.0.0/16", "143.215.0.0/16", "204.152.10.0/23"]
|
32
|
+
|
33
|
+
== Contributing to shadowserver
|
34
|
+
|
35
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
36
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
37
|
+
* Fork the project
|
38
|
+
* Start a feature/bugfix branch
|
39
|
+
* Commit and push until you are happy with your contribution
|
40
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
41
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
42
|
+
|
43
|
+
== Copyright
|
44
|
+
|
45
|
+
Copyright (c) 2011 Chris Lee. See LICENSE.txt for
|
46
|
+
further details.
|
47
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
require 'rake'
|
11
|
+
|
12
|
+
require 'jeweler'
|
13
|
+
Jeweler::Tasks.new do |gem|
|
14
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
15
|
+
gem.name = "shadowserver"
|
16
|
+
gem.homepage = "http://github.com/chrislee35/shadowserver"
|
17
|
+
gem.license = "MIT"
|
18
|
+
gem.summary = %Q{Queries various Shadowserver services for ASN information, malware hash lookups, and whitelist hash lookups}
|
19
|
+
gem.description = %Q{The Shadowserver Foundation is an all volunteer watchdog group of security professionals that gather, track, and report on malware, botnet activity, and electronic fraud. It is the mission of the Shadowserver Foundation to improve the security of the Internet by raising awareness of the presence of compromised servers, malicious attackers, and the spread of malware.}
|
20
|
+
gem.email = "rubygems@chrislee.dhs.org"
|
21
|
+
gem.authors = ["Chris Lee"]
|
22
|
+
gem.executables = ["shadowserver_asn", "shadowserver_whitelist", "shadowserver_malware"]
|
23
|
+
# Include your dependencies below. Runtime dependencies are required when using your gem,
|
24
|
+
# and development dependencies are only needed for development (ie running rake tasks, tests, etc)
|
25
|
+
gem.add_runtime_dependency "json", ">= 1.4.3"
|
26
|
+
end
|
27
|
+
Jeweler::RubygemsDotOrgTasks.new
|
28
|
+
|
29
|
+
require 'rake/testtask'
|
30
|
+
Rake::TestTask.new(:test) do |test|
|
31
|
+
test.libs << 'lib' << 'test'
|
32
|
+
test.pattern = 'test/**/test_*.rb'
|
33
|
+
test.verbose = true
|
34
|
+
end
|
35
|
+
|
36
|
+
require 'rcov/rcovtask'
|
37
|
+
Rcov::RcovTask.new do |test|
|
38
|
+
test.libs << 'test'
|
39
|
+
test.pattern = 'test/**/test_*.rb'
|
40
|
+
test.verbose = true
|
41
|
+
end
|
42
|
+
|
43
|
+
task :default => :test
|
44
|
+
|
45
|
+
require 'rake/rdoctask'
|
46
|
+
Rake::RDocTask.new do |rdoc|
|
47
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
48
|
+
|
49
|
+
rdoc.rdoc_dir = 'rdoc'
|
50
|
+
rdoc.title = "shadowserver #{version}"
|
51
|
+
rdoc.rdoc_files.include('README*')
|
52
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
53
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.0
|
@@ -0,0 +1,63 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'shadowserver'
|
3
|
+
require 'pp'
|
4
|
+
require 'getoptlong'
|
5
|
+
|
6
|
+
def lookup(item)
|
7
|
+
if item =~ /^AS(\d+)$/i
|
8
|
+
Shadowserver::ASN.prefix($1.to_i)
|
9
|
+
elsif item =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/
|
10
|
+
case $mode
|
11
|
+
when 'origin'
|
12
|
+
Shadowserver::ASN.origin(item)
|
13
|
+
when 'peer'
|
14
|
+
Shadowserver::ASN.peer(item)
|
15
|
+
else
|
16
|
+
"Unknown argument type: #{item}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def usage
|
22
|
+
puts "Usage: #{$0} [-h|-p|-o] [<ip or asn>] [<ip or asn> ...]"
|
23
|
+
puts "-h usage information"
|
24
|
+
puts "-p display peering information"
|
25
|
+
puts "-o display origin information"
|
26
|
+
puts
|
27
|
+
puts "If no arguments are provided, then the tool reads from standard input."
|
28
|
+
puts "If an ASN is provided, then the prefixes are listed"
|
29
|
+
puts "Examples"
|
30
|
+
puts " #{$0} -p 4.2.2.5"
|
31
|
+
puts " #{$0} -o 4.2.2.5"
|
32
|
+
puts " #{$0} AS2637"
|
33
|
+
exit
|
34
|
+
end
|
35
|
+
|
36
|
+
$mode = 'origin'
|
37
|
+
opts = GetoptLong.new(
|
38
|
+
[ '--help', '-h', GetoptLong::NO_ARGUMENT ],
|
39
|
+
[ '--origin', '-o', GetoptLong::NO_ARGUMENT ],
|
40
|
+
[ '--peer', '-p', GetoptLong::NO_ARGUMENT ]
|
41
|
+
)
|
42
|
+
opts.each do |opt, arg|
|
43
|
+
case opt
|
44
|
+
when '--help'
|
45
|
+
usage
|
46
|
+
when '--origin'
|
47
|
+
$mode = 'origin'
|
48
|
+
when '--peer'
|
49
|
+
$mode = 'peer'
|
50
|
+
else
|
51
|
+
usage
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
if ARGV.length > 0
|
56
|
+
ARGV.each do |item|
|
57
|
+
pp lookup(item)
|
58
|
+
end
|
59
|
+
else
|
60
|
+
$stdin.each_line do |item|
|
61
|
+
pp lookup(item.chomp)
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'shadowserver'
|
3
|
+
require 'digest/md5'
|
4
|
+
require 'pp'
|
5
|
+
|
6
|
+
def usage
|
7
|
+
puts "Usage: #{$0} (<hash>|<filename>) [<hash>|<filename> ...]"
|
8
|
+
puts "this tool will query the malware list for each hash or filename provided at the commandline"
|
9
|
+
exit
|
10
|
+
end
|
11
|
+
|
12
|
+
usage unless ARGV.length > 0
|
13
|
+
|
14
|
+
ARGV.each do |item|
|
15
|
+
if item =~ /^[a-f0-9]{32}([a-f0-9]{8})?$/i
|
16
|
+
pp Shadowserver::Malware.query(item)
|
17
|
+
elsif File.exists?(item)
|
18
|
+
hash = Digest::MD5.hexdigest(File.open(item).read)
|
19
|
+
pp Shadowserver::Malware.query(hash)
|
20
|
+
else
|
21
|
+
puts "#{item} isn't a hash or a filename (that I can find)"
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'shadowserver'
|
3
|
+
require 'pp'
|
4
|
+
|
5
|
+
def usage
|
6
|
+
puts "Usage: #{$0} (<hash>|<filename>) [<hash>|<filename> ...]"
|
7
|
+
puts "this tool will query the whitelist for each hash or filename provided at the commandline"
|
8
|
+
exit
|
9
|
+
end
|
10
|
+
|
11
|
+
usage unless ARGV.length > 0
|
12
|
+
|
13
|
+
ARGV.each do |item|
|
14
|
+
if item =~ /^[a-f0-9]{32}([a-f0-9]{8})?$/i
|
15
|
+
pp Shadowserver::Whitelist.by_hash(item)
|
16
|
+
elsif File.exists?(item)
|
17
|
+
pp Shadowserver::Whitelist.by_filename(item)
|
18
|
+
else
|
19
|
+
puts "#{item} isn't a hash or a filename (that I can find)"
|
20
|
+
end
|
21
|
+
end
|
data/lib/shadowserver.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'socket'
|
2
|
+
|
3
|
+
module Shadowserver
|
4
|
+
class ASN
|
5
|
+
@@server = 'asn.shadowserver.org'
|
6
|
+
@@port = 43
|
7
|
+
def ASN::origin(ip)
|
8
|
+
t = TCPSocket.new(@@server,@@port)
|
9
|
+
t.write("origin #{ip}\n")
|
10
|
+
asn, cidr, asname, cc, domain, isp = t.read.chomp.split(/\|/).map{|x| x.strip}
|
11
|
+
asn = asn.to_i
|
12
|
+
t.close
|
13
|
+
{
|
14
|
+
"asn" => asn,
|
15
|
+
"cidr" => cidr,
|
16
|
+
"asname" => asname,
|
17
|
+
"cc" => cc,
|
18
|
+
"domain" => domain,
|
19
|
+
"isp" => isp
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
def ASN::peer(ip)
|
24
|
+
t = TCPSocket.new(@@server,@@port)
|
25
|
+
t.write("peer #{ip}\n")
|
26
|
+
peers, asn, prefix, asname, cc, domain, isp = t.read.chomp.split(/\|/).map{|x| x.strip}
|
27
|
+
asn = asn.to_i
|
28
|
+
peers = peers.split(/ /).map{|x| x.to_i}
|
29
|
+
t.close
|
30
|
+
{
|
31
|
+
"peers" => peers,
|
32
|
+
"asn" => asn,
|
33
|
+
"prefix" => prefix,
|
34
|
+
"asname" => asname,
|
35
|
+
"cc" => cc,
|
36
|
+
"domain" => domain,
|
37
|
+
"isp" => isp
|
38
|
+
}
|
39
|
+
end
|
40
|
+
|
41
|
+
def ASN::prefix(asn)
|
42
|
+
t = TCPSocket.new(@@server,@@port)
|
43
|
+
t.write("prefix #{asn}\n")
|
44
|
+
prefixes = t.read.chomp.split(/\n/)
|
45
|
+
t.close
|
46
|
+
prefixes
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'net/https'
|
3
|
+
require 'json'
|
4
|
+
require 'uri'
|
5
|
+
|
6
|
+
module Shadowserver
|
7
|
+
class Malware
|
8
|
+
def Malware::query(hash)
|
9
|
+
doc = _get("http://innocuous.shadowserver.org/api/?query=#{hash}")
|
10
|
+
return nil if doc =~ /^\!/
|
11
|
+
lines = doc.split(/\n/)
|
12
|
+
md5, sha1, first_seen, last_seen, filetype, ssdeep = lines[0].gsub(/\"/,'').split(/,/)
|
13
|
+
avresults = JSON.parse(lines[1])
|
14
|
+
{
|
15
|
+
"md5" => md5,
|
16
|
+
"sha1" => sha1,
|
17
|
+
"first_seen" => first_seen,
|
18
|
+
"last_seen" => last_seen,
|
19
|
+
"filetype" => filetype,
|
20
|
+
"ssdeep" => ssdeep,
|
21
|
+
"avresults" => avresults
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
# untested
|
26
|
+
def Malware::download(hash,filename=nil)
|
27
|
+
doc = _get("https://innocuous.shadowserver.org/api/?download=#{hash}")
|
28
|
+
raise doc.chomp if doc =~ /\! The Shadowserver Foundation: RESTRICTED ACCESS/
|
29
|
+
return nil if doc =~ /^\!/
|
30
|
+
if filename
|
31
|
+
File.open(filename,"w") do |f|
|
32
|
+
f.write(doc)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
doc
|
36
|
+
end
|
37
|
+
|
38
|
+
# untested
|
39
|
+
def Malware::avresult(hash)
|
40
|
+
doc = _get("http://innocuous.shadowserver.org/api/?avresult=#{hash}")
|
41
|
+
raise doc.chomp if doc =~ /\! The Shadowserver Foundation: RESTRICTED ACCESS/
|
42
|
+
return nil if doc =~ /^\!/
|
43
|
+
JSON.parse(doc)
|
44
|
+
end
|
45
|
+
|
46
|
+
# untested
|
47
|
+
def Malware::ssdeep(hash)
|
48
|
+
doc = _get("http://innocuous.shadowserver.org/api/?ssdeep=#{hash}")
|
49
|
+
raise doc.chomp if doc =~ /\! The Shadowserver Foundation: RESTRICTED ACCESS/
|
50
|
+
return nil if doc =~ /^\!/
|
51
|
+
JSON.parse(doc)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def Malware::_get(url)
|
56
|
+
url = URI.parse(url)
|
57
|
+
request = Net::HTTP::Get.new(url.path+"?"+url.query)
|
58
|
+
request.add_field("User-Agent", "Ruby/#{RUBY_VERSION} shadowserver rubygem (https://github.com/chrislee35/shadowserver)")
|
59
|
+
http = Net::HTTP.new(url.host, url.port)
|
60
|
+
if url.scheme == 'https'
|
61
|
+
http.use_ssl = true
|
62
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
63
|
+
http.verify_depth = 5
|
64
|
+
end
|
65
|
+
resp = http.request(request)
|
66
|
+
resp.body
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'digest/sha1'
|
3
|
+
require 'uri'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
module Shadowserver
|
7
|
+
class Whitelist
|
8
|
+
@@baseurl = "http://bin-test.shadowserver.org/api"
|
9
|
+
def Whitelist::by_hash(hash)
|
10
|
+
url = @@baseurl
|
11
|
+
if hash.length == 32
|
12
|
+
url += "?md5=#{hash.upcase}"
|
13
|
+
elsif hash.length == 40
|
14
|
+
url += "?sha1=#{hash.upcase}"
|
15
|
+
else
|
16
|
+
raise "The hash must be either 32 or 40 characters long"
|
17
|
+
end
|
18
|
+
url = URI.parse(url)
|
19
|
+
request = Net::HTTP::Get.new(url.path+"?"+url.query)
|
20
|
+
request.add_field("User-Agent", "Ruby/#{RUBY_VERSION} shadowserver rubygem (https://github.com/chrislee35/shadowserver)")
|
21
|
+
http = Net::HTTP.new(url.host, url.port)
|
22
|
+
if url.scheme == 'https'
|
23
|
+
http.use_ssl = true
|
24
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
25
|
+
http.verify_depth = 5
|
26
|
+
end
|
27
|
+
resp = http.request(request)
|
28
|
+
if resp.body =~ /^[0-9A-F]{32,40} (.+)/
|
29
|
+
JSON.parse($1)
|
30
|
+
else
|
31
|
+
nil
|
32
|
+
end
|
33
|
+
end
|
34
|
+
def Whitelist::by_filename(filename)
|
35
|
+
if File.exists?(filename)
|
36
|
+
hash = Digest::SHA1.hexdigest(File.open(filename).read)
|
37
|
+
else
|
38
|
+
raise "Whitelist::by_filename: Could not find file, #{filename}"
|
39
|
+
end
|
40
|
+
Whitelist::by_hash(hash)
|
41
|
+
end
|
42
|
+
def Whitelist::by_string(string)
|
43
|
+
hash = Digest::SHA1.hexdigest(string)
|
44
|
+
Whitelist::by_hash(hash)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
require 'test/unit'
|
11
|
+
require 'shoulda'
|
12
|
+
|
13
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
14
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
15
|
+
require 'shadowserver'
|
16
|
+
|
17
|
+
class Test::Unit::TestCase
|
18
|
+
end
|
data/test/notepad.exe
ADDED
Binary file
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestShadowserver < Test::Unit::TestCase
|
4
|
+
should "return whitelist results for 0E53C14A3E48D94FF596A2824307B492" do
|
5
|
+
w = Shadowserver::Whitelist.by_hash("0E53C14A3E48D94FF596A2824307B492")
|
6
|
+
assert_not_nil(w)
|
7
|
+
assert_equal({"source_version"=>"$version", "language"=>"English", "os_name"=>"Windows NT", "mfg_name"=>"Corel Corporation", "filesize"=>"2226", "os_version"=>"Generic", "product_name"=>"Gallery", "filename"=>"00br2026.gif", "crc32"=>"AA6A7B16", "application_type"=>"Graphic/Drawing", "source"=>"NIST", "os_mfg"=>"Microsoft", "product_version"=>"750,000"}, w)
|
8
|
+
end
|
9
|
+
|
10
|
+
should "return nil for whitelist query for 0E53C14A3E48D94FF596A2824307B493" do
|
11
|
+
w = Shadowserver::Whitelist.by_hash("0E53C14A3E48D94FF596A2824307B493")
|
12
|
+
assert_nil(w)
|
13
|
+
end
|
14
|
+
|
15
|
+
should "return whitelist results for notepad.exe" do
|
16
|
+
w = Shadowserver::Whitelist.by_filename("test/notepad.exe")
|
17
|
+
assert_not_nil(w)
|
18
|
+
assert_equal({"source_version"=>"$version", "language"=>"English", "os_name"=>"Unknown", "mfg_name"=>"Sony", "filesize"=>"66048", "os_version"=>"Unknown", "product_name"=>"VAIO Computer Quick Start", "filename"=>"NOTEPAD.EXE", "crc32"=>"0BE7841C", "application_type"=>"System Software,System restoration", "source"=>"NIST", "os_mfg"=>"Unknown", "product_version"=>"Version G186.0"}, w)
|
19
|
+
end
|
20
|
+
|
21
|
+
should "return whitelist results for the string version of notepad.exe" do
|
22
|
+
w = Shadowserver::Whitelist.by_string(File.new("test/notepad.exe").read)
|
23
|
+
assert_not_nil(w)
|
24
|
+
assert_equal({"source_version"=>"$version", "language"=>"English", "os_name"=>"Unknown", "mfg_name"=>"Sony", "filesize"=>"66048", "os_version"=>"Unknown", "product_name"=>"VAIO Computer Quick Start", "filename"=>"NOTEPAD.EXE", "crc32"=>"0BE7841C", "application_type"=>"System Software,System restoration", "source"=>"NIST", "os_mfg"=>"Unknown", "product_version"=>"Version G186.0"}, w)
|
25
|
+
end
|
26
|
+
|
27
|
+
should "return malware results for aca4aad254280d25e74c82d440b76f79" do
|
28
|
+
mr = Shadowserver::Malware.query("aca4aad254280d25e74c82d440b76f79")
|
29
|
+
assert_equal({"first_seen"=>"2010-06-15 03:09:41", "filetype"=>"exe", "avresults"=>{"TrendMicro"=>"TROJ_DLOADR.SMM", "AntiVir"=>"WORM/VB.NVA", "VirusBuster"=>"Worm.VB.FMYJ", "QuickHeal"=>"Worm.VB.at", "Clam"=>"Trojan.Downloader-50691", "VBA32"=>"Trojan.VBO.011858", "Sophos"=>"Troj/DwnLdr-HQY", "NOD32"=>"Win32/AutoRun.VB.JP", "Kaspersky"=>"Trojan.Win32.Cosmu.nyl", "Panda"=>"W32/OverDoom.A", "Vexira"=>"Trojan.DL.VB.EEDT", "G-Data"=>"Trojan.Generic.2609117", "Ikarus"=>"Trojan-Downloader.Win32.VB", "Norman"=>"Suspicious_Gen2.SKLJ", "McAfee"=>"Generic", "AVG7"=>"Downloader.Generic9.URM", "F-Secure"=>"Worm:W32/Revois.gen!A", "F-Prot6"=>"W32/Worm.BAOX", "DrWeb"=>"Win32.HLLW.Autoruner.6014", "Avast-Commercial"=>"Win32:Zbot-LRA"}, "ssdeep"=>"12288:gOqOB0v2eZJys73dOvXDpNjNe8NuMpX4aBaa48L/93zKnP6ppgg2HFZlxVPbZX:sOA2eZJ8NI8Nah8L/4PqmTVPlX", "sha1"=>"6fe80e56ad4de610304bab1675ce84d16ab6988e", "last_seen"=>"2010-06-15 03:09:41", "md5"=>"aca4aad254280d25e74c82d440b76f79"}, mr)
|
30
|
+
end
|
31
|
+
|
32
|
+
should "return nil for malware query for 0E53C14A3E48D94FF596A2824307B492" do
|
33
|
+
mr = Shadowserver::Malware.query("0E53C14A3E48D94FF596A2824307B492")
|
34
|
+
assert_nil(mr)
|
35
|
+
end
|
36
|
+
|
37
|
+
should "return origin for 4.2.2.5" do
|
38
|
+
a = Shadowserver::ASN.origin("4.2.2.5")
|
39
|
+
assert_not_nil(a)
|
40
|
+
assert_equal({"cc"=>"US", "domain"=>"LEVEL3.NET", "isp"=>"LEVEL 3 COMMUNICATIONS INC", "asn"=>3356, "asname"=>"LEVEL3", "cidr"=>"4.0.0.0/9"}, a)
|
41
|
+
end
|
42
|
+
|
43
|
+
should "return peer for 4.2.2.5" do
|
44
|
+
a = Shadowserver::ASN.peer("4.2.2.5")
|
45
|
+
assert_not_nil(a)
|
46
|
+
assert_equal({"cc"=>"US", "prefix"=>"4.0.0.0/9", "domain"=>"LEVEL3.NET", "isp"=>"LEVEL 3 COMMUNICATIONS INC", "asn"=>3356, "asname"=>"LEVEL3", "peers"=>[701, 1239]}, a)
|
47
|
+
end
|
48
|
+
|
49
|
+
should "retun prefixes for AS2637" do
|
50
|
+
a = Shadowserver::ASN.prefix(2637)
|
51
|
+
assert_not_nil(a)
|
52
|
+
assert_equal(["128.61.0.0/19", "128.61.32.0/19", "128.61.64.0/18", "128.61.128.0/17", "130.207.0.0/16", "143.215.0.0/16", "204.152.10.0/23"], a)
|
53
|
+
end
|
54
|
+
end
|
metadata
ADDED
@@ -0,0 +1,176 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: shadowserver
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 31
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 0
|
10
|
+
version: 0.0.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Chris Lee
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-05-29 00:00:00 Z
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
version_requirements: &id001 !ruby/object:Gem::Requirement
|
22
|
+
none: false
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
hash: 1
|
27
|
+
segments:
|
28
|
+
- 1
|
29
|
+
- 4
|
30
|
+
- 3
|
31
|
+
version: 1.4.3
|
32
|
+
requirement: *id001
|
33
|
+
prerelease: false
|
34
|
+
name: json
|
35
|
+
type: :runtime
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
version_requirements: &id002 !ruby/object:Gem::Requirement
|
38
|
+
none: false
|
39
|
+
requirements:
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
hash: 3
|
43
|
+
segments:
|
44
|
+
- 0
|
45
|
+
version: "0"
|
46
|
+
requirement: *id002
|
47
|
+
prerelease: false
|
48
|
+
name: shoulda
|
49
|
+
type: :development
|
50
|
+
- !ruby/object:Gem::Dependency
|
51
|
+
version_requirements: &id003 !ruby/object:Gem::Requirement
|
52
|
+
none: false
|
53
|
+
requirements:
|
54
|
+
- - ~>
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
hash: 23
|
57
|
+
segments:
|
58
|
+
- 1
|
59
|
+
- 0
|
60
|
+
- 0
|
61
|
+
version: 1.0.0
|
62
|
+
requirement: *id003
|
63
|
+
prerelease: false
|
64
|
+
name: bundler
|
65
|
+
type: :development
|
66
|
+
- !ruby/object:Gem::Dependency
|
67
|
+
version_requirements: &id004 !ruby/object:Gem::Requirement
|
68
|
+
none: false
|
69
|
+
requirements:
|
70
|
+
- - ~>
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
hash: 7
|
73
|
+
segments:
|
74
|
+
- 1
|
75
|
+
- 5
|
76
|
+
- 2
|
77
|
+
version: 1.5.2
|
78
|
+
requirement: *id004
|
79
|
+
prerelease: false
|
80
|
+
name: jeweler
|
81
|
+
type: :development
|
82
|
+
- !ruby/object:Gem::Dependency
|
83
|
+
version_requirements: &id005 !ruby/object:Gem::Requirement
|
84
|
+
none: false
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
hash: 3
|
89
|
+
segments:
|
90
|
+
- 0
|
91
|
+
version: "0"
|
92
|
+
requirement: *id005
|
93
|
+
prerelease: false
|
94
|
+
name: rcov
|
95
|
+
type: :development
|
96
|
+
- !ruby/object:Gem::Dependency
|
97
|
+
version_requirements: &id006 !ruby/object:Gem::Requirement
|
98
|
+
none: false
|
99
|
+
requirements:
|
100
|
+
- - ">="
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
hash: 1
|
103
|
+
segments:
|
104
|
+
- 1
|
105
|
+
- 4
|
106
|
+
- 3
|
107
|
+
version: 1.4.3
|
108
|
+
requirement: *id006
|
109
|
+
prerelease: false
|
110
|
+
name: json
|
111
|
+
type: :runtime
|
112
|
+
description: The Shadowserver Foundation is an all volunteer watchdog group of security professionals that gather, track, and report on malware, botnet activity, and electronic fraud. It is the mission of the Shadowserver Foundation to improve the security of the Internet by raising awareness of the presence of compromised servers, malicious attackers, and the spread of malware.
|
113
|
+
email: rubygems@chrislee.dhs.org
|
114
|
+
executables:
|
115
|
+
- shadowserver_asn
|
116
|
+
- shadowserver_whitelist
|
117
|
+
- shadowserver_malware
|
118
|
+
extensions: []
|
119
|
+
|
120
|
+
extra_rdoc_files:
|
121
|
+
- LICENSE.txt
|
122
|
+
- README.rdoc
|
123
|
+
files:
|
124
|
+
- .document
|
125
|
+
- Gemfile
|
126
|
+
- Gemfile.lock
|
127
|
+
- LICENSE.txt
|
128
|
+
- README.rdoc
|
129
|
+
- Rakefile
|
130
|
+
- VERSION
|
131
|
+
- bin/shadowserver_asn
|
132
|
+
- bin/shadowserver_malware
|
133
|
+
- bin/shadowserver_whitelist
|
134
|
+
- lib/shadowserver.rb
|
135
|
+
- lib/shadowserver/asn.rb
|
136
|
+
- lib/shadowserver/malware.rb
|
137
|
+
- lib/shadowserver/whitelist.rb
|
138
|
+
- test/helper.rb
|
139
|
+
- test/notepad.exe
|
140
|
+
- test/test_shadowserver.rb
|
141
|
+
homepage: http://github.com/chrislee35/shadowserver
|
142
|
+
licenses:
|
143
|
+
- MIT
|
144
|
+
post_install_message:
|
145
|
+
rdoc_options: []
|
146
|
+
|
147
|
+
require_paths:
|
148
|
+
- lib
|
149
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
150
|
+
none: false
|
151
|
+
requirements:
|
152
|
+
- - ">="
|
153
|
+
- !ruby/object:Gem::Version
|
154
|
+
hash: 3
|
155
|
+
segments:
|
156
|
+
- 0
|
157
|
+
version: "0"
|
158
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
159
|
+
none: false
|
160
|
+
requirements:
|
161
|
+
- - ">="
|
162
|
+
- !ruby/object:Gem::Version
|
163
|
+
hash: 3
|
164
|
+
segments:
|
165
|
+
- 0
|
166
|
+
version: "0"
|
167
|
+
requirements: []
|
168
|
+
|
169
|
+
rubyforge_project:
|
170
|
+
rubygems_version: 1.7.2
|
171
|
+
signing_key:
|
172
|
+
specification_version: 3
|
173
|
+
summary: Queries various Shadowserver services for ASN information, malware hash lookups, and whitelist hash lookups
|
174
|
+
test_files:
|
175
|
+
- test/helper.rb
|
176
|
+
- test/test_shadowserver.rb
|