virus_blacklist 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (2) hide show
  1. data/lib/virus_blacklist.rb +102 -19
  2. metadata +1 -1
@@ -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
- # Our default query_timeout is pretty aggressive. You might want to wait longer, depending
17
- # on the application.
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
- # For testing, use md5 = "733a48a9cb49651d72fe824ca91e8d00" which should get marked as a known virus.
22
- # That example is directly from their documentation on the service.
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
- unless md5.match(/\A[a-f0-9]{32}\z/i)
26
- # MD5s are exactly 32 hex characters.
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
- return :unknown
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
- rescue Exception => e
41
- puts e.message
42
- return :error
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. So this is poor
51
- # security, but it's the best we can do.
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
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: virus_blacklist
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors: