sqreen 1.4.2-java → 1.4.3-java

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: fcc1bc6cf192ce4b177a5e638226a989e0f8e174
4
- data.tar.gz: b52e7d1765d4021129bb0107a4345613872f389c
3
+ metadata.gz: 3be83ec63339da677df7f8d12efd3f57c5ae135b
4
+ data.tar.gz: 873ab18040fdb66fd7a6f4ebe75d6c465b2035e0
5
5
  SHA512:
6
- metadata.gz: f9ffbbcfa1fa5c9ebeeca43963c74c724e2322de0feb38d42e39242bfd5402efe4c6043af307b55e34564f2ccec7d3847906f71e15b9987a635b2f97758d7d38
7
- data.tar.gz: aeb35086030d9b6ce6cbf3d210b9388927066a237d3bdb83c080004b43b6a00b562b8d889f4499ae46336a7a889141dcc8ac259c0bfa5974c90b8db5e9db0b78
6
+ metadata.gz: 208b06ca1100546c07a8512d5ab22ee9630f749408aa7f450ba7ea41c7449c952f16f58ef76c3d2631183f64f353bb53fc94d52a6c871f18cfd7cbcea7b64530
7
+ data.tar.gz: 503bfca4f48c619745153cbfa9049cdc0fbb234a320dfdab74a7a0672604b50b0c36d8dd0540af1c53dc3433c6b611204b8da39c6487709c3c45825ea131ae72
@@ -56,6 +56,34 @@ class ConditionEvaluator
56
56
  end
57
57
  end
58
58
 
59
+ # Predicate: Is one of values deeply present in keys of hash
60
+ # @params value [Array] Array of objects to find
61
+ # @params hash [Hash] Hash to search into
62
+ # @params min_value_size [Fixnum] to compare against
63
+ def self.hash_key_include?(values, hash, min_value_size, rem = 10)
64
+ return true if rem <= 0
65
+ if hash.is_a?(Array)
66
+ return hash.any? do |v|
67
+ ConditionEvaluator.hash_key_include?(values, v, min_value_size, rem - 1)
68
+ end
69
+ end
70
+
71
+ return false unless hash.is_a?(Hash)
72
+
73
+ hash.any? do |hkey, hval|
74
+ case hkey
75
+ when NilClass
76
+ false
77
+ else
78
+ if hkey.respond_to?(:empty?) && hkey.empty?
79
+ false
80
+ else
81
+ values.include?(hkey.to_s) || ConditionEvaluator.hash_key_include?(values, hval, min_value_size, rem - 1)
82
+ end
83
+ end
84
+ end
85
+ end
86
+
59
87
  # Test is a str contains what. Rencode if necessary
60
88
  def self.str_include?(str, what)
61
89
  str1 = if str.encoding != Encoding::UTF_8
@@ -128,12 +156,14 @@ class ConditionEvaluator
128
156
  GT_OPERATOR = '%gt'.freeze
129
157
  LT_OPERATOR = '%lt'.freeze
130
158
  HASH_INC_OPERATOR = '%hash_val_include'.freeze
159
+ HASH_KEY_OPERATOR = '%hash_key_include'.freeze
131
160
  INC_OPERATOR = '%include'.freeze
132
161
  OR_OPERATOR = '%or'.freeze
133
162
  AND_OPERATOR = '%and'.freeze
134
163
 
135
164
  OPERATORS_ARITY = {
136
165
  HASH_INC_OPERATOR => 3,
166
+ HASH_KEY_OPERATOR => 3,
137
167
  EQ_OPERATOR => 2,
138
168
  NEQ_OPERATOR => 2,
139
169
  INC_OPERATOR => 2,
@@ -191,6 +221,8 @@ class ConditionEvaluator
191
221
  end
192
222
  when HASH_INC_OPERATOR
193
223
  ConditionEvaluator.hash_val_include?(res[0], res[1], res[2])
224
+ when HASH_KEY_OPERATOR
225
+ ConditionEvaluator.hash_key_include?(res[0], res[1], res[2])
194
226
  else
195
227
  # FIXME: this should be check in compile
196
228
  raise(Sqreen::Exception, "unknown op #{op})")
@@ -167,7 +167,7 @@ module Sqreen
167
167
  @wait << block
168
168
  end
169
169
 
170
- # Does the parameters include this value
170
+ # Does the parameters value include this value
171
171
  def params_include?(value)
172
172
  params = request_params
173
173
  return false if params.nil?
@@ -177,6 +177,16 @@ module Sqreen
177
177
  false
178
178
  end
179
179
 
180
+ # Does the parameters key/value include this value
181
+ def full_params_include?(value)
182
+ params = request_params
183
+ return false if params.nil?
184
+ each_key_value_for_hash(params) do |param|
185
+ return true if param == value
186
+ end
187
+ false
188
+ end
189
+
180
190
  # Fetch and store the current request object
181
191
  # Nota: cleanup should be performed at end of request (see clean_request)
182
192
  def store_request(object)
@@ -313,6 +323,18 @@ module Sqreen
313
323
  end
314
324
  end
315
325
 
326
+ def each_key_value_for_hash(params, &block)
327
+ case params
328
+ when Hash then params.each do |k, v|
329
+ yield k
330
+ each_key_value_for_hash(v, &block)
331
+ end
332
+ when Array then params.each { |v| each_key_value_for_hash(v, &block) }
333
+ else
334
+ yield params
335
+ end
336
+ end
337
+
316
338
  def ensure_rack_loaded
317
339
  @cannot_load_rack ||= false
318
340
  return false if @cannot_load_rack
@@ -1,6 +1,7 @@
1
1
  # Copyright (c) 2015 Sqreen. All Rights Reserved.
2
2
  # Please refer to our terms for more information: https://www.sqreen.io/terms.html
3
3
 
4
+ require 'sqreen/rule_attributes'
4
5
  require 'sqreen/rule_callback'
5
6
 
6
7
  module Sqreen
@@ -14,5 +15,25 @@ module Sqreen
14
15
  advise_action(nil)
15
16
  end
16
17
  end
18
+
19
+ # Count 1 for each things located by the binding accessor
20
+ class BindingAccessorCounter < RuleCB
21
+ def initialize(klass, method, rule_hash)
22
+ super(klass, method, rule_hash)
23
+ @accessors = @data['values'].map do |expr|
24
+ BindingAccessor.new(expr, true)
25
+ end
26
+ @metric_category = rule_hash[Attrs::METRICS].first['name']
27
+ end
28
+
29
+ def post(rv, inst, *args, &_block)
30
+ return unless rv.is_a?(Array) && !rv.empty?
31
+ key = @accessors.map do |accessor|
32
+ accessor.resolve(binding, framework, inst, args, @data, rv)
33
+ end
34
+ record_observation(@metric_category, JSON.dump(key), 1)
35
+ advise_action(nil)
36
+ end
37
+ end
17
38
  end
18
39
  end
@@ -10,8 +10,24 @@ require 'sqreen/rules_callbacks/regexp_rule'
10
10
  module Sqreen
11
11
  # Sqreen rules
12
12
  module Rules
13
+ # XSSCB abstract common behaviour of tpls
14
+ class XSSCB < RegexpRuleCB
15
+ # The remaining code is only to find out if user entry was an attack,
16
+ # and record it. Since we don't rely on it to respond to user, it would
17
+ # be better to do it in background.
18
+ def report_dangerous_xss(value)
19
+ found = match_regexp(value)
20
+
21
+ return unless found
22
+ infos = {
23
+ :found => found,
24
+ :payload => value,
25
+ }
26
+ record_event(infos)
27
+ end
28
+ end
13
29
  # look for reflected XSS with erb template engine
14
- class ReflectedXSSCB < RegexpRuleCB
30
+ class ReflectedXSSCB < XSSCB
15
31
  def pre(_inst, *args, &_block)
16
32
  value = args[0]
17
33
 
@@ -38,33 +54,20 @@ module Sqreen
38
54
  advise_action(nil)
39
55
  end
40
56
 
41
- # The remaining code is only to find out if user entry was an attack,
42
- # and record it. Since we don't rely on it to respond to user, it would
43
- # be better to do it in background.
44
- def report_dangerous_xss(value)
45
- found = match_regexp(value)
46
-
47
- return unless found
48
- infos = {
49
- :found => found,
50
- :payload => value,
51
- }
52
- record_event(infos)
53
- end
54
57
  end
55
58
  # look for reflected XSS with haml template engine
56
59
  # hook function arguments of
57
60
  # Haml::Buffer.format_script(result, preserve_script, in_tag, preserve_tag,
58
61
  # escape_html, nuke_inner_whitespace,
59
62
  # interpolated, ugly)
60
- class ReflectedXSSHamlCB < ReflectedXSSCB
63
+ class ReflectedXSSHamlCB < XSSCB
61
64
  def post(ret, _inst, *_args, &_block)
62
65
  value = ret
63
66
  return if value.nil?
64
67
 
65
68
  # Sqreen::log.debug value
66
69
 
67
- return unless framework.params_include?(value)
70
+ return unless framework.full_params_include?(value)
68
71
 
69
72
  Sqreen.log.debug { format('Found unescaped user param: %s', value) }
70
73
 
@@ -103,10 +106,117 @@ module Sqreen
103
106
  nil
104
107
  end
105
108
  end
109
+
110
+ class Haml4UtilInterpolationHookCB < RuleCB
111
+ def pre(_inst, *args, &_block)
112
+ str = args[0]
113
+ escape_html = args[1]
114
+ # Original code from HAML tuned up to insert escape_haml call
115
+ res = ''
116
+ rest = Haml::Util.handle_interpolation str.dump do |scan|
117
+ escapes = (scan[2].size - 1) / 2
118
+ res << scan.matched[0...-3 - escapes]
119
+ if escapes.odd?
120
+ res << '#{'
121
+ else
122
+ content = eval('"' + Haml::Util.balance(scan, '{', '}', 1)[0][0...-1] + '"')
123
+ content = "Haml::Helpers.html_escape((#{content}))" if escape_html
124
+ res << '#{Sqreen.escape_haml(' + content + ')}' # Use eval to get rid of string escapes
125
+ end
126
+ end
127
+ { :status => :skip, :new_return_value => res + rest }
128
+ end
129
+ end
130
+
131
+ # Hook build attributes
132
+ class Haml4CompilerBuildAttributeCB < XSSCB
133
+ def pre(inst, *args, &_block)
134
+ attrs = args[-1]
135
+ new_attrs, found_xss = Haml4CompilerBuildAttributeCB.clean_hash_key(attrs) do |key|
136
+ if !key.nil? && key.is_a?(String) && framework.full_params_include?(key)
137
+ Sqreen.log.debug { format('Found unescaped user param: %s', key) }
138
+ report_dangerous_xss(key)
139
+ [CGI.escape_html(key), true]
140
+ else
141
+ [key, false]
142
+ end
143
+ end
144
+
145
+ return if !found_xss || !block
146
+ # potential XSS! let's escape
147
+ if !framework || !find_whitelisted_path(framework.request_path.to_s)
148
+ args[-1] = new_attrs
149
+ r = inst.send(method, *args)
150
+ return { :status => :skip, :new_return_value => r }
151
+ end
152
+ end
153
+
154
+ def self.clean_hash_key(hash, limit = 10, seen = [], &block)
155
+ seen << hash.object_id
156
+ has_xss = false
157
+ new_h = {}
158
+ return if limit <= 0
159
+ hash.each do |k, v|
160
+ if seen.include?(v.object_id)
161
+ new_h[k] = nil
162
+ next
163
+ end
164
+ seen << v.object_id
165
+ new_key, found_xss = yield k
166
+ has_xss |= found_xss
167
+ if v.is_a?(Hash)
168
+ new_h[new_key], found_xss = Haml4CompilerBuildAttributeCB.clean_hash_key(v, limit - 1, seen, &block)
169
+ has_xss |= found_xss
170
+ else
171
+ new_h[new_key] = v
172
+ end
173
+ end
174
+ [new_h, has_xss]
175
+ end
176
+ end
177
+
178
+ # Hook into temple template rendering
179
+ class TempleEscapableHookCB < RuleCB
180
+ def post(ret, _inst, *_args, &_block)
181
+ ret[1] = "Sqreen.escape_temple(#{ret[1]})"
182
+ { :status => :override, :new_return_value => ret }
183
+ end
184
+ end
185
+
186
+ # Hook into temple template rendering
187
+ class SlimSplatBuilderCB < XSSCB
188
+ def pre(inst, *args, &_block)
189
+ value = args[0]
190
+ return if value.nil?
191
+
192
+ return unless framework.full_params_include?(value)
193
+
194
+ Sqreen.log.debug { format('Found unescaped user param: %s', value) }
195
+
196
+ return unless value.is_a?(String)
197
+
198
+ report_dangerous_xss(value)
199
+
200
+ return unless block
201
+ # potential XSS! let's escape
202
+ if block &&
203
+ (!framework || !find_whitelisted_path(framework.request_path.to_s))
204
+ args[0] = CGI.escape_html(value)
205
+ r = inst.send(method, *args)
206
+ return { :status => :skip, :new_return_value => r }
207
+ end
208
+ nil
209
+ end
210
+ end
106
211
  end
107
212
 
108
213
  # Escape HAML when instrumented to do it
109
214
  def self.escape_haml(x)
110
215
  x
111
216
  end
217
+
218
+ # Escape Temple when instrumented to do it
219
+ def self.escape_temple(x)
220
+ x
221
+ end
112
222
  end
@@ -1,5 +1,5 @@
1
1
  # Copyright (c) 2015 Sqreen. All Rights Reserved.
2
2
  # Please refer to our terms for more information: https://www.sqreen.io/terms.html
3
3
  module Sqreen
4
- VERSION = '1.4.2'.freeze
4
+ VERSION = '1.4.3'.freeze
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sqreen
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.2
4
+ version: 1.4.3
5
5
  platform: java
6
6
  authors:
7
7
  - Sqreen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-03-28 00:00:00.000000000 Z
11
+ date: 2017-04-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: execjs