mirror of
https://github.com/owasp-modsecurity/ModSecurity.git
synced 2025-08-13 13:26:01 +03:00
Adds support to URLENCODED_ERROR variable
This commit is contained in:
parent
c5262d54f2
commit
6052d2628b
@ -216,3 +216,4 @@ TESTS+=test/test-cases/secrules-language-tests/operators/detectXSS.json
|
||||
TESTS+=test/test-cases/secrules-language-tests/operators/eq.json
|
||||
TESTS+=test/test-cases/regression/variable-REQBODY_PROCESSOR.json
|
||||
TESTS+=test/test-cases/regression/variable-REQBODY_PROCESSOR_ERROR.json
|
||||
TESTS+=test/test-cases/regression/variable-URLENCODED_ERROR.json
|
||||
|
@ -31,64 +31,6 @@ namespace actions {
|
||||
namespace transformations {
|
||||
|
||||
|
||||
int UrlDecode::urldecode_nonstrict_inplace(unsigned char *input,
|
||||
uint64_t input_len, int *invalid_count, int *changed) {
|
||||
unsigned char *d = (unsigned char *)input;
|
||||
uint64_t i, count;
|
||||
|
||||
*changed = 0;
|
||||
|
||||
if (input == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
i = count = 0;
|
||||
while (i < input_len) {
|
||||
if (input[i] == '%') {
|
||||
/* Character is a percent sign. */
|
||||
|
||||
/* Are there enough bytes available? */
|
||||
if (i + 2 < input_len) {
|
||||
char c1 = input[i + 1];
|
||||
char c2 = input[i + 2];
|
||||
if (VALID_HEX(c1) && VALID_HEX(c2)) {
|
||||
uint64_t uni = x2c(&input[i + 1]);
|
||||
|
||||
*d++ = (wchar_t)uni;
|
||||
count++;
|
||||
i += 3;
|
||||
*changed = 1;
|
||||
} else {
|
||||
/* Not a valid encoding, skip this % */
|
||||
*d++ = input[i++];
|
||||
count++;
|
||||
(*invalid_count)++;
|
||||
}
|
||||
} else {
|
||||
/* Not enough bytes available, copy the raw bytes. */
|
||||
*d++ = input[i++];
|
||||
count++;
|
||||
(*invalid_count)++;
|
||||
}
|
||||
} else {
|
||||
/* Character is not a percent sign. */
|
||||
if (input[i] == '+') {
|
||||
*d++ = ' ';
|
||||
*changed = 1;
|
||||
} else {
|
||||
*d++ = input[i];
|
||||
}
|
||||
count++;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
*d = '\0';
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
UrlDecode::UrlDecode(std::string action)
|
||||
: Transformation(action) {
|
||||
this->action_kind = 1;
|
||||
|
@ -53,9 +53,6 @@ class UrlDecode : public Transformation {
|
||||
explicit UrlDecode(std::string action);
|
||||
std::string evaluate(std::string exp,
|
||||
Transaction *transaction) override;
|
||||
|
||||
int urldecode_nonstrict_inplace(unsigned char *input, uint64_t input_len,
|
||||
int *invalid_count, int *changed);
|
||||
};
|
||||
|
||||
} // namespace transformations
|
||||
|
@ -149,7 +149,7 @@ RUN_TIME_VAR_TIME_WDAY (?i:TIME_WDAY)
|
||||
RUN_TIME_VAR_TIME_YEAR (?i:TIME_YEAR)
|
||||
RUN_TIME_VAR_XML (?i:XML)
|
||||
|
||||
VARIABLENOCOLON (?i:REQBODY_PROCESSOR_ERROR_MSG|REQBODY_PROCESSOR_ERROR|REQBODY_PROCESSOR|REQBODY_ERROR_MSG|REQBODY_ERROR|MULTIPART_FILE_LIMIT_EXCEEDED|MULTIPART_INVALID_QUOTING|MULTIPART_HEADER_FOLDING|MULTIPART_INVALID_HEADER_FOLDING|MULTIPART_STRICT_ERROR|MULTIPART_UNMATCHED_BOUNDARY|REMOTE_ADDR|REQUEST_LINE)
|
||||
VARIABLENOCOLON (?i:URLENCODED_ERROR|REQBODY_PROCESSOR_ERROR_MSG|REQBODY_PROCESSOR_ERROR|REQBODY_PROCESSOR|REQBODY_ERROR_MSG|REQBODY_ERROR|MULTIPART_FILE_LIMIT_EXCEEDED|MULTIPART_INVALID_QUOTING|MULTIPART_HEADER_FOLDING|MULTIPART_INVALID_HEADER_FOLDING|MULTIPART_STRICT_ERROR|MULTIPART_UNMATCHED_BOUNDARY|REMOTE_ADDR|REQUEST_LINE)
|
||||
|
||||
|
||||
CONFIG_VALUE_ON (?i:On)
|
||||
|
@ -140,6 +140,7 @@ Transaction::Transaction(ModSecurity *ms, Rules *rules, void *logCbData)
|
||||
this->m_responseContentType = m_collections.resolveFirst(
|
||||
"RESPONSE_CONTENT_TYPE");
|
||||
|
||||
m_collections.storeOrUpdateFirst("URLENCODED_ERROR", "0");
|
||||
|
||||
#ifndef NO_LOGS
|
||||
this->debug(4, "Initialising transaction");
|
||||
@ -239,6 +240,10 @@ bool Transaction::extractArguments(const std::string &orig,
|
||||
for (std::string t : key_value_sets) {
|
||||
char sep2 = '=';
|
||||
int i = 0;
|
||||
size_t key_s = 0;
|
||||
size_t value_s = 0;
|
||||
int invalid = 0;
|
||||
int changed = 0;
|
||||
|
||||
std::string key;
|
||||
std::string value;
|
||||
@ -254,9 +259,29 @@ bool Transaction::extractArguments(const std::string &orig,
|
||||
i++;
|
||||
}
|
||||
|
||||
key = uri_decode(key);
|
||||
value = uri_decode(value);
|
||||
addArgument(orig, key, value);
|
||||
key_s = (key.length() + 1);
|
||||
value_s = (value.length() + 1);
|
||||
unsigned char *key_c = (unsigned char *) malloc(sizeof(char) * key_s);
|
||||
unsigned char *value_c = (unsigned char *) malloc(sizeof(char) * value_s);
|
||||
|
||||
memset(key_c, '\0', sizeof(char) * key_s);
|
||||
memset(value_c, '\0', sizeof(char) * value_s);
|
||||
|
||||
memcpy(key_c, key.c_str(), key_s);
|
||||
memcpy(value_c, value.c_str(), value_s);
|
||||
|
||||
key_s = urldecode_nonstrict_inplace(key_c, key_s, &invalid, &changed);
|
||||
value_s = urldecode_nonstrict_inplace(value_c, value_s, &invalid, &changed);
|
||||
|
||||
if (invalid) {
|
||||
m_collections.storeOrUpdateFirst("URLENCODED_ERROR", "1");
|
||||
}
|
||||
|
||||
addArgument(orig, std::string((char *)key_c, key_s-1),
|
||||
std::string((char *)value_c, value_s-1));
|
||||
|
||||
free(key_c);
|
||||
free(value_c);
|
||||
}
|
||||
}
|
||||
|
||||
|
61
src/utils.cc
61
src/utils.cc
@ -73,6 +73,67 @@ std::string phase_name(int x) {
|
||||
}
|
||||
|
||||
|
||||
int urldecode_nonstrict_inplace(unsigned char *input,
|
||||
uint64_t input_len, int *invalid_count, int *changed) {
|
||||
unsigned char *d = (unsigned char *)input;
|
||||
uint64_t i, count;
|
||||
|
||||
*changed = 0;
|
||||
|
||||
if (input == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
i = count = 0;
|
||||
while (i < input_len) {
|
||||
if (input[i] == '%') {
|
||||
/* Character is a percent sign. */
|
||||
|
||||
/* Are there enough bytes available? */
|
||||
if (i + 2 < input_len) {
|
||||
char c1 = input[i + 1];
|
||||
char c2 = input[i + 2];
|
||||
if (VALID_HEX(c1) && VALID_HEX(c2)) {
|
||||
uint64_t uni = x2c(&input[i + 1]);
|
||||
|
||||
*d++ = (wchar_t)uni;
|
||||
count++;
|
||||
i += 3;
|
||||
*changed = 1;
|
||||
} else {
|
||||
/* Not a valid encoding, skip this % */
|
||||
*d++ = input[i++];
|
||||
count++;
|
||||
(*invalid_count)++;
|
||||
}
|
||||
} else {
|
||||
/* Not enough bytes available, copy the raw bytes. */
|
||||
*d++ = input[i++];
|
||||
count++;
|
||||
(*invalid_count)++;
|
||||
}
|
||||
} else {
|
||||
/* Character is not a percent sign. */
|
||||
if (input[i] == '+') {
|
||||
*d++ = ' ';
|
||||
*changed = 1;
|
||||
} else {
|
||||
*d++ = input[i];
|
||||
}
|
||||
count++;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
*d = '\0';
|
||||
#endif
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::vector<std::string> split(std::string str, char delimiter) {
|
||||
std::vector<std::string> internal;
|
||||
std::stringstream ss(str); // Turn the string into a stream.
|
||||
|
@ -31,6 +31,8 @@
|
||||
|
||||
namespace modsecurity {
|
||||
std::vector<std::string> split(std::string str, char delimiter);
|
||||
int urldecode_nonstrict_inplace(unsigned char *input,
|
||||
uint64_t input_len, int *invalid_count, int *changed);
|
||||
double random_number(const double from, const double to);
|
||||
double generate_transaction_unique_id();
|
||||
std::string ascTime(time_t *t);
|
||||
|
@ -118,7 +118,7 @@
|
||||
]
|
||||
},
|
||||
"expected":{
|
||||
"debug_log":"Target value: \"24."
|
||||
"debug_log":"Target value: \"25."
|
||||
},
|
||||
"rules":[
|
||||
"SecRuleEngine On",
|
||||
@ -144,7 +144,7 @@
|
||||
"Host":"localhost",
|
||||
"User-Agent":"curl/7.38.0",
|
||||
"Accept":"*/*",
|
||||
"Content-Length": "27",
|
||||
"Content-Length": "28",
|
||||
"Content-Type": "application/x-www-form-urlencoded"
|
||||
},
|
||||
"uri":"/",
|
||||
@ -164,7 +164,7 @@
|
||||
]
|
||||
},
|
||||
"expected":{
|
||||
"debug_log":"Target value: \"27."
|
||||
"debug_log":"Target value: \"28."
|
||||
},
|
||||
"rules":[
|
||||
"SecRuleEngine On",
|
||||
@ -210,7 +210,7 @@
|
||||
]
|
||||
},
|
||||
"expected":{
|
||||
"debug_log":"Target value: \"15."
|
||||
"debug_log":"Target value: \"16."
|
||||
},
|
||||
"rules":[
|
||||
"SecRuleEngine On",
|
||||
|
309
test/test-cases/regression/variable-URLENCODED_ERROR.json
Normal file
309
test/test-cases/regression/variable-URLENCODED_ERROR.json
Normal file
@ -0,0 +1,309 @@
|
||||
[
|
||||
{
|
||||
"enabled":1,
|
||||
"version_min":300000,
|
||||
"title":"Testing Variables :: URLENCODED_ERROR - GET (1/7)",
|
||||
"client":{
|
||||
"ip":"200.249.12.31",
|
||||
"port":123
|
||||
},
|
||||
"server":{
|
||||
"ip":"200.249.12.31",
|
||||
"port":80
|
||||
},
|
||||
"request":{
|
||||
"headers":{
|
||||
"Host":"localhost",
|
||||
"User-Agent":"curl/7.38.0",
|
||||
"Accept":"*/*"
|
||||
},
|
||||
"uri":"/?key=value&key=other_value%2",
|
||||
"method":"GET"
|
||||
},
|
||||
"response":{
|
||||
"headers":{
|
||||
"Date":"Mon, 13 Jul 2015 20:02:41 GMT",
|
||||
"Last-Modified":"Sun, 26 Oct 2014 22:33:37 GMT",
|
||||
"Content-Type":"text/html"
|
||||
},
|
||||
"body":[
|
||||
"no need."
|
||||
]
|
||||
},
|
||||
"expected":{
|
||||
"debug_log":"Target value: \"1\" \\(Variable: URLENCODED_ERROR\\)"
|
||||
},
|
||||
"rules":[
|
||||
"SecRuleEngine On",
|
||||
"SecDebugLog \/tmp\/modsec_debug.log",
|
||||
"SecDebugLogLevel 9",
|
||||
"SecRule URLENCODED_ERROR \"@gt 10 \" \"id:1,pass\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"enabled":1,
|
||||
"version_min":300000,
|
||||
"title":"Testing Variables :: URLENCODED_ERROR - GET (2/7)",
|
||||
"client":{
|
||||
"ip":"200.249.12.31",
|
||||
"port":123
|
||||
},
|
||||
"server":{
|
||||
"ip":"200.249.12.31",
|
||||
"port":80
|
||||
},
|
||||
"request":{
|
||||
"headers":{
|
||||
"Host":"localhost",
|
||||
"User-Agent":"curl/7.38.0",
|
||||
"Accept":"*/*"
|
||||
},
|
||||
"uri":"/?key=value&key=other_value&a=b%2a",
|
||||
"method":"GET"
|
||||
},
|
||||
"response":{
|
||||
"headers":{
|
||||
"Date":"Mon, 13 Jul 2015 20:02:41 GMT",
|
||||
"Last-Modified":"Sun, 26 Oct 2014 22:33:37 GMT",
|
||||
"Content-Type":"text/html"
|
||||
},
|
||||
"body":[
|
||||
"no need."
|
||||
]
|
||||
},
|
||||
"expected":{
|
||||
"debug_log":"Target value: \"0\" \\(Variable: URLENCODED_ERROR\\)"
|
||||
},
|
||||
"rules":[
|
||||
"SecRuleEngine On",
|
||||
"SecDebugLog \/tmp\/modsec_debug.log",
|
||||
"SecDebugLogLevel 9",
|
||||
"SecRule URLENCODED_ERROR \"@gt 10 \" \"id:1,pass\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"enabled":1,
|
||||
"version_min":300000,
|
||||
"title":"Testing Variables :: URLENCODED_ERROR - POST (3/7)",
|
||||
"client":{
|
||||
"ip":"200.249.12.31",
|
||||
"port":123
|
||||
},
|
||||
"server":{
|
||||
"ip":"200.249.12.31",
|
||||
"port":80
|
||||
},
|
||||
"request":{
|
||||
"headers":{
|
||||
"Host":"localhost",
|
||||
"User-Agent":"curl/7.38.0",
|
||||
"Accept":"*/*",
|
||||
"Content-Length": "27",
|
||||
"Content-Type": "application/x-www-form-urlencoded"
|
||||
},
|
||||
"uri":"/",
|
||||
"method":"POST",
|
||||
"body": [
|
||||
"param1=value12%¶m2=value2%2"
|
||||
]
|
||||
},
|
||||
"response":{
|
||||
"headers":{
|
||||
"Date":"Mon, 13 Jul 2015 20:02:41 GMT",
|
||||
"Last-Modified":"Sun, 26 Oct 2014 22:33:37 GMT",
|
||||
"Content-Type":"text/html"
|
||||
},
|
||||
"body":[
|
||||
"no need."
|
||||
]
|
||||
},
|
||||
"expected":{
|
||||
"debug_log":"Target value: \"1\" \\(Variable: URLENCODED_ERROR\\)"
|
||||
},
|
||||
"rules":[
|
||||
"SecRuleEngine On",
|
||||
"SecDebugLog \/tmp\/modsec_debug.log",
|
||||
"SecDebugLogLevel 9",
|
||||
"SecRule URLENCODED_ERROR \"@gt 10 \" \"id:1,phase:3,pass\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"enabled":1,
|
||||
"version_min":300000,
|
||||
"title":"Testing Variables :: URLENCODED_ERROR - POST (4/7)",
|
||||
"client":{
|
||||
"ip":"200.249.12.31",
|
||||
"port":123
|
||||
},
|
||||
"server":{
|
||||
"ip":"200.249.12.31",
|
||||
"port":80
|
||||
},
|
||||
"request":{
|
||||
"headers":{
|
||||
"Host":"localhost",
|
||||
"User-Agent":"curl/7.38.0",
|
||||
"Accept":"*/*",
|
||||
"Content-Length": "28",
|
||||
"Content-Type": "application/x-www-form-urlencoded"
|
||||
},
|
||||
"uri":"/",
|
||||
"method":"POST",
|
||||
"body": [
|
||||
"param1=value1¶m2=value2&a=b5%2a\n"
|
||||
]
|
||||
},
|
||||
"response":{
|
||||
"headers":{
|
||||
"Date":"Mon, 13 Jul 2015 20:02:41 GMT",
|
||||
"Last-Modified":"Sun, 26 Oct 2014 22:33:37 GMT",
|
||||
"Content-Type":"text/html"
|
||||
},
|
||||
"body":[
|
||||
"no need."
|
||||
]
|
||||
},
|
||||
"expected":{
|
||||
"debug_log":"Target value: \"0\" \\(Variable: URLENCODED_ERROR\\)"
|
||||
},
|
||||
"rules":[
|
||||
"SecRuleEngine On",
|
||||
"SecDebugLog \/tmp\/modsec_debug.log",
|
||||
"SecDebugLogLevel 9",
|
||||
"SecRule URLENCODED_ERROR \"@gt 10 \" \"id:1,phase:3,pass,t:trim\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"enabled":1,
|
||||
"version_min":300000,
|
||||
"title":"Testing Variables :: URLENCODED_ERROR - POST (5/7)",
|
||||
"client":{
|
||||
"ip":"200.249.12.31",
|
||||
"port":123
|
||||
},
|
||||
"server":{
|
||||
"ip":"200.249.12.31",
|
||||
"port":80
|
||||
},
|
||||
"request":{
|
||||
"headers":{
|
||||
"Host":"localhost",
|
||||
"User-Agent":"curl/7.38.0",
|
||||
"Accept":"*/*",
|
||||
"Content-Length": "27",
|
||||
"Content-Type": "application/x-www-form-urlencoded"
|
||||
},
|
||||
"uri":"/",
|
||||
"method":"POST",
|
||||
"body": [
|
||||
"a=%EC%A7%84%20%EB%A7%88%EC%9D%BC%20%EB%A6%AC"
|
||||
]
|
||||
},
|
||||
"response":{
|
||||
"headers":{
|
||||
"Date":"Mon, 13 Jul 2015 20:02:41 GMT",
|
||||
"Last-Modified":"Sun, 26 Oct 2014 22:33:37 GMT",
|
||||
"Content-Type":"text/html"
|
||||
},
|
||||
"body":[
|
||||
"no need."
|
||||
]
|
||||
},
|
||||
"expected":{
|
||||
"debug_log":"Target value: \"0\" \\(Variable: URLENCODED_ERROR\\)"
|
||||
},
|
||||
"rules":[
|
||||
"SecRuleEngine On",
|
||||
"SecDebugLog \/tmp\/modsec_debug.log",
|
||||
"SecDebugLogLevel 9",
|
||||
"SecRule URLENCODED_ERROR \"@gt 10 \" \"id:1,phase:3,pass,t:trim\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"enabled":1,
|
||||
"version_min":300000,
|
||||
"title":"Testing Variables :: URLENCODED_ERROR - GET (6/7)",
|
||||
"client":{
|
||||
"ip":"200.249.12.31",
|
||||
"port":123
|
||||
},
|
||||
"server":{
|
||||
"ip":"200.249.12.31",
|
||||
"port":80
|
||||
},
|
||||
"request":{
|
||||
"headers":{
|
||||
"Host":"localhost",
|
||||
"User-Agent":"curl/7.38.0",
|
||||
"Accept":"*/*",
|
||||
"Content-Length": "27",
|
||||
"Content-Type": "application/x-www-form-urlencoded"
|
||||
},
|
||||
"uri":"/?z=%EC%A7%84%20%EB%A7%88%EC%9D%BC%20%EB%A6%A%AC",
|
||||
"method":"GET"
|
||||
},
|
||||
"response":{
|
||||
"headers":{
|
||||
"Date":"Mon, 13 Jul 2015 20:02:41 GMT",
|
||||
"Last-Modified":"Sun, 26 Oct 2014 22:33:37 GMT",
|
||||
"Content-Type":"text/html"
|
||||
},
|
||||
"body":[
|
||||
"no need."
|
||||
]
|
||||
},
|
||||
"expected":{
|
||||
"debug_log":"Target value: \"1\" \\(Variable: URLENCODED_ERROR\\)"
|
||||
},
|
||||
"rules":[
|
||||
"SecRuleEngine On",
|
||||
"SecDebugLog \/tmp\/modsec_debug.log",
|
||||
"SecDebugLogLevel 9",
|
||||
"SecRule URLENCODED_ERROR \"@gt 10 \" \"id:1,phase:3,pass,t:trim\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"enabled":1,
|
||||
"version_min":300000,
|
||||
"title":"Testing Variables :: URLENCODED_ERROR - GET (7/7)",
|
||||
"client":{
|
||||
"ip":"200.249.12.31",
|
||||
"port":123
|
||||
},
|
||||
"server":{
|
||||
"ip":"200.249.12.31",
|
||||
"port":80
|
||||
},
|
||||
"request":{
|
||||
"headers":{
|
||||
"Host":"localhost",
|
||||
"User-Agent":"curl/7.38.0",
|
||||
"Accept":"*/*",
|
||||
"Content-Length": "27",
|
||||
"Content-Type": "application/x-www-form-urlencoded"
|
||||
},
|
||||
"uri":"/?z=진 마일 리",
|
||||
"method":"GET"
|
||||
},
|
||||
"response":{
|
||||
"headers":{
|
||||
"Date":"Mon, 13 Jul 2015 20:02:41 GMT",
|
||||
"Last-Modified":"Sun, 26 Oct 2014 22:33:37 GMT",
|
||||
"Content-Type":"text/html"
|
||||
},
|
||||
"body":[
|
||||
"no need."
|
||||
]
|
||||
},
|
||||
"expected":{
|
||||
"debug_log":"Target value: \"0\" \\(Variable: URLENCODED_ERROR\\)"
|
||||
},
|
||||
"rules":[
|
||||
"SecRuleEngine On",
|
||||
"SecDebugLog \/tmp\/modsec_debug.log",
|
||||
"SecDebugLogLevel 9",
|
||||
"SecRule URLENCODED_ERROR \"@gt 10 \" \"id:1,phase:3,pass,t:trim\""
|
||||
]
|
||||
}
|
||||
]
|
||||
|
Loading…
x
Reference in New Issue
Block a user