dap 0.0.4 → 0.0.5

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7353b035e42f0ddd251e0e568ecd58cf22294869
4
- data.tar.gz: fa161592d559ecb61c0ca8e03bb88a93377406f0
3
+ metadata.gz: a5979d47a46ba9175ad7041e9ae9e27281c0bbae
4
+ data.tar.gz: ce96da3ec587d1174890396b7e8cc0ec0d9e8789
5
5
  SHA512:
6
- metadata.gz: 4f96b6c1e7032263ed23214ea4a5cd56a7ae16690f92e59321635cd3d05c74ae4d7f2735612e925e2517e471e7ec19187b64d8a83ecf2eb25bcfbc10f83c4f5b
7
- data.tar.gz: b7f9c5bb9a947f7bec0c38f57bed0059be0b893bbdcc8087f8821db72aa1869069cf06eb999e72136b768fbadcff3ab3733237c8cea5979bdebb3bdf41d717bf
6
+ metadata.gz: f5ae71d2855a533c4d06060c416686e691fb5e93439a456b1b68c6c3b92443ba5790c3b5baf4e2dc2c04f51c69623dcfebc59a87bec13955fb319fc4bd5f736f
7
+ data.tar.gz: 39a3e52480b4970ca5f95df73090172243a857dc2902a251e913fbf3fc03250f6483baf52f5b8fb3e53701020adcc8531fbf73b0a8a214c5ad6abfbf72b4dad2
data/Gemfile CHANGED
@@ -1,12 +1,11 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- gem 'nokogiri'
4
3
  gem 'oj'
5
4
  gem 'htmlentities'
6
5
  gem 'net-dns'
7
6
  gem 'bit-struct'
8
7
  gem 'geoip-c'
9
- gem 'recog', '>=1.0.15'
8
+ gem 'recog', '>=2.0'
10
9
 
11
10
  group :test do
12
11
  gem 'rspec', '~> 3.1.0'
@@ -28,7 +28,7 @@ GEM
28
28
  nokogiri (1.6.3.1)
29
29
  mini_portile (= 0.6.0)
30
30
  oj (2.10.2)
31
- recog (1.0.15)
31
+ recog (2.0.2)
32
32
  nokogiri
33
33
  rspec (3.1.0)
34
34
  rspec-core (~> 3.1.0)
@@ -53,7 +53,6 @@ DEPENDENCIES
53
53
  geoip-c
54
54
  htmlentities
55
55
  net-dns
56
- nokogiri
57
56
  oj
58
- recog (>= 1.0.15)
57
+ recog (>= 2.0)
59
58
  rspec (~> 3.1.0)
@@ -80,4 +80,37 @@ SEARCHES = {
80
80
  ['7.0', 'sp4'] => ['CVE-2003-0230', 'CVE-2003-0231', 'CVE-2003-0232', 'CVE-2004-1560', 'CVE-2008-0085', 'CVE-2008-0086', 'CVE-2008-0106', 'CVE-2008-0107'],
81
81
  }
82
82
  }],
83
+
84
+ :http => [
85
+ #### ELASTICSEARCH RCE
86
+ {
87
+ # direct shellcommand elastic rce
88
+ :match => [
89
+ ['http.path', '/_search'],
90
+ ['http.body', 'script_fields'],
91
+ ['http.body', 'java.lang.Runtime'],
92
+ ['http.body', 'getRuntime()'],
93
+ ],
94
+ :cve => ['VULN-ELASTICSEARCH-RCE', 'CVE-2014-3120']
95
+ },{
96
+ # this just adds another tag as it's most likely done with metasploit
97
+ :match => [
98
+ ['http.path', '/_search'],
99
+ ['http.body', 'script_fields'],
100
+ ['http.body', 'metasploit.Payload'],
101
+ ],
102
+ :cve => ['VULN-ELASTICSEARCH-RCE', 'METASPLOIT']
103
+ }] + [
104
+ #### PHP CGI
105
+ {
106
+ :match => [
107
+ ['http.path', '/cgi-bin/php'],
108
+ ],
109
+ :cve => ['VULN-PHPCGI']
110
+ },{
111
+ :match => [
112
+ ['http.path', '/cgi-bin/authLogin.cgi'],
113
+ ],
114
+ :cve => ['VULN-QNAP-SHELLSHOCK']
115
+ }],
83
116
  }
@@ -2,11 +2,62 @@ module Dap
2
2
  module Filter
3
3
 
4
4
  require 'htmlentities'
5
- require 'nokogiri'
5
+ require 'shellwords'
6
6
  require 'uri'
7
7
 
8
+ # Dirty element extractor, works around memory issues with Nokogiri
9
+ module HTMLGhetto
10
+ def extract_elements(data)
11
+ @coder ||= HTMLEntities.new
12
+ res = []
13
+ data.
14
+ to_s.
15
+ encode('UTF-8', invalid: :replace, undef: :replace, replace: '').
16
+ scan(/<([^>]+)>/m).each do |e|
17
+
18
+ e = e.first
19
+
20
+ # Skip closing tags
21
+ next if e[0,1] == "/"
22
+
23
+ # Get the name vs attributes
24
+ name, astr = e.split(/\s+/, 2).map{|x| x.to_s }
25
+ astr ||= ''
26
+
27
+ # Skip non-alpha elements
28
+ next unless name =~ /^[a-zA-Z]/
29
+
30
+ # Convert newlines to spaces & strip trailing />
31
+ astr = astr.gsub(/\n/, ' ').sub(/\/$/, '')
32
+
33
+ o = { name: name }
34
+
35
+ begin
36
+ Shellwords.shellwords(astr).each do |attr_str|
37
+ aname, avalue = attr_str.split('=', 2).map{|x| x.to_s.strip }
38
+ avalue = avalue.to_s.gsub(/^\"|"$/, '')
39
+ o[aname] = @coder.decode(avalue)
40
+ end
41
+ rescue ::Interrupt
42
+ raise $!
43
+ rescue ::Exception
44
+ # If shellwords couldn't parse it, split on space instead
45
+ astr.to_s.split(/\s+/).each do |attr_str|
46
+ aname, avalue = attr_str.split('=', 2).map{|x| x.to_s.strip }
47
+ avalue = avalue.to_s.gsub(/^\"|"$/, '')
48
+ o[aname] = @coder.decode(avalue)
49
+ end
50
+ end
51
+ res << o
52
+ end
53
+
54
+ res
55
+ end
56
+ end
57
+
8
58
  class FilterHTMLIframes
9
59
  include Base
60
+ include HTMLGhetto
10
61
 
11
62
  def process(doc)
12
63
  out = []
@@ -20,25 +71,11 @@ class FilterHTMLIframes
20
71
  end
21
72
 
22
73
  def extract(data)
23
- @coder ||= HTMLEntities.new
24
- urls = []
25
-
26
- data = data.encode('UTF-8', invalid: :replace, undef: :replace, replace: '')
27
- html = nil
28
- begin
29
- html = Nokogiri::HTML(data) do |conf|
30
- conf.strict.noent
31
- end
32
- rescue ::Exception
33
- return urls
34
- end
35
-
36
- html.xpath('//iframe').each do |e|
74
+ extract_elements(data).select{|x| x[:name] == 'iframe'}.each do |e|
37
75
  url = e['src']
38
- next unless url
76
+ next unless (url && url.length > 0)
39
77
  urls << url
40
78
  end
41
-
42
79
  urls
43
80
  end
44
81
  end
@@ -46,6 +83,7 @@ end
46
83
 
47
84
  class FilterHTMLLinks
48
85
  include Base
86
+ include HTMLGhetto
49
87
 
50
88
  def process(doc)
51
89
  out = []
@@ -61,20 +99,10 @@ class FilterHTMLLinks
61
99
  def extract(data)
62
100
  urls = []
63
101
 
64
- data = data.encode('UTF-8', invalid: :replace, undef: :replace, replace: '')
65
- html = nil
66
- begin
67
- html = Nokogiri::HTML(data) do |conf|
68
- conf.strict.noent
69
- end
70
- rescue ::Exception
71
- return urls
72
- end
73
-
74
- html.xpath('//*').each do |e|
102
+ extract_elements(data).each do |e|
75
103
  url = e['href'] || e['src']
76
- next unless url
77
- urls << { 'link' => url, 'element' => e.name }
104
+ next unless (url && url.length > 0)
105
+ urls << { 'link' => url, 'element' => e[:name] }
78
106
  end
79
107
 
80
108
  urls
@@ -136,14 +164,14 @@ class FilterDecodeHTTPReply
136
164
  when /^Date:\s*(.*)/i
137
165
  d = DateTime.parse($1.strip) rescue nil
138
166
  save["http_date"] = d.to_time.strftime("%Y%m%dT%H:%M:%S") if d
139
-
167
+
140
168
  when /^Last-modified:\s*(.*)/i
141
169
  d = DateTime.parse($1.strip) rescue nil
142
170
  save["http_modified"] = d.to_time.strftime("%Y%m%dT%H:%M:%S") if d
143
171
 
144
172
  when /^Location:\s*(.*)/i
145
- save["http_location"] = $1.strip
146
-
173
+ save["http_location"] = $1.strip
174
+
147
175
  when /^WWW-Authenticate:\s*(.*)/i
148
176
  save["http_auth"] = $1.strip
149
177
 
@@ -159,7 +187,7 @@ class FilterDecodeHTTPReply
159
187
  end
160
188
 
161
189
  head, body = data.split(/\r?\n\r?\n/, 2)
162
-
190
+
163
191
  # Some buggy systems exclude the header entirely
164
192
  body ||= head
165
193
 
@@ -64,5 +64,145 @@ class FilterVulnMatchMSSQL
64
64
  end
65
65
  end
66
66
 
67
+ class FilterVulnMatchHTTP
68
+ include Base
69
+ include BaseVulnMatch
70
+
71
+ def check_shellshock(doc)
72
+ if not doc["http.headers"]
73
+ return []
74
+ end
75
+
76
+ h = doc["http.headers"]
77
+ sspattern = /\(\)\s*{\s*:;\s*};/
78
+
79
+ if h["user-agent"] and h["user-agent"] =~ sspattern
80
+ return ['VULN-SHELLSHOCK', 'CVE-2014-6271']
81
+ end
82
+
83
+ if h["referrer"] and h["referrer"] =~ sspattern
84
+ return ['VULN-SHELLSHOCK', 'CVE-2014-6271']
85
+ end
86
+
87
+ return []
88
+ end
89
+
90
+ def check_elastic(doc)
91
+ if not doc['http.path']
92
+ return []
93
+ end
94
+ if not doc['http.path'] == '/_search'
95
+ return []
96
+ end
97
+
98
+ input = doc['http.url']
99
+ if doc['http.method'] == "POST"
100
+ input = doc['http.body']
101
+ end
102
+
103
+ if not input.match("script_fields")
104
+ return []
105
+ end
106
+
107
+ out = ['VULN-ELASTICSEARCH-RCE', 'CVE-2014-3120']
108
+ if input.match("Runtime") and input.match("getRuntime()")
109
+ out += ["EXEC-SHELLCMD"]
110
+ end
111
+
112
+ if input.match("FileOutputStream") and input.match("URLClassLoader")
113
+ out += ["EXEC-JAVA-CLASS"]
114
+ end
115
+
116
+ if input.match("getDeclaredConstructor")
117
+ out += ['CVE-2015-1427']
118
+ end
119
+
120
+ if input.match("metasploit.Payload")
121
+ out += ['METASPLOIT']
122
+ end
123
+
124
+ return out
125
+ end
126
+
127
+ def process(doc)
128
+ vulns = []
129
+ if doc['vulnerability']
130
+ vulns |= doc['vulnerability']
131
+ end
132
+
133
+ vulns |= check_elastic(doc)
134
+ vulns |= check_shellshock(doc)
135
+
136
+ # see vulndb.rb, allows for simple matches to be added quickly
137
+ SEARCHES[:http].each do | entry |
138
+ success = true
139
+
140
+ # all matches must go through
141
+ entry[:match].each do | k, v |
142
+ if not doc[k]
143
+ success = false
144
+ else
145
+ m = doc[k].match(v)
146
+ if not m
147
+ success = false
148
+ end
149
+ end
150
+
151
+ if not success
152
+ break
153
+ end
154
+ end
155
+
156
+ if success
157
+ vulns |= entry[:cve]
158
+ end
159
+ end
160
+
161
+ if vulns != []
162
+ doc['vulnerability'] = vulns
163
+ end
164
+
165
+ [ doc ]
166
+ end
167
+ end
168
+
169
+ class FilterGenericSetMatch
170
+ include Base
171
+ attr_accessor :matchset
172
+
173
+ def initialize(args)
174
+ self.opts = {}
175
+ args.each do |arg|
176
+ k,v = arg.split("=", 2)
177
+ self.opts[k] = v
178
+ end
179
+ self.name = Dap::Factory.name_from_class(self.class)
180
+
181
+ fail "Expected key and set arguments to #{self.name} but got #{self.opts}" unless self.opts.has_key?("key") and self.opts.has_key?("set")
182
+
183
+ self.matchset = {}
184
+ File.readlines(self.opts["set"]).each do |line|
185
+ self.matchset[line.chomp] = nil
186
+ end
187
+ end
188
+
189
+ def process(doc)
190
+ if doc.has_key?(self.opts["key"])
191
+ if doc[self.opts["key"]].kind_of?(Array)
192
+ doc[self.opts["key"]].each do |val|
193
+ if self.matchset.has_key?(val)
194
+ return [ doc ]
195
+ end
196
+ end
197
+ else
198
+ if self.matchset.has_key?(doc[self.opts["key"]])
199
+ return [ doc ]
200
+ end
201
+ end
202
+ end
203
+ [ ]
204
+ end
205
+ end
206
+
67
207
  end
68
208
  end
@@ -1,3 +1,3 @@
1
1
  module Dap
2
- VERSION = "0.0.4"
2
+ VERSION = "0.0.5"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dap
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rapid7 Research
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-02-10 00:00:00.000000000 Z
11
+ date: 2015-09-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -241,7 +241,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
241
241
  version: '0'
242
242
  requirements: []
243
243
  rubyforge_project:
244
- rubygems_version: 2.4.3
244
+ rubygems_version: 2.4.8
245
245
  signing_key:
246
246
  specification_version: 4
247
247
  summary: 'DAP: The Data Analysis Pipeline'