Merge pull request #2915 from martinhsv/v3/master

Fix: Lua scripts cannot read whole collection at once
This commit is contained in:
martinhsv 2023-06-13 17:27:23 -04:00 committed by GitHub
commit 85c8760774
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 248 additions and 163 deletions

View File

@ -1,6 +1,8 @@
v3.x.y - YYYY-MMM-DD (to be released)
-------------------------------------
- Fix: Lua scripts cannot read whole collection at once
[Issue #2900 - @udi-aharon, @airween, @martinhsv]
- Fix: quoted Include config with wildcard
[Issue #2905 - @wiseelf, @airween, @martinhsv]
- Support isolated PCRE match limits

View File

@ -179,167 +179,199 @@ class VariableMonkeyResolution {
static void stringMatchResolveMulti(Transaction *t,
const std::string &variable,
std::vector<const VariableValue *> *l) {
size_t collection = variable.find(".");
if (collection == std::string::npos) {
collection = variable.find(":");
size_t collection_delimiter_offset = variable.find(".");
if (collection_delimiter_offset == std::string::npos) {
collection_delimiter_offset = variable.find(":");
}
if (collection == std::string::npos) {
if (comp(variable, "RESPONSE_CONTENT_TYPE")) {
t->m_variableResponseContentType.evaluate(l);
} else if (comp(variable, "ARGS_COMBINED_SIZE")) {
t->m_variableARGScombinedSize.evaluate(l);
} else if (comp(variable, "AUTH_TYPE")) {
t->m_variableAuthType.evaluate(l);
} else if (comp(variable, "FILES_COMBINED_SIZE")) {
t->m_variableFilesCombinedSize.evaluate(l);
} else if (comp(variable, "FULL_REQUEST")) {
t->m_variableFullRequest.evaluate(l);
} else if (comp(variable, "FULL_REQUEST_LENGTH")) {
t->m_variableFullRequestLength.evaluate(l);
} else if (comp(variable, "INBOUND_DATA_ERROR")) {
t->m_variableInboundDataError.evaluate(l);
} else if (comp(variable, "MATCHED_VAR")) {
t->m_variableMatchedVar.evaluate(l);
} else if (comp(variable, "MATCHED_VAR_NAME")) {
t->m_variableMatchedVarName.evaluate(l);
} else if (comp(variable, "MSC_PCRE_ERROR")) {
t->m_variableMscPcreError.evaluate(l);
} else if (comp(variable, "MSC_PCRE_LIMITS_EXCEEDED")) {
t->m_variableMscPcreLimitsExceeded.evaluate(l);
} else if (comp(variable, "MULTIPART_CRLF_LF_LINES")) {
t->m_variableMultipartCrlfLFLines.evaluate(l);
} else if (comp(variable, "MULTIPART_DATA_AFTER")) {
t->m_variableMultipartDataAfter.evaluate(l);
} else if (comp(variable, "MULTIPART_FILE_LIMIT_EXCEEDED")) {
t->m_variableMultipartFileLimitExceeded.evaluate(l);
} else if (comp(variable, "MULTIPART_STRICT_ERROR")) {
t->m_variableMultipartStrictError.evaluate(l);
} else if (comp(variable, "MULTIPART_HEADER_FOLDING")) {
t->m_variableMultipartHeaderFolding.evaluate(l);
} else if (comp(variable, "MULTIPART_INVALID_QUOTING")) {
t->m_variableMultipartInvalidQuoting.evaluate(l);
} else if (comp(variable, "MULTIPART_INVALID_HEADER_FOLDING")) {
t->m_variableMultipartInvalidHeaderFolding.evaluate(l);
} else if (comp(variable, "MULTIPART_UNMATCHED_BOUNDARY")) {
t->m_variableMultipartUnmatchedBoundary.evaluate(l);
} else if (comp(variable, "OUTBOUND_DATA_ERROR")) {
t->m_variableOutboundDataError.evaluate(l);
} else if (comp(variable, "PATH_INFO")) {
t->m_variablePathInfo.evaluate(l);
} else if (comp(variable, "QUERY_STRING")) {
t->m_variableQueryString.evaluate(l);
} else if (comp(variable, "REMOTE_ADDR")) {
t->m_variableRemoteAddr.evaluate(l);
} else if (comp(variable, "REMOTE_HOST")) {
t->m_variableRemoteHost.evaluate(l);
} else if (comp(variable, "REMOTE_PORT")) {
t->m_variableRemotePort.evaluate(l);
} else if (comp(variable, "REQBODY_ERROR")) {
t->m_variableReqbodyError.evaluate(l);
} else if (comp(variable, "REQBODY_ERROR_MSG")) {
t->m_variableReqbodyErrorMsg.evaluate(l);
} else if (comp(variable, "REQBODY_PROCESSOR_ERROR_MSG")) {
t->m_variableReqbodyProcessorErrorMsg.evaluate(l);
} else if (comp(variable, "REQBODY_PROCESSOR_ERROR")) {
t->m_variableReqbodyProcessorError.evaluate(l);
} else if (comp(variable, "REQBODY_PROCESSOR")) {
t->m_variableReqbodyProcessor.evaluate(l);
} else if (comp(variable, "REQUEST_BASENAME")) {
t->m_variableRequestBasename.evaluate(l);
} else if (comp(variable, "REQUEST_BODY")) {
t->m_variableRequestBody.evaluate(l);
} else if (comp(variable, "REQUEST_BODY_LENGTH")) {
t->m_variableRequestBodyLength.evaluate(l);
} else if (comp(variable, "REQUEST_FILENAME")) {
t->m_variableRequestFilename.evaluate(l);
} else if (comp(variable, "REQUEST_LINE")) {
t->m_variableRequestLine.evaluate(l);
} else if (comp(variable, "REQUEST_METHOD")) {
t->m_variableRequestMethod.evaluate(l);
} else if (comp(variable, "REQUEST_PROTOCOL")) {
t->m_variableRequestProtocol.evaluate(l);
} else if (comp(variable, "REQUEST_URI")) {
t->m_variableRequestURI.evaluate(l);
} else if (comp(variable, "REQUEST_URI_RAW")) {
t->m_variableRequestURIRaw.evaluate(l);
} else if (comp(variable, "RESOURCE")) {
t->m_variableResource.evaluate(l);
} else if (comp(variable, "RESPONSE_BODY")) {
t->m_variableResponseBody.evaluate(l);
} else if (comp(variable, "RESPONSE_CONTENT_LENGTH")) {
t->m_variableResponseContentLength.evaluate(l);
} else if (comp(variable, "RESPONSE_PROTOCOL")) {
t->m_variableResponseProtocol.evaluate(l);
} else if (comp(variable, "RESPONSE_STATUS")) {
t->m_variableResponseStatus.evaluate(l);
} else if (comp(variable, "SERVER_ADDR")) {
t->m_variableServerAddr.evaluate(l);
} else if (comp(variable, "SERVER_NAME")) {
t->m_variableServerName.evaluate(l);
} else if (comp(variable, "SERVER_PORT")) {
t->m_variableServerPort.evaluate(l);
} else if (comp(variable, "SESSIONID")) {
t->m_variableSessionID.evaluate(l);
} else if (comp(variable, "UNIQUE_ID")) {
t->m_variableUniqueID.evaluate(l);
} else if (comp(variable, "URLENCODED_ERROR")) {
t->m_variableUrlEncodedError.evaluate(l);
} else if (comp(variable, "USERID")) {
t->m_variableUserID.evaluate(l);
} else {
throw std::invalid_argument("Variable not found.");
}
std::string col; // collection name excluding individual variable specification
std::string var; // variable within the collection
if (collection_delimiter_offset == std::string::npos) {
col = variable;
} else {
std::string col = std::string(variable, 0, collection);
std::string var = std::string(variable, collection + 1,
variable.length() - (collection + 1));
if (comp(col, "ARGS")) {
t->m_variableArgs.resolve(var, l);
} else if (comp(variable, "ARGS_NAMES")) {
t->m_variableArgsNames.resolve(var, l);
} else if (comp(variable, "ARGS_GET_NAMES")) {
t->m_variableArgsGetNames.resolve(var, l);
} else if (comp(variable, "ARGS_POST_NAMES")) {
t->m_variableArgsPostNames.resolve(var, l);
} else if (comp(col, "ARGS_GET")) {
t->m_variableArgsGet.resolve(var, l);
} else if (comp(col, "ARGS_POST")) {
t->m_variableArgsPost.resolve(var, l);
} else if (comp(col, "FILES_SIZES")) {
t->m_variableFilesSizes.resolve(var, l);
} else if (comp(col, "FILES_NAMES")) {
t->m_variableFilesNames.resolve(var, l);
} else if (comp(col, "FILES_TMP_CONTENT")) {
t->m_variableFilesTmpContent.resolve(var, l);
} else if (comp(col, "MULTIPART_FILENAME")) {
t->m_variableMultipartFileName.resolve(var, l);
} else if (comp(col, "MULTIPART_NAME")) {
t->m_variableMultipartName.resolve(var, l);
} else if (comp(col, "MATCHED_VARS_NAMES")) {
t->m_variableMatchedVarsNames.resolve(var, l);
} else if (comp(col, "MATCHED_VARS")) {
t->m_variableMatchedVars.resolve(var, l);
} else if (comp(col, "FILES")) {
t->m_variableFiles.resolve(var, l);
} else if (comp(col, "REQUEST_COOKIES")) {
t->m_variableRequestCookies.resolve(var, l);
} else if (comp(col, "REQUEST_HEADERS")) {
t->m_variableRequestHeaders.resolve(var, l);
} else if (comp(variable, "REQUEST_HEADERS_NAMES")) {
t->m_variableRequestHeadersNames.resolve(var, l);
} else if (comp(col, "RESPONSE_HEADERS")) {
t->m_variableResponseHeaders.resolve(var, l);
} else if (comp(variable, "RESPONSE_HEADERS_NAMES")) {
t->m_variableResponseHeadersNames.resolve(var, l);
} else if (comp(col, "GEO")) {
t->m_variableGeo.resolve(var, l);
} else if (comp(col, "REQUEST_COOKIES_NAMES")) {
t->m_variableRequestCookiesNames.resolve(var, l);
} else if (comp(col, "FILES_TMPNAMES")) {
t->m_variableFilesTmpNames.resolve(var, l);
col = std::string(variable, 0, collection_delimiter_offset);
var = std::string(variable, collection_delimiter_offset + 1,
variable.length() - (collection_delimiter_offset + 1));
}
// First check if the request is for a collection of type AnchoredSetVariable
AnchoredSetVariable* anchoredSetVariable = NULL;
if (comp(col, "ARGS")) {
anchoredSetVariable = &t->m_variableArgs;
} else if (comp(col, "ARGS_GET")) {
anchoredSetVariable = &t->m_variableArgsGet;
} else if (comp(col, "ARGS_POST")) {
anchoredSetVariable = &t->m_variableArgsPost;
} else if (comp(col, "FILES_SIZES")) {
anchoredSetVariable = &t->m_variableFilesSizes;
} else if (comp(col, "FILES_NAMES")) {
anchoredSetVariable = &t->m_variableFilesNames;
} else if (comp(col, "FILES_TMP_CONTENT")) {
anchoredSetVariable = &t->m_variableFilesTmpContent;
} else if (comp(col, "MULTIPART_FILENAME")) {
anchoredSetVariable = &t->m_variableMultipartFileName;
} else if (comp(col, "MULTIPART_NAME")) {
anchoredSetVariable = &t->m_variableMultipartName;
} else if (comp(col, "MATCHED_VARS_NAMES")) {
anchoredSetVariable = &t->m_variableMatchedVarsNames;
} else if (comp(col, "MATCHED_VARS")) {
anchoredSetVariable = &t->m_variableMatchedVars;
} else if (comp(col, "FILES")) {
anchoredSetVariable = &t->m_variableFiles;
} else if (comp(col, "REQUEST_COOKIES")) {
anchoredSetVariable = &t->m_variableRequestCookies;
} else if (comp(col, "REQUEST_HEADERS")) {
anchoredSetVariable = &t->m_variableRequestHeaders;
} else if (comp(variable, "REQUEST_HEADERS_NAMES")) {
anchoredSetVariable = &t->m_variableRequestHeadersNames;
} else if (comp(col, "RESPONSE_HEADERS")) {
anchoredSetVariable = &t->m_variableResponseHeaders;
} else if (comp(variable, "RESPONSE_HEADERS_NAMES")) {
anchoredSetVariable = &t->m_variableResponseHeadersNames;
} else if (comp(col, "GEO")) {
anchoredSetVariable = &t->m_variableGeo;
} else if (comp(col, "REQUEST_COOKIES_NAMES")) {
anchoredSetVariable = &t->m_variableRequestCookiesNames;
} else if (comp(col, "FILES_TMPNAMES")) {
anchoredSetVariable = &t->m_variableFilesTmpNames;
}
if (anchoredSetVariable != NULL) {
if (collection_delimiter_offset == std::string::npos) {
anchoredSetVariable->resolve(l);
} else {
throw std::invalid_argument("Variable not found.");
anchoredSetVariable->resolve(var, l);
}
return;
}
// Next check for collection of type AnchoredSetVariableTranslationProxy
AnchoredSetVariableTranslationProxy* anchoredSetVariableTranslationProxy = NULL;
if (comp(col, "ARGS_NAMES")) {
anchoredSetVariableTranslationProxy = &t->m_variableArgsNames;
} else if (comp(col, "ARGS_GET_NAMES")) {
anchoredSetVariableTranslationProxy = &t->m_variableArgsGetNames;
} else if (comp(col, "ARGS_POST_NAMES")) {
anchoredSetVariableTranslationProxy = &t->m_variableArgsPostNames;
}
if (anchoredSetVariableTranslationProxy != NULL) {
if (collection_delimiter_offset == std::string::npos) {
anchoredSetVariableTranslationProxy->resolve(l);
} else {
anchoredSetVariableTranslationProxy->resolve(var, l);
}
return;
}
// It could still be a non-collection variable, but in that case
// there should not be a request for a variable-within-a-collection
if (collection_delimiter_offset != std::string::npos) {
throw std::invalid_argument("Variable not found.");
}
if (comp(variable, "RESPONSE_CONTENT_TYPE")) {
t->m_variableResponseContentType.evaluate(l);
} else if (comp(variable, "ARGS_COMBINED_SIZE")) {
t->m_variableARGScombinedSize.evaluate(l);
} else if (comp(variable, "AUTH_TYPE")) {
t->m_variableAuthType.evaluate(l);
} else if (comp(variable, "FILES_COMBINED_SIZE")) {
t->m_variableFilesCombinedSize.evaluate(l);
} else if (comp(variable, "FULL_REQUEST")) {
t->m_variableFullRequest.evaluate(l);
} else if (comp(variable, "FULL_REQUEST_LENGTH")) {
t->m_variableFullRequestLength.evaluate(l);
} else if (comp(variable, "INBOUND_DATA_ERROR")) {
t->m_variableInboundDataError.evaluate(l);
} else if (comp(variable, "MATCHED_VAR")) {
t->m_variableMatchedVar.evaluate(l);
} else if (comp(variable, "MATCHED_VAR_NAME")) {
t->m_variableMatchedVarName.evaluate(l);
} else if (comp(variable, "MSC_PCRE_ERROR")) {
t->m_variableMscPcreError.evaluate(l);
} else if (comp(variable, "MSC_PCRE_LIMITS_EXCEEDED")) {
t->m_variableMscPcreLimitsExceeded.evaluate(l);
} else if (comp(variable, "MULTIPART_CRLF_LF_LINES")) {
t->m_variableMultipartCrlfLFLines.evaluate(l);
} else if (comp(variable, "MULTIPART_DATA_AFTER")) {
t->m_variableMultipartDataAfter.evaluate(l);
} else if (comp(variable, "MULTIPART_FILE_LIMIT_EXCEEDED")) {
t->m_variableMultipartFileLimitExceeded.evaluate(l);
} else if (comp(variable, "MULTIPART_STRICT_ERROR")) {
t->m_variableMultipartStrictError.evaluate(l);
} else if (comp(variable, "MULTIPART_HEADER_FOLDING")) {
t->m_variableMultipartHeaderFolding.evaluate(l);
} else if (comp(variable, "MULTIPART_INVALID_QUOTING")) {
t->m_variableMultipartInvalidQuoting.evaluate(l);
} else if (comp(variable, "MULTIPART_INVALID_HEADER_FOLDING")) {
t->m_variableMultipartInvalidHeaderFolding.evaluate(l);
} else if (comp(variable, "MULTIPART_UNMATCHED_BOUNDARY")) {
t->m_variableMultipartUnmatchedBoundary.evaluate(l);
} else if (comp(variable, "OUTBOUND_DATA_ERROR")) {
t->m_variableOutboundDataError.evaluate(l);
} else if (comp(variable, "PATH_INFO")) {
t->m_variablePathInfo.evaluate(l);
} else if (comp(variable, "QUERY_STRING")) {
t->m_variableQueryString.evaluate(l);
} else if (comp(variable, "REMOTE_ADDR")) {
t->m_variableRemoteAddr.evaluate(l);
} else if (comp(variable, "REMOTE_HOST")) {
t->m_variableRemoteHost.evaluate(l);
} else if (comp(variable, "REMOTE_PORT")) {
t->m_variableRemotePort.evaluate(l);
} else if (comp(variable, "REQBODY_ERROR")) {
t->m_variableReqbodyError.evaluate(l);
} else if (comp(variable, "REQBODY_ERROR_MSG")) {
t->m_variableReqbodyErrorMsg.evaluate(l);
} else if (comp(variable, "REQBODY_PROCESSOR_ERROR_MSG")) {
t->m_variableReqbodyProcessorErrorMsg.evaluate(l);
} else if (comp(variable, "REQBODY_PROCESSOR_ERROR")) {
t->m_variableReqbodyProcessorError.evaluate(l);
} else if (comp(variable, "REQBODY_PROCESSOR")) {
t->m_variableReqbodyProcessor.evaluate(l);
} else if (comp(variable, "REQUEST_BASENAME")) {
t->m_variableRequestBasename.evaluate(l);
} else if (comp(variable, "REQUEST_BODY")) {
t->m_variableRequestBody.evaluate(l);
} else if (comp(variable, "REQUEST_BODY_LENGTH")) {
t->m_variableRequestBodyLength.evaluate(l);
} else if (comp(variable, "REQUEST_FILENAME")) {
t->m_variableRequestFilename.evaluate(l);
} else if (comp(variable, "REQUEST_LINE")) {
t->m_variableRequestLine.evaluate(l);
} else if (comp(variable, "REQUEST_METHOD")) {
t->m_variableRequestMethod.evaluate(l);
} else if (comp(variable, "REQUEST_PROTOCOL")) {
t->m_variableRequestProtocol.evaluate(l);
} else if (comp(variable, "REQUEST_URI")) {
t->m_variableRequestURI.evaluate(l);
} else if (comp(variable, "REQUEST_URI_RAW")) {
t->m_variableRequestURIRaw.evaluate(l);
} else if (comp(variable, "RESOURCE")) {
t->m_variableResource.evaluate(l);
} else if (comp(variable, "RESPONSE_BODY")) {
t->m_variableResponseBody.evaluate(l);
} else if (comp(variable, "RESPONSE_CONTENT_LENGTH")) {
t->m_variableResponseContentLength.evaluate(l);
} else if (comp(variable, "RESPONSE_PROTOCOL")) {
t->m_variableResponseProtocol.evaluate(l);
} else if (comp(variable, "RESPONSE_STATUS")) {
t->m_variableResponseStatus.evaluate(l);
} else if (comp(variable, "SERVER_ADDR")) {
t->m_variableServerAddr.evaluate(l);
} else if (comp(variable, "SERVER_NAME")) {
t->m_variableServerName.evaluate(l);
} else if (comp(variable, "SERVER_PORT")) {
t->m_variableServerPort.evaluate(l);
} else if (comp(variable, "SESSIONID")) {
t->m_variableSessionID.evaluate(l);
} else if (comp(variable, "UNIQUE_ID")) {
t->m_variableUniqueID.evaluate(l);
} else if (comp(variable, "URLENCODED_ERROR")) {
t->m_variableUrlEncodedError.evaluate(l);
} else if (comp(variable, "USERID")) {
t->m_variableUserID.evaluate(l);
} else {
throw std::invalid_argument("Variable not found.");
}
}

View File

@ -0,0 +1,13 @@
function main()
local d = m.getvars("ARGS");
local size = #d;
m.log(9,"ARGS count read =" .. tostring(size));
ret = nil
if ( #d == 2 ) then
return nil
end
return "Unexpected result"
end

View File

@ -2,7 +2,7 @@
{
"enabled":1,
"version_min":300000,
"title":"Testing LUA :: m.set TX (1/6)",
"title":"Testing LUA :: m.set TX (1/7)",
"resource":"lua",
"client":{
"ip":"200.249.12.31",
@ -44,7 +44,7 @@
{
"enabled":1,
"version_min":300000,
"title":"Testing LUA :: m.set IP (2/6)",
"title":"Testing LUA :: m.set IP (2/7)",
"resource":"lua",
"client":{
"ip":"200.249.12.31",
@ -86,7 +86,7 @@
{
"enabled":1,
"version_min":300000,
"title":"Testing LUA :: m.set GLOBAL (3/6)",
"title":"Testing LUA :: m.set GLOBAL (3/7)",
"resource":"lua",
"client":{
"ip":"200.249.12.31",
@ -128,7 +128,7 @@
{
"enabled":1,
"version_min":300000,
"title":"Testing LUA :: m.set RESOURCE (4/6)",
"title":"Testing LUA :: m.set RESOURCE (4/7)",
"resource":"lua",
"client":{
"ip":"200.249.12.31",
@ -170,7 +170,7 @@
{
"enabled":1,
"version_min":300000,
"title":"Testing LUA :: m.set SESSION (5/6)",
"title":"Testing LUA :: m.set SESSION (5/7)",
"resource":"lua",
"client":{
"ip":"200.249.12.31",
@ -212,7 +212,7 @@
{
"enabled":1,
"version_min":300000,
"title":"Testing LUA :: m.set USER (6/6)",
"title":"Testing LUA :: m.set USER (6/7)",
"resource":"lua",
"client":{
"ip":"200.249.12.31",
@ -250,5 +250,43 @@
"SecRuleScript test-cases/data/setvar.lua \"id:2,pass\"",
"SecRule USER.lua_set_var \"@contains 2\" \"id:3,t:none\""
]
},
{
"enabled":1,
"version_min":300000,
"title":"Testing LUA :: m.getvars ARGS (8/8)",
"resource":"lua",
"client":{
"ip":"200.249.12.31",
"port":123
},
"server":{
"ip":"200.249.12.31",
"port":80
},
"request":{
"headers":{
"Host":"localhost",
"User-Agent":"My sweet little browser",
"Accept":"*/*",
"Content-Length": "0"
},
"uri":"/whee?parm1=a&parm2=b",
"method":"GET",
"body": [ ]
},
"response":{
"headers":{},
"body":[
"no need."
]
},
"expected":{
"http_code": 200
},
"rules":[
"SecRuleEngine On",
"SecRuleScript test-cases/data/match-getvars-args.lua \"id:2,phase:2,deny,status:403\""
]
}
]