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.
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: