Adds support to URLENCODED_ERROR variable

This commit is contained in:
Felipe Zimmerle 2016-06-17 20:41:07 -03:00
parent c5262d54f2
commit 6052d2628b
No known key found for this signature in database
GPG Key ID: E6DFB08CE8B11277
9 changed files with 406 additions and 69 deletions

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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)

View File

@ -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);
}
}

View File

@ -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.

View File

@ -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);

View File

@ -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",

View 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%&param2=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&param2=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\""
]
}
]