virus_blacklist 1.0.0 → 1.1.0
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/lib/virus_blacklist.rb +102 -19
- metadata +1 -1
data/lib/virus_blacklist.rb
CHANGED
@@ -1,29 +1,56 @@
|
|
1
1
|
require 'dnsruby'
|
2
2
|
|
3
|
-
# CYMRU publishes the MD5 hashes of known viruses as DNS records, which is perfect for us. In short:
|
4
|
-
# You get 127.0.0.1 back if the file is in their registry and marked as safe.
|
5
|
-
# You get 127.0.0.2 back if the file is in their registry and marked as unsafe.
|
6
|
-
# You get NXDOMAIN if the file isn't in their registry at all.
|
7
|
-
# You may also get no reply if you're being rate limited.
|
8
|
-
# See http://www.team-cymru.org/Services/MHR/ for more info on this service.
|
9
|
-
|
10
3
|
module VirusBlacklist
|
11
4
|
|
5
|
+
# CYMRU publishes the MD5 hashes of known viruses as DNS A records. In short:
|
6
|
+
# You get 127.0.0.1 back if the file is in their registry and marked as safe.
|
7
|
+
# You get 127.0.0.2 back if the file is in their registry and marked as unsafe.
|
8
|
+
# You get NXDOMAIN if the file isn't in their registry at all.
|
9
|
+
# You may also get no reply if you're being rate limited.
|
10
|
+
#
|
11
|
+
# If you ask for TXT records, you can get information on the detection rate,
|
12
|
+
# but we don't use this. The service is free for non-commercial use.
|
13
|
+
# See http://www.team-cymru.org/Services/MHR/ for more info.
|
14
|
+
|
12
15
|
include Dnsruby
|
13
16
|
extend self
|
14
17
|
|
15
18
|
def resolver
|
16
|
-
#
|
17
|
-
#
|
19
|
+
# This is our Dnsruby::Resolver object. You can modify its settings via this. For example,
|
20
|
+
# VirusBlacklist.resolver.query_timeout = 5
|
21
|
+
#
|
22
|
+
# Our default query_timeout is very aggresive: 2 seconds. You might want to wait longer,
|
23
|
+
# depending on the application.
|
24
|
+
|
18
25
|
@resolver ||= Dnsruby::Resolver.new(:query_timeout => 2) # Only waits for 2 seconds
|
19
26
|
end
|
20
27
|
|
21
|
-
|
22
|
-
|
28
|
+
def valid_hash?(hash)
|
29
|
+
# Returns true if argument is a String containing 32 hex digits, false otherwise.
|
30
|
+
return !!hash.match(/\A[a-f0-9]{32}\z/i) # Return a boolean instead of MatchData
|
31
|
+
end
|
23
32
|
|
24
33
|
def scan(md5)
|
25
|
-
|
26
|
-
|
34
|
+
# Checks for a file in their blacklist.
|
35
|
+
#
|
36
|
+
# Example:
|
37
|
+
# >> VirusBlacklist.scan(virus_hash)
|
38
|
+
# => :unsafe
|
39
|
+
#
|
40
|
+
# Arguments:
|
41
|
+
# md5: (String) - String containing an MD5 hash. Must be exactly 32 hexadecimal digits.
|
42
|
+
#
|
43
|
+
# Outputs:
|
44
|
+
# :safe - Hash in registry, not detected as virus.
|
45
|
+
# :unsafe - Hash in registry, known virus
|
46
|
+
# :unknown - Hash not in registry. Most files will be unknown.
|
47
|
+
# :error - We got an unexpected IP back in reply. Could occur due to SiteFinder and
|
48
|
+
# other ISP tools that mask NXDOMAIN responses.
|
49
|
+
#
|
50
|
+
# Raises:
|
51
|
+
# ArgumentError - When the argument is not an MD5 hash.
|
52
|
+
|
53
|
+
unless valid_hash?(md5)
|
27
54
|
raise ArgumentError, "Invalid MD5 value (" + md5 + "). MD5s contain exactly 32 hexadecimal digits."
|
28
55
|
end
|
29
56
|
|
@@ -34,21 +61,77 @@ module VirusBlacklist
|
|
34
61
|
when /\A127\.0\.0\.2\z/
|
35
62
|
return :unsafe
|
36
63
|
else
|
37
|
-
|
64
|
+
# This usually happens due to something like SiteFinder returning its own IP.
|
65
|
+
return :error
|
38
66
|
end
|
67
|
+
|
68
|
+
rescue NXDomain, ResolvTimeout
|
69
|
+
# Hashes not in the DB (i.e. almost everything) will end up as NXDomain unless you have SiteFinder
|
70
|
+
# or some other ISP "feature" feeding you phony results that lead to some page full of ads.
|
71
|
+
# You might also get timeouts due to DNS problems, or if rate limited.
|
72
|
+
return :unknown
|
73
|
+
end
|
39
74
|
|
40
|
-
|
41
|
-
|
42
|
-
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
def probe(md5)
|
79
|
+
# Gives you a string containing a Unix timestamp when the virus was last seen
|
80
|
+
# followed by the overall AV detection rate, e.g. "1277221946 79" or nil, when
|
81
|
+
# there is no data for that hash.
|
82
|
+
#
|
83
|
+
# Example:
|
84
|
+
# >> VirusBlacklist.probe("733a48a9cb49651d72fe824ca91e8d00")
|
85
|
+
# => "1277221946 79"
|
86
|
+
#
|
87
|
+
# Arguments:
|
88
|
+
# md5 (String) - MD5 hash of the file you want information on.
|
89
|
+
#
|
90
|
+
# Outputs:
|
91
|
+
# nil - No data exists for that file.
|
92
|
+
# String - A unix timestamp when the virus was last seen
|
93
|
+
# - then a space and the detection % for that virus.
|
94
|
+
#
|
95
|
+
# Raises:
|
96
|
+
# ArgumentError - When passed a string that is not an MD5 hash.
|
97
|
+
# ResolvTimeout - When the nameserver does not respond in time.
|
98
|
+
|
99
|
+
unless valid_hash?(md5)
|
100
|
+
raise ArgumentError, "Invalid MD5 value (" + md5 + "). MD5s contain exactly 32 hexadecimal digits."
|
101
|
+
end
|
102
|
+
|
103
|
+
begin
|
104
|
+
return resolver.query(md5.downcase + ".malware.hash.cymru.com", Types.TXT).answer.entries[0].data
|
105
|
+
rescue NXDomain
|
106
|
+
return nil
|
43
107
|
end
|
44
108
|
end
|
45
109
|
|
110
|
+
|
46
111
|
def is_ok?(md5)
|
112
|
+
|
113
|
+
# A simple interpreter for scan that considers everything but :unsafe to be ok.
|
114
|
+
#
|
115
|
+
# Example:
|
116
|
+
# >> VirusBlacklist.is_ok?(virus_hash)
|
117
|
+
# => false
|
118
|
+
#
|
119
|
+
# Arguments:
|
120
|
+
# md5: (String) - String containing an MD5 hash. Must be exactly 32 hexadecimal digits.
|
121
|
+
#
|
122
|
+
# Output:
|
123
|
+
# false - if scan says :unsafe
|
124
|
+
# true - if scan says anything else (including :error)
|
125
|
+
#
|
47
126
|
# Unfortunately, we're limited by the fact that this is a blacklist and that there's
|
48
127
|
# no way to whitelist every possible benign file. So we consider it safe if it's
|
49
128
|
# not known to be bad. That doesn't matter much, because it's also trivial to change
|
50
|
-
# any unimportant part of a malicious file, which will change its hash.
|
51
|
-
#
|
129
|
+
# any unimportant part of a malicious file, which will change its hash.
|
130
|
+
#
|
131
|
+
# The :error result is hard to interpret. Tools like SiteFinder create false errors by
|
132
|
+
# masking NXDOMAIN results which would make everything look like a virus. On the other
|
133
|
+
# hand, your DNS cache might be poisoned. If that happens, though, you have bigger
|
134
|
+
# problems.
|
52
135
|
|
53
136
|
if scan(md5) == :unsafe
|
54
137
|
return false
|