mirror of
https://github.com/owasp-modsecurity/ModSecurity.git
synced 2025-08-14 05:45:59 +03:00
Adds support to macro expansion in setvar action
This commit is contained in:
parent
e12d95b10d
commit
5fdb5b7d2e
@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
#include "modsecurity/assay.h"
|
#include "modsecurity/assay.h"
|
||||||
#include "src/rule.h"
|
#include "src/rule.h"
|
||||||
|
#include "src/macro_expansion.h"
|
||||||
|
|
||||||
namespace ModSecurity {
|
namespace ModSecurity {
|
||||||
namespace actions {
|
namespace actions {
|
||||||
@ -94,6 +95,7 @@ void SetVar::dump() {
|
|||||||
bool SetVar::evaluate(Rule *rule, Assay *assay) {
|
bool SetVar::evaluate(Rule *rule, Assay *assay) {
|
||||||
std::string targetValue;
|
std::string targetValue;
|
||||||
|
|
||||||
|
variableName = MacroExpansion::expand(variableName, assay);
|
||||||
int value = 0;
|
int value = 0;
|
||||||
try {
|
try {
|
||||||
std::string *resolvedValue =
|
std::string *resolvedValue =
|
||||||
@ -111,14 +113,16 @@ bool SetVar::evaluate(Rule *rule, Assay *assay) {
|
|||||||
try {
|
try {
|
||||||
pre = stoi(predicate);
|
pre = stoi(predicate);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
/* perform a macro expansion. */
|
try {
|
||||||
pre = 0;
|
pre = stoi(MacroExpansion::expand(predicate, assay));
|
||||||
|
} catch (...) {
|
||||||
|
pre = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (operation) {
|
switch (operation) {
|
||||||
case setOperation:
|
case setOperation:
|
||||||
/* perform a macro expansion. */
|
targetValue = MacroExpansion::expand(predicate, assay);
|
||||||
targetValue = predicate;
|
|
||||||
break;
|
break;
|
||||||
case sumAndSetOperation:
|
case sumAndSetOperation:
|
||||||
targetValue = std::to_string(value + pre);
|
targetValue = std::to_string(value + pre);
|
||||||
|
@ -1374,8 +1374,9 @@ std::string* Assay::resolve_variable_first(std::string var) {
|
|||||||
std::string* Assay::resolve_variable_first(const std::string collectionName,
|
std::string* Assay::resolve_variable_first(const std::string collectionName,
|
||||||
std::string var) {
|
std::string var) {
|
||||||
for (auto &a : collections) {
|
for (auto &a : collections) {
|
||||||
if (a.first == collectionName) {
|
if (tolower(a.first) == tolower(collectionName)) {
|
||||||
auto range = a.second->equal_range(collectionName + ":" + var);
|
auto range = a.second->equal_range(toupper(collectionName)
|
||||||
|
+ ":" + var);
|
||||||
for (auto it = range.first; it != range.second; ++it) {
|
for (auto it = range.first; it != range.second; ++it) {
|
||||||
return &it->second;
|
return &it->second;
|
||||||
}
|
}
|
||||||
@ -1391,8 +1392,8 @@ void Assay::setCollection(const std::string& collectionName,
|
|||||||
ModSecurityStringVariables *collection;
|
ModSecurityStringVariables *collection;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
collection = collections.at(collectionName);
|
collection = collections.at(toupper(collectionName));
|
||||||
collection->storeOrUpdateVariable(collectionName + ":"
|
collection->storeOrUpdateVariable(toupper(collectionName) + ":"
|
||||||
+ variableName, targetValue);
|
+ variableName, targetValue);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
debug(9, "don't know any collection named: "
|
debug(9, "don't know any collection named: "
|
||||||
|
@ -14,10 +14,43 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "src/macro_expansion.h"
|
#include "src/macro_expansion.h"
|
||||||
|
#include "modsecurity/assay.h"
|
||||||
|
|
||||||
namespace ModSecurity {
|
namespace ModSecurity {
|
||||||
|
|
||||||
MacroExpansion::MacroExpansion() {
|
MacroExpansion::MacroExpansion() { }
|
||||||
|
|
||||||
|
std::string MacroExpansion::expand(const std::string& input, Assay *assay) {
|
||||||
|
std::string res(input);
|
||||||
|
|
||||||
|
size_t pos = res.find("%{");
|
||||||
|
while (pos != std::string::npos) {
|
||||||
|
size_t start = pos;
|
||||||
|
size_t end = res.find("}%");
|
||||||
|
if (end == std::string::npos) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
std::string variable(res, start + 2, end - (start + 2));
|
||||||
|
std::string *variableValue;
|
||||||
|
size_t collection = variable.find(".");
|
||||||
|
if (collection == std::string::npos) {
|
||||||
|
variableValue = assay->resolve_variable_first(variable);
|
||||||
|
} else {
|
||||||
|
std::string col = std::string(variable, 0, collection);
|
||||||
|
std::string var = std::string(variable, collection + 1,
|
||||||
|
variable.length() - (collection + 1));
|
||||||
|
variableValue = assay->resolve_variable_first(col, var);
|
||||||
|
}
|
||||||
|
|
||||||
|
res.erase(start, end + 2);
|
||||||
|
if (variableValue != NULL) {
|
||||||
|
res.insert(start, *variableValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
pos = res.find("%{");
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ModSecurity
|
} // namespace ModSecurity
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "modsecurity/modsecurity.h"
|
#include "modsecurity/modsecurity.h"
|
||||||
|
#include "modsecurity/assay.h"
|
||||||
|
|
||||||
#ifndef SRC_MACRO_EXPANSION_H_
|
#ifndef SRC_MACRO_EXPANSION_H_
|
||||||
#define SRC_MACRO_EXPANSION_H_
|
#define SRC_MACRO_EXPANSION_H_
|
||||||
@ -29,6 +30,8 @@ namespace ModSecurity {
|
|||||||
class MacroExpansion {
|
class MacroExpansion {
|
||||||
public:
|
public:
|
||||||
MacroExpansion();
|
MacroExpansion();
|
||||||
|
|
||||||
|
static std::string expand(const std::string& input, Assay *assay);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
10
src/utils.cc
10
src/utils.cc
@ -112,6 +112,16 @@ std::string tolower(std::string str) {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string toupper(std::string str) {
|
||||||
|
std::locale loc;
|
||||||
|
std::string value;
|
||||||
|
|
||||||
|
for (std::string::size_type i=0; i < str.length(); ++i) {
|
||||||
|
value.assign(value + std::toupper(str[i], loc));
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
const char SAFE[256] = {
|
const char SAFE[256] = {
|
||||||
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
|
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
|
||||||
|
@ -32,6 +32,7 @@ namespace ModSecurity {
|
|||||||
void chomp(std::string *str);
|
void chomp(std::string *str);
|
||||||
std::string uri_decode(const std::string & sSrc);
|
std::string uri_decode(const std::string & sSrc);
|
||||||
std::string tolower(std::string str);
|
std::string tolower(std::string str);
|
||||||
|
std::string toupper(std::string str);
|
||||||
double cpu_seconds(void);
|
double cpu_seconds(void);
|
||||||
int js_decode_nonstrict_inplace(unsigned char *input, int64_t input_len);
|
int js_decode_nonstrict_inplace(unsigned char *input, int64_t input_len);
|
||||||
static unsigned char x2c(unsigned char *what);
|
static unsigned char x2c(unsigned char *what);
|
||||||
|
245
test/test-cases/regression/collection-tx-with-macro.json
Normal file
245
test/test-cases/regression/collection-tx-with-macro.json
Normal file
@ -0,0 +1,245 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"enabled":1,
|
||||||
|
"version_min":300000,
|
||||||
|
"version_max":0,
|
||||||
|
"title":"Testing collection :: TX (with macro) (1/4)",
|
||||||
|
"client":{
|
||||||
|
"ip":"200.249.12.31",
|
||||||
|
"port":2313
|
||||||
|
},
|
||||||
|
"server":{
|
||||||
|
"ip":"200.249.12.31",
|
||||||
|
"port":80
|
||||||
|
},
|
||||||
|
"request":{
|
||||||
|
"headers":{
|
||||||
|
"User-Agent":"Mozilla\/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko\/20091102 Firefox\/3.5.5 (.NET CLR 3.5.30729)",
|
||||||
|
"Accept":"text\/html,application\/xhtml+xml,application\/xml;q=0.9,*\/*;q=0.8",
|
||||||
|
"Accept-Language":"en-us,en;q=0.5",
|
||||||
|
"Accept-Encoding":"gzip,deflate",
|
||||||
|
"Accept-Charset":"ISO-8859-1,utf-8;q=0.7,*;q=0.7",
|
||||||
|
"Keep-Alive":"300",
|
||||||
|
"Connection":"keep-alive",
|
||||||
|
"Cookie":"PHPSESSID=rAAAAAAA2t5uvjq435r4q7ib3vtdjq120",
|
||||||
|
"Pragma":"no-cache",
|
||||||
|
"Cache-Control":"no-cache"
|
||||||
|
},
|
||||||
|
"uri":"\/test.pl?param1= test ¶m2=test2",
|
||||||
|
"protocol":"GET",
|
||||||
|
"http_version":1.1,
|
||||||
|
"body":""
|
||||||
|
},
|
||||||
|
"response":{
|
||||||
|
"headers":{
|
||||||
|
"Content-Type":"text\/xml; charset=utf-8\n\r",
|
||||||
|
"Content-Length":"length\n\r"
|
||||||
|
},
|
||||||
|
"body":[
|
||||||
|
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\r",
|
||||||
|
"<soap:Envelope xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\" xmlns:xsd=\"http:\/\/www.w3.org\/2001\/XMLSchema\" xmlns:soap=\"http:\/\/schemas.xmlsoap.org\/soap\/envelope\/\">\n\r",
|
||||||
|
" <soap:Body>\n\r",
|
||||||
|
" <EnlightenResponse xmlns=\"http:\/\/clearforest.com\/\">\n\r",
|
||||||
|
" <EnlightenResult>string<\/EnlightenResult>\n\r",
|
||||||
|
" <\/EnlightenResponse>\n\r",
|
||||||
|
" <\/soap:Body>\n\r",
|
||||||
|
"<\/soap:Envelope>\n\r"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"expected":{
|
||||||
|
"audit_log":"",
|
||||||
|
"debug_log":"Target value: \"PHPSESSID=rAAAAAAA2t5uvjq435r4q7ib3vtdjq120\" \\(Variable: TX:something\\)",
|
||||||
|
"error_log":""
|
||||||
|
},
|
||||||
|
"rules":[
|
||||||
|
"SecRuleEngine On",
|
||||||
|
"SecDebugLog \/tmp\/modsec_debug.log",
|
||||||
|
"SecDebugLogLevel 9",
|
||||||
|
"SecRule REQUEST_HEADERS \"@contains PHPSESSID\" \"t:lowercase,t:none,setvar:TX.something=%{REQUEST_HEADERS:Cookie}%\"",
|
||||||
|
"SecRule TX \"@contains to_test\" \"t:lowercase,t:none\""
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"enabled":1,
|
||||||
|
"version_min":300000,
|
||||||
|
"version_max":0,
|
||||||
|
"title":"Testing collection :: TX (with macro) (2/4)",
|
||||||
|
"client":{
|
||||||
|
"ip":"200.249.12.31",
|
||||||
|
"port":2313
|
||||||
|
},
|
||||||
|
"server":{
|
||||||
|
"ip":"200.249.12.31",
|
||||||
|
"port":80
|
||||||
|
},
|
||||||
|
"request":{
|
||||||
|
"headers":{
|
||||||
|
"User-Agent":"Mozilla\/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko\/20091102 Firefox\/3.5.5 (.NET CLR 3.5.30729)",
|
||||||
|
"Accept":"text\/html,application\/xhtml+xml,application\/xml;q=0.9,*\/*;q=0.8",
|
||||||
|
"Accept-Language":"en-us,en;q=0.5",
|
||||||
|
"Accept-Encoding":"gzip,deflate",
|
||||||
|
"Accept-Charset":"ISO-8859-1,utf-8;q=0.7,*;q=0.7",
|
||||||
|
"Keep-Alive":"300",
|
||||||
|
"Connection":"keep-alive",
|
||||||
|
"Cookie":"PHPSESSID=rAAAAAAA2t5uvjq435r4q7ib3vtdjq120",
|
||||||
|
"Pragma":"no-cache",
|
||||||
|
"Cache-Control":"no-cache"
|
||||||
|
},
|
||||||
|
"uri":"\/test.pl?param1= test ¶m2=test2",
|
||||||
|
"protocol":"GET",
|
||||||
|
"http_version":1.1,
|
||||||
|
"body":""
|
||||||
|
},
|
||||||
|
"response":{
|
||||||
|
"headers":{
|
||||||
|
"Content-Type":"text\/xml; charset=utf-8\n\r",
|
||||||
|
"Content-Length":"length\n\r"
|
||||||
|
},
|
||||||
|
"body":[
|
||||||
|
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\r",
|
||||||
|
"<soap:Envelope xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\" xmlns:xsd=\"http:\/\/www.w3.org\/2001\/XMLSchema\" xmlns:soap=\"http:\/\/schemas.xmlsoap.org\/soap\/envelope\/\">\n\r",
|
||||||
|
" <soap:Body>\n\r",
|
||||||
|
" <EnlightenResponse xmlns=\"http:\/\/clearforest.com\/\">\n\r",
|
||||||
|
" <EnlightenResult>string<\/EnlightenResult>\n\r",
|
||||||
|
" <\/EnlightenResponse>\n\r",
|
||||||
|
" <\/soap:Body>\n\r",
|
||||||
|
"<\/soap:Envelope>\n\r"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"expected":{
|
||||||
|
"audit_log":"",
|
||||||
|
"debug_log":"Target value: \"1\" \\(Variable: TX:somethingPHPSESSID=rAAAAAAA2t5uvjq435r4q7ib3vtdjq120\\)",
|
||||||
|
"error_log":""
|
||||||
|
},
|
||||||
|
"rules":[
|
||||||
|
"SecRuleEngine On",
|
||||||
|
"SecDebugLog \/tmp\/modsec_debug.log",
|
||||||
|
"SecDebugLogLevel 9",
|
||||||
|
"SecRule REQUEST_HEADERS \"@contains PHPSESSID\" \"t:lowercase,t:none,setvar:TX.something%{REQUEST_HEADERS:Cookie}%\"",
|
||||||
|
"SecRule TX \"@contains to_test\" \"t:lowercase,t:none\""
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"enabled":1,
|
||||||
|
"version_min":300000,
|
||||||
|
"version_max":0,
|
||||||
|
"title":"Testing collection :: TX (with macro) (3/4)",
|
||||||
|
"client":{
|
||||||
|
"ip":"200.249.12.31",
|
||||||
|
"port":2313
|
||||||
|
},
|
||||||
|
"server":{
|
||||||
|
"ip":"200.249.12.31",
|
||||||
|
"port":80
|
||||||
|
},
|
||||||
|
"request":{
|
||||||
|
"headers":{
|
||||||
|
"User-Agent":"Mozilla\/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko\/20091102 Firefox\/3.5.5 (.NET CLR 3.5.30729)",
|
||||||
|
"Accept":"text\/html,application\/xhtml+xml,application\/xml;q=0.9,*\/*;q=0.8",
|
||||||
|
"Accept-Language":"en-us,en;q=0.5",
|
||||||
|
"Accept-Encoding":"gzip,deflate",
|
||||||
|
"Accept-Charset":"ISO-8859-1,utf-8;q=0.7,*;q=0.7",
|
||||||
|
"Keep-Alive":"300",
|
||||||
|
"Connection":"keep-alive",
|
||||||
|
"Cookie":"PHPSESSID=rAAAAAAA2t5uvjq435r4q7ib3vtdjq120",
|
||||||
|
"Pragma":"no-cache",
|
||||||
|
"Cache-Control":"no-cache"
|
||||||
|
},
|
||||||
|
"uri":"\/test.pl?param1= test ¶m2=test2",
|
||||||
|
"protocol":"GET",
|
||||||
|
"http_version":1.1,
|
||||||
|
"body":""
|
||||||
|
},
|
||||||
|
"response":{
|
||||||
|
"headers":{
|
||||||
|
"Content-Type":"text\/xml; charset=utf-8\n\r",
|
||||||
|
"Content-Length":"length\n\r"
|
||||||
|
},
|
||||||
|
"body":[
|
||||||
|
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\r",
|
||||||
|
"<soap:Envelope xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\" xmlns:xsd=\"http:\/\/www.w3.org\/2001\/XMLSchema\" xmlns:soap=\"http:\/\/schemas.xmlsoap.org\/soap\/envelope\/\">\n\r",
|
||||||
|
" <soap:Body>\n\r",
|
||||||
|
" <EnlightenResponse xmlns=\"http:\/\/clearforest.com\/\">\n\r",
|
||||||
|
" <EnlightenResult>string<\/EnlightenResult>\n\r",
|
||||||
|
" <\/EnlightenResponse>\n\r",
|
||||||
|
" <\/soap:Body>\n\r",
|
||||||
|
"<\/soap:Envelope>\n\r"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"expected":{
|
||||||
|
"audit_log":"",
|
||||||
|
"debug_log":"Target value: \"310\" \\(Variable: TX:something\\)",
|
||||||
|
"error_log":""
|
||||||
|
},
|
||||||
|
"rules":[
|
||||||
|
"SecRuleEngine On",
|
||||||
|
"SecDebugLog \/tmp\/modsec_debug.log",
|
||||||
|
"SecDebugLogLevel 9",
|
||||||
|
"SecRule REQUEST_HEADERS \"@contains PHPSESSID\" \"t:lowercase,t:none,setvar:TX.something=%{REQUEST_HEADERS:Keep-Alive}%\"",
|
||||||
|
"SecRule REQUEST_HEADERS \"@contains PHPSESSID\" \"t:lowercase,t:none,setvar:TX.something=+10\"",
|
||||||
|
"SecRule TX \"@contains to_test\" \"t:lowercase,t:none\""
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"enabled":1,
|
||||||
|
"version_min":300000,
|
||||||
|
"version_max":0,
|
||||||
|
"title":"Testing collection :: TX (with macro) (4/4)",
|
||||||
|
"client":{
|
||||||
|
"ip":"200.249.12.31",
|
||||||
|
"port":2313
|
||||||
|
},
|
||||||
|
"server":{
|
||||||
|
"ip":"200.249.12.31",
|
||||||
|
"port":80
|
||||||
|
},
|
||||||
|
"request":{
|
||||||
|
"headers":{
|
||||||
|
"User-Agent":"Mozilla\/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko\/20091102 Firefox\/3.5.5 (.NET CLR 3.5.30729)",
|
||||||
|
"Accept":"text\/html,application\/xhtml+xml,application\/xml;q=0.9,*\/*;q=0.8",
|
||||||
|
"Accept-Language":"en-us,en;q=0.5",
|
||||||
|
"Accept-Encoding":"gzip,deflate",
|
||||||
|
"Accept-Charset":"ISO-8859-1,utf-8;q=0.7,*;q=0.7",
|
||||||
|
"Keep-Alive":"300",
|
||||||
|
"Connection":"keep-alive",
|
||||||
|
"Cookie":"PHPSESSID=rAAAAAAA2t5uvjq435r4q7ib3vtdjq120",
|
||||||
|
"Pragma":"no-cache",
|
||||||
|
"Cache-Control":"no-cache"
|
||||||
|
},
|
||||||
|
"uri":"\/test.pl?param1= test ¶m2=test2",
|
||||||
|
"protocol":"GET",
|
||||||
|
"http_version":1.1,
|
||||||
|
"body":""
|
||||||
|
},
|
||||||
|
"response":{
|
||||||
|
"headers":{
|
||||||
|
"Content-Type":"text\/xml; charset=utf-8\n\r",
|
||||||
|
"Content-Length":"length\n\r"
|
||||||
|
},
|
||||||
|
"body":[
|
||||||
|
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\r",
|
||||||
|
"<soap:Envelope xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\" xmlns:xsd=\"http:\/\/www.w3.org\/2001\/XMLSchema\" xmlns:soap=\"http:\/\/schemas.xmlsoap.org\/soap\/envelope\/\">\n\r",
|
||||||
|
" <soap:Body>\n\r",
|
||||||
|
" <EnlightenResponse xmlns=\"http:\/\/clearforest.com\/\">\n\r",
|
||||||
|
" <EnlightenResult>string<\/EnlightenResult>\n\r",
|
||||||
|
" <\/EnlightenResponse>\n\r",
|
||||||
|
" <\/soap:Body>\n\r",
|
||||||
|
"<\/soap:Envelope>\n\r"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"expected":{
|
||||||
|
"audit_log":"",
|
||||||
|
"debug_log":"Target value: \"5\" \\(Variable: TX:something_else\\)",
|
||||||
|
"error_log":""
|
||||||
|
},
|
||||||
|
"rules":[
|
||||||
|
"SecRuleEngine On",
|
||||||
|
"SecDebugLog \/tmp\/modsec_debug.log",
|
||||||
|
"SecDebugLogLevel 9",
|
||||||
|
"SecRule REQUEST_HEADERS \"@contains PHPSESSID\" \"t:lowercase,t:none,setvar:TX.something=+10\"",
|
||||||
|
"SecRule REQUEST_HEADERS \"@contains PHPSESSID\" \"t:lowercase,t:none,setvar:TX.something_else=%{tx.something}%\"",
|
||||||
|
"SecRule REQUEST_HEADERS \"@contains PHPSESSID\" \"t:lowercase,t:none,setvar:TX.something_else=-5\"",
|
||||||
|
"SecRule TX:something_else \"@contains to_test\" \"t:lowercase,t:none\""
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
Loading…
x
Reference in New Issue
Block a user