dap 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
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'