sqreen 1.3.21489051313-java → 1.4.2-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Rakefile +0 -20
- data/lib/sqreen/events/attack.rb +2 -0
- data/lib/sqreen/instrumentation.rb +8 -1
- data/lib/sqreen/remote_command.rb +1 -0
- data/lib/sqreen/rule_callback.rb +28 -0
- data/lib/sqreen/rules.rb +9 -2
- data/lib/sqreen/rules_callbacks/binding_accessor_metrics.rb +1 -1
- data/lib/sqreen/rules_callbacks/count_http_codes.rb +1 -1
- data/lib/sqreen/rules_callbacks/crawler_user_agent_matches.rb +1 -1
- data/lib/sqreen/rules_callbacks/crawler_user_agent_matches_metrics.rb +1 -1
- data/lib/sqreen/rules_callbacks/execjs.rb +4 -1
- data/lib/sqreen/rules_callbacks/headers_insert.rb +1 -1
- data/lib/sqreen/rules_callbacks/rails_parameters.rb +1 -1
- data/lib/sqreen/rules_callbacks/record_request_context.rb +3 -0
- data/lib/sqreen/rules_callbacks/reflected_xss.rb +48 -22
- data/lib/sqreen/rules_callbacks/shell_env.rb +1 -1
- data/lib/sqreen/rules_callbacks/url_matches.rb +1 -1
- data/lib/sqreen/rules_callbacks/user_agent_matches.rb +1 -1
- data/lib/sqreen/runner.rb +12 -0
- data/lib/sqreen/version.rb +1 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fcc1bc6cf192ce4b177a5e638226a989e0f8e174
|
4
|
+
data.tar.gz: b52e7d1765d4021129bb0107a4345613872f389c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f9ffbbcfa1fa5c9ebeeca43963c74c724e2322de0feb38d42e39242bfd5402efe4c6043af307b55e34564f2ccec7d3847906f71e15b9987a635b2f97758d7d38
|
7
|
+
data.tar.gz: aeb35086030d9b6ce6cbf3d210b9388927066a237d3bdb83c080004b43b6a00b562b8d889f4499ae46336a7a889141dcc8ac259c0bfa5974c90b8db5e9db0b78
|
data/Rakefile
CHANGED
@@ -18,23 +18,3 @@ end
|
|
18
18
|
|
19
19
|
desc 'Run tests'
|
20
20
|
task :default => :test
|
21
|
-
|
22
|
-
task :pre_build do
|
23
|
-
version = Bundler::GemHelper.new.send(:version)
|
24
|
-
template = <<-EOF.gsub(/^\s{0,3}/m, '')
|
25
|
-
# Copyright (c) 2015 Sqreen. All Rights Reserved.
|
26
|
-
# Please refer to our terms for more information: https://www.sqreen.io/terms.html
|
27
|
-
# Warning This file is auto generated! DO NOT edit.
|
28
|
-
|
29
|
-
module Sqreen
|
30
|
-
VERSION = #{version.to_s.inspect}.freeze
|
31
|
-
end
|
32
|
-
EOF
|
33
|
-
fname = File.join(File.dirname(__FILE__), 'lib', 'sqreen', 'version.rb')
|
34
|
-
File.open(fname, 'w') do |f|
|
35
|
-
f.puts template
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
default_build = Rake::Task['build']
|
40
|
-
default_build.prerequisites.push(Rake::Task['pre_build'])
|
data/lib/sqreen/events/attack.rb
CHANGED
@@ -45,6 +45,7 @@ module Sqreen
|
|
45
45
|
res = {}
|
46
46
|
rule_p = payload['rule']
|
47
47
|
request_p = payload['request']
|
48
|
+
whitelisted = request_p.delete('whitelisted') if request_p
|
48
49
|
res[:rule_name] = rule_p['name'] if rule_p && rule_p['name']
|
49
50
|
res[:rulespack_id] = rule_p['rulespack_id'] if rule_p && rule_p['rulespack_id']
|
50
51
|
res[:test] = rule_p['test'] if rule_p && rule_p['test']
|
@@ -55,6 +56,7 @@ module Sqreen
|
|
55
56
|
res[:params] = payload['params'] if payload['params']
|
56
57
|
res[:context] = payload['context'] if payload['context']
|
57
58
|
res[:headers] = payload['headers'] if payload['headers']
|
59
|
+
res[:whitelist_match] = whitelisted if whitelisted
|
58
60
|
res
|
59
61
|
end
|
60
62
|
end
|
@@ -371,6 +371,13 @@ module Sqreen
|
|
371
371
|
klass.singleton_methods.include? method
|
372
372
|
end
|
373
373
|
|
374
|
+
# Does this object or an instance of it respond_to method?
|
375
|
+
def valid_method?(obj, method)
|
376
|
+
return true if is_class_method?(obj, method)
|
377
|
+
return false unless obj.respond_to?(:instance_methods)
|
378
|
+
is_instance_method?(obj, method)
|
379
|
+
end
|
380
|
+
|
374
381
|
def add_callback(cb)
|
375
382
|
@@override_semaphore.synchronize do
|
376
383
|
klass = cb.klass
|
@@ -487,7 +494,7 @@ module Sqreen
|
|
487
494
|
end
|
488
495
|
remove_all_callbacks # Force cb tree to be empty before instrumenting
|
489
496
|
rules.each do |rule|
|
490
|
-
rcb = Sqreen::Rules.cb_from_rule(rule, metrics_engine, verifier)
|
497
|
+
rcb = Sqreen::Rules.cb_from_rule(rule, self, metrics_engine, verifier)
|
491
498
|
next unless rcb
|
492
499
|
rcb.framework = framework
|
493
500
|
add_callback(rcb)
|
data/lib/sqreen/rule_callback.rb
CHANGED
@@ -46,11 +46,39 @@ module Sqreen
|
|
46
46
|
@rule[Attrs::RULESPACK_ID]
|
47
47
|
end
|
48
48
|
|
49
|
+
# Recommend taking an action (optionnally adding more data/context)
|
50
|
+
#
|
51
|
+
# This will format the requested action and optionnally
|
52
|
+
# override it if it should not be taken (should not block for example)
|
53
|
+
def advise_action(action, additional_data = {})
|
54
|
+
return if action.nil? && additional_data.empty?
|
55
|
+
if %w(override raise).include?(action.to_s) && framework
|
56
|
+
prefix = find_whitelisted_path(framework.request_path.to_s)
|
57
|
+
if prefix
|
58
|
+
Sqreen.log.debug { "Trying to block on whitelisted path #{prefix}" }
|
59
|
+
action = nil
|
60
|
+
end
|
61
|
+
end
|
62
|
+
additional_data.merge(:status => action)
|
63
|
+
end
|
64
|
+
|
65
|
+
# Is this a whitelisted path?
|
66
|
+
# return the path witelisted prefix that match path
|
67
|
+
def find_whitelisted_path(rpath)
|
68
|
+
(Sqreen.whitelisted_paths || []).find do |path|
|
69
|
+
rpath.start_with?(path)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
49
73
|
# Record an attack event into Sqreen system
|
50
74
|
# @param infos [Hash] Additional information about request
|
51
75
|
def record_event(infos)
|
52
76
|
payload = @payload_generator.payload(framework, @rule)
|
53
77
|
payload['infos'] = infos
|
78
|
+
if framework && payload['request']
|
79
|
+
prefix = find_whitelisted_path(framework.request_path.to_s)
|
80
|
+
payload['request']['whitelisted'] = prefix
|
81
|
+
end
|
54
82
|
Attack.record(payload)
|
55
83
|
end
|
56
84
|
|
data/lib/sqreen/rules.rb
CHANGED
@@ -40,9 +40,10 @@ module Sqreen
|
|
40
40
|
|
41
41
|
# Given a rule, will instantiate the related callback.
|
42
42
|
# @param hash_rule [Hash] Rules metadata
|
43
|
+
# @param instrumentation_engine [Instrumentation] Instrumentation engine
|
43
44
|
# @param metrics_store [MetricStore] Metrics storage facility
|
44
45
|
# @param verifier [SqreenSignedVerifier] Signed verifier
|
45
|
-
def self::cb_from_rule(hash_rule, metrics_store = nil, verifier = nil)
|
46
|
+
def self::cb_from_rule(hash_rule, instrumentation_engine=nil, metrics_store = nil, verifier = nil)
|
46
47
|
# Check rules signature
|
47
48
|
if verifier
|
48
49
|
raise InvalidSignatureException unless verifier.verify(hash_rule)
|
@@ -56,12 +57,18 @@ module Sqreen
|
|
56
57
|
|
57
58
|
if instr_class.nil?
|
58
59
|
rule_name = hash_rule[Attrs::NAME]
|
59
|
-
Sqreen.log.debug "#{klass} does not exists. Skipping #{rule_name}"
|
60
|
+
Sqreen.log.debug { "#{klass} does not exists. Skipping #{rule_name}" }
|
60
61
|
return nil
|
61
62
|
end
|
62
63
|
|
63
64
|
instr_method = hook[Attrs::METHOD]
|
64
65
|
instr_method = instr_method.to_sym
|
66
|
+
if instrumentation_engine &&
|
67
|
+
!instrumentation_engine.valid_method?(instr_class, instr_method)
|
68
|
+
|
69
|
+
Sqreen.log.debug { "#{instr_method} does not exist on #{klass} Skipping #{rule_name}" }
|
70
|
+
return nil
|
71
|
+
end
|
65
72
|
|
66
73
|
cbname = hook[Attrs::CALLBACK_CLASS]
|
67
74
|
|
@@ -94,7 +94,10 @@ module Sqreen
|
|
94
94
|
end
|
95
95
|
Sqreen.log.debug { [name, arguments].inspect }
|
96
96
|
ret = @compiled.call("callbacks.#{name}", *arguments)
|
97
|
-
|
97
|
+
unless record_and_continue?(ret)
|
98
|
+
return nil if ret.nil?
|
99
|
+
return advise_action(ret[:status], ret)
|
100
|
+
end
|
98
101
|
name = ret[:call]
|
99
102
|
rv = ret[:data]
|
100
103
|
args_override = ret[:args]
|
@@ -9,14 +9,17 @@ module Sqreen
|
|
9
9
|
class RecordRequestContext < RuleCB
|
10
10
|
def pre(_inst, *args, &_block)
|
11
11
|
framework.store_request(args[0])
|
12
|
+
advise_action(nil)
|
12
13
|
end
|
13
14
|
|
14
15
|
def post(_rv, _inst, *_args, &_block)
|
15
16
|
framework.clean_request
|
17
|
+
advise_action(nil)
|
16
18
|
end
|
17
19
|
|
18
20
|
def failing(_exception, _inst, *_args, &_block)
|
19
21
|
framework.clean_request
|
22
|
+
advise_action(nil)
|
20
23
|
end
|
21
24
|
end
|
22
25
|
end
|
@@ -3,9 +3,12 @@
|
|
3
3
|
|
4
4
|
require 'cgi'
|
5
5
|
|
6
|
+
require 'sqreen/rule_callback'
|
6
7
|
require 'sqreen/rules_callbacks/regexp_rule'
|
7
8
|
|
9
|
+
# Sqreen module
|
8
10
|
module Sqreen
|
11
|
+
# Sqreen rules
|
9
12
|
module Rules
|
10
13
|
# look for reflected XSS with erb template engine
|
11
14
|
class ReflectedXSSCB < RegexpRuleCB
|
@@ -25,11 +28,14 @@ module Sqreen
|
|
25
28
|
|
26
29
|
saved_value = value.dup
|
27
30
|
# potential XSS! let's escape
|
28
|
-
|
31
|
+
if block &&
|
32
|
+
(!framework || !find_whitelisted_path(framework.request_path.to_s))
|
33
|
+
args[0].replace(CGI.escape_html(value))
|
34
|
+
end
|
29
35
|
|
30
36
|
report_dangerous_xss(saved_value)
|
31
37
|
|
32
|
-
nil
|
38
|
+
advise_action(nil)
|
33
39
|
end
|
34
40
|
|
35
41
|
# The remaining code is only to find out if user entry was an attack,
|
@@ -41,7 +47,7 @@ module Sqreen
|
|
41
47
|
return unless found
|
42
48
|
infos = {
|
43
49
|
:found => found,
|
44
|
-
:payload => value
|
50
|
+
:payload => value,
|
45
51
|
}
|
46
52
|
record_event(infos)
|
47
53
|
end
|
@@ -52,35 +58,55 @@ module Sqreen
|
|
52
58
|
# escape_html, nuke_inner_whitespace,
|
53
59
|
# interpolated, ugly)
|
54
60
|
class ReflectedXSSHamlCB < ReflectedXSSCB
|
55
|
-
def
|
56
|
-
value =
|
61
|
+
def post(ret, _inst, *_args, &_block)
|
62
|
+
value = ret
|
63
|
+
return if value.nil?
|
57
64
|
|
58
|
-
|
59
|
-
|
60
|
-
# if escape_html is already true, it will be escaped later
|
61
|
-
return if args[4]
|
65
|
+
# Sqreen::log.debug value
|
62
66
|
|
63
67
|
return unless framework.params_include?(value)
|
64
68
|
|
65
69
|
Sqreen.log.debug { format('Found unescaped user param: %s', value) }
|
66
70
|
|
67
|
-
|
68
|
-
# escape_html true
|
69
|
-
if block
|
70
|
-
nargs = args.dup
|
71
|
-
nargs[4] = true
|
72
|
-
return_value = {
|
73
|
-
:status => :skip,
|
74
|
-
# 'method' is an attribut reader in class CB, it's the name of the
|
75
|
-
# hooked method
|
76
|
-
:new_return_value => inst.send(method, *nargs),
|
77
|
-
}
|
78
|
-
end
|
71
|
+
return unless value.is_a?(String)
|
79
72
|
|
80
73
|
report_dangerous_xss(value)
|
81
74
|
|
82
|
-
|
75
|
+
return unless block
|
76
|
+
# potential XSS! let's escape
|
77
|
+
advise_action(:override, :new_return_value => CGI.escape_html(value))
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# Hook into haml4 script parser
|
82
|
+
class Haml4ParserScriptHookCB < RuleCB
|
83
|
+
def pre(_inst, *args, &_block)
|
84
|
+
return unless args.size > 1
|
85
|
+
text = args[0]
|
86
|
+
escape_html = args[1]
|
87
|
+
if escape_html == false && !text.include?('html_escape')
|
88
|
+
args[0].replace("Sqreen.escape_haml(#{args[0]})")
|
89
|
+
end
|
90
|
+
nil
|
83
91
|
end
|
84
92
|
end
|
93
|
+
|
94
|
+
# Hook into haml4 tag parser
|
95
|
+
class Haml4ParserTagHookCB < RuleCB
|
96
|
+
def post(ret, _inst, *_args, &_block)
|
97
|
+
tag = ret
|
98
|
+
if tag.value[:escape_html] == false &&
|
99
|
+
!tag.value[:value].include?('html_escape')
|
100
|
+
tag.value[:value] = "Sqreen.escape_haml(#{tag.value[:value]})"
|
101
|
+
return { :status => :override, :new_return_value => tag }
|
102
|
+
end
|
103
|
+
nil
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# Escape HAML when instrumented to do it
|
109
|
+
def self.escape_haml(x)
|
110
|
+
x
|
85
111
|
end
|
86
112
|
end
|
data/lib/sqreen/runner.rb
CHANGED
@@ -48,6 +48,11 @@ module Sqreen
|
|
48
48
|
|
49
49
|
attr_accessor :logged_in
|
50
50
|
alias logged_in? logged_in
|
51
|
+
|
52
|
+
attr_reader :whitelisted_paths
|
53
|
+
def update_whitelisted_paths(paths)
|
54
|
+
@whitelisted_paths = paths.freeze
|
55
|
+
end
|
51
56
|
end
|
52
57
|
|
53
58
|
# Main running job class for the agent
|
@@ -81,6 +86,7 @@ module Sqreen
|
|
81
86
|
|
82
87
|
@token = @configuration.get(:token)
|
83
88
|
@url = @configuration.get(:url)
|
89
|
+
Sqreen.update_whitelisted_paths([])
|
84
90
|
raise(Sqreen::Exception, 'no url found') unless @url
|
85
91
|
raise(Sqreen::TokenNotFoundException, 'no token found') unless @token
|
86
92
|
|
@@ -232,6 +238,12 @@ module Sqreen
|
|
232
238
|
batch_events(features['batch_size'], features['max_staleness'])
|
233
239
|
end
|
234
240
|
|
241
|
+
def change_whitelisted_paths(paths, _context_infos = {})
|
242
|
+
return false unless paths.respond_to?(:each)
|
243
|
+
Sqreen.update_whitelisted_paths(paths)
|
244
|
+
true
|
245
|
+
end
|
246
|
+
|
235
247
|
def change_features(new_features, _context_infos = {})
|
236
248
|
old = features
|
237
249
|
self.features = new_features
|
data/lib/sqreen/version.rb
CHANGED
@@ -1,6 +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
|
-
# Warning This file is auto generated! DO NOT edit.
|
4
3
|
module Sqreen
|
5
|
-
VERSION =
|
4
|
+
VERSION = '1.4.2'.freeze
|
6
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
|
+
version: 1.4.2
|
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-
|
11
|
+
date: 2017-03-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: execjs
|