Squashed 'src/deps/src/modsecurity/' changes from 205dac0e8..ccc2d9b53

ccc2d9b53 Change release version to v3.0.10
092921d87 Merge pull request #2934 from martinhsv/v3/master
ab5658f2d Fix: worst-case time in implementation of four transformations
3f0971666 CHANGES entry for previous PR
fea6e6d60 Merge pull request #2901 from airween/v3/pcrelimittx
2cb6344bf Merge pull request #2916 from martinhsv/v3/master
f812a3d72 Make MULTIPART_PART_HEADERS accessible to lua
85c876077 Merge pull request #2915 from martinhsv/v3/master
63bbf624d Remove check-static from macos builds
b8e1aedef Fix: Lua scripts cannot read whole collection at once
b84f32d6f Merge pull request #2909 from martinhsv/v3/master
938707d11 Fix: quoted Include config with wildcard
4403a163c Set TX:MSC_PCRE_LIMITS_EXCEEDED variable is limits exceeded
2121938c5 Change some parms to reference-to-const to satisfy cppcheck
da8782ce7 Minor whitespace adjustment
fdeaf17c6 CHANGES entry for previous PR
1ca282a5e Add exclusions due to newer cppcheck version
f8ec87337 github workflow: update macos version to macos-11
09a135baa Merge pull request #2736 from brandonpayton/add-regex-match-limits-and-error-reporting
62bbd7b07 Correction to previous cppcheck suppression adjustment
95c7009b8 Add cppcheck suppressions
1078a7cfa Change some parms from pass-by-value to reference-to-const
8d91a5084 github workflow: toggle pcre2 instead of ssdeep in Ubuntu tests
4fac8d72f Address some constParameter complaints from cppcheck
e9277e199 CHANGES entry for previous PR
4050c840f Merge pull request #2868 from grnet/v3/fix-multimatch-chain
12add9aef Fix meta-actions not being applied if multiMatch is enabled in the chain starter rule
808148ce0 CHANGES entry and cppcheck suppression adjustment for prev PR
5b709d9da Merge pull request #2866 from grnet/v3/fix-multimatch-tags
7ca571952 CHANGES entry for previous PR
7cf0445ad Merge pull request #2870 from airween/v3/multipartpartheaderfix
6623c0ae2 Changed strip methodology to MULTIPART_PART_HEADERS
6fbdee9ff Merge branch 'v3/master' of https://github.com/SpiderLabs/ModSecurity into v3/multipartpartheaderfix
a830ef634 Merge pull request #2894 from martinhsv/v3/master
8d62ac4b0 Configure: use AS_ECHO_N instead echo -n
6fc270e22 Merge pull request #2891 from martinhsv/v3/master
b9eb39af8 Adjust position of memset from 2890
09568351d CHANGES entry for previous PR
5365a17c5 Merge pull request #2846 from tomsommer/patch-1
f8db5fc85 Remove no-longer-needed cppcheck suppressions
a5320add2 Refactoring: remove two unneeded local vars from multipart parser
9ea50a497 Change arg from pass-by-value (satisify cppcheck)
c34bd91a4 CHANGES: Preparing for next version
d875738bd Add PCRE error tests for rx operator
6f1bd27fe Move var into conditional block where used
23a0e2617 Give PCRE error vars initial value
f3d8198b8 Respond to code review feedback
0c42ee229 Switch to simpler PCRE error flags
8c4b7c18e Fix some style issues in regex util header
8c269d31c Update Regex util to support match limits
18adbb6fd Merge branch 'v3/master' of https://github.com/SpiderLabs/ModSecurity into v3/multipartpartheaderfix
0a296af37 Add regression test case
514abeb51 Remove EOL chars from MULTIPART_PART_HEADER variable
d3a6b6a6f Fix tags not being populated in audit log when multiMatch is enabled
3caac9942 Also test empty lines

git-subtree-dir: src/deps/src/modsecurity
git-subtree-split: ccc2d9b53632fb5088673bbaafedf0d8d4b5f1d8
This commit is contained in:
Théophile Diot 2023-09-15 14:07:48 +02:00
parent a75b90f525
commit e0a89a2fcd
44 changed files with 8637 additions and 7832 deletions

View file

@ -18,7 +18,7 @@ jobs:
- {label: "wo yajl", opt: "--without-yajl" }
- {label: "wo geoip", opt: "--without-geoip" }
- {label: "wo lmdb", opt: "--without-lmdb" }
- {label: "wo ssdeep", opt: "--without-ssdeep" }
- {label: "with pcre2", opt: "--with-pcre2" }
- {label: "wo lua", opt: "--without-lua" }
- {label: "without maxmind", opt: "--without-maxmind" }
steps:
@ -26,7 +26,7 @@ jobs:
run: |
sudo add-apt-repository --yes ppa:maxmind/ppa
sudo apt-get update -y -qq
sudo apt-get install -y libfuzzy-dev libyajl-dev libgeoip-dev liblua5.2-dev liblmdb-dev cppcheck libmaxminddb-dev libcurl4-openssl-dev
sudo apt-get install -y libfuzzy-dev libyajl-dev libgeoip-dev liblua5.2-dev liblmdb-dev cppcheck libmaxminddb-dev libcurl4-openssl-dev libpcre2-dev pcre2-utils
- uses: actions/checkout@v2
with:
submodules: true
@ -46,7 +46,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [macos-10.15]
os: [macos-11]
compiler: [clang]
configure:
- {label: "with parser generation", opt: "--enable-parser-generation" }
@ -73,5 +73,3 @@ jobs:
run: make -j `sysctl -n hw.logicalcpu`
- name: check
run: make check
- name: check-static
run: make check-static

29
CHANGES
View file

@ -1,3 +1,32 @@
v3.0.10 - 2023-Jul-25
---------------------
- Fix: worst-case time in implementation of four transformations
[Issue #2934 - @martinhsv]
- Add TX synonym for MSC_PCRE_LIMITS_EXCEEDED
[Issue #2901 - @airween]
- Make MULTIPART_PART_HEADERS accessible to lua
[Issue #2916 - @martinhsv]
- 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
[Issue #2736 - @brandonpayton, @martinhsv]
- Fix: meta actions not applied if multiMatch in first rule of chain
[Issue #2867, #2868 - @mlevogiannis, @martinhsv]
- Fix: audit log may omit tags when multiMatch
[Issue #2866 - @mlevogiannis]
- Exclude CRLF from MULTIPART_PART_HEADER value
[Issue #2870 - @airween, @martinhsv]
- Configure: use AS_ECHO_N instead echo -n
[Issue #2894 - @liudongmiao, @martinhsv]
- Adjust position of memset from 2890
[Issue #2891 - @mirkodziadzka-avi, @martinhsv]
- Add test: empty lines in ipMatchFromFile test
[Issue #2846 - @tomsommer]
v3.0.9 - 2023-Apr-12
--------------------

View file

@ -424,9 +424,9 @@ echo " "
echo "ModSecurity - ${MSC_GIT_VERSION} for $PLATFORM"
echo " "
echo " Mandatory dependencies"
echo -n " + libInjection ...."
AS_ECHO_N(" + libInjection ....")
echo LIBINJECTION_VERSION
echo -n " + SecLang tests ...."
AS_ECHO_N(" + SecLang tests ....")
echo SECLANG_TEST_VERSION
echo " "
@ -439,7 +439,7 @@ if test "x$GEOIP_FOUND" = "x0" && test "x$MAXMIND_FOUND" = "x0"; then
echo " + GeoIP/MaxMind ....not found"
fi
if test "x$GEOIP_FOUND" = "x1" || test "x$MAXMIND_FOUND" = "x1"; then
echo -n " + GeoIP/MaxMind ....found "
AS_ECHO_N(" + GeoIP/MaxMind ....found ")
echo ""
if test "x$MAXMIND_FOUND" = "x1"; then
echo " * (MaxMind) v${MAXMIND_VERSION}"
@ -460,7 +460,7 @@ if test "x$CURL_FOUND" = "x0"; then
echo " + LibCURL ....not found"
fi
if test "x$CURL_FOUND" = "x1"; then
echo -n " + LibCURL ....found "
AS_ECHO_N(" + LibCURL ....found ")
if ! test "x$CURL_VERSION" = "x"; then
echo "v${CURL_VERSION}"
else
@ -478,7 +478,7 @@ if test "x$YAJL_FOUND" = "x0"; then
echo " + YAJL ....not found"
fi
if test "x$YAJL_FOUND" = "x1"; then
echo -n " + YAJL ....found "
AS_ECHO_N(" + YAJL ....found ")
if ! test "x$YAJL_VERSION" = "x"; then
echo "v${YAJL_VERSION}"
else
@ -496,7 +496,7 @@ if test "x$LMDB_FOUND" = "x0"; then
echo " + LMDB ....not found"
fi
if test "x$LMDB_FOUND" = "x1"; then
echo -n " + LMDB ....found "
AS_ECHO_N(" + LMDB ....found ")
if ! test "x$LMDB_VERSION" = "x"; then
echo "v${LMDB_VERSION}"
else
@ -514,7 +514,7 @@ if test "x$LIBXML2_FOUND" = "x0"; then
echo " + LibXML2 ....not found"
fi
if test "x$LIBXML2_FOUND" = "x1"; then
echo -n " + LibXML2 ....found "
AS_ECHO_N(" + LibXML2 ....found ")
if ! test "x$LIBXML2_VERSION" = "x"; then
echo "v${LIBXML2_VERSION}"
else
@ -532,7 +532,7 @@ if test "x$SSDEEP_FOUND" = "x0"; then
echo " + SSDEEP ....not found"
fi
if test "x$SSDEEP_FOUND" = "x1"; then
echo -n " + SSDEEP ....found "
AS_ECHO_N(" + SSDEEP ....found ")
if ! test "x$SSDEEP_VERSION" = "x"; then
echo "v${SSDEEP_VERSION}"
else
@ -549,7 +549,7 @@ if test "x$LUA_FOUND" = "x0"; then
echo " + LUA ....not found"
fi
if test "x$LUA_FOUND" = "x1"; then
echo -n " + LUA ....found "
AS_ECHO_N(" + LUA ....found ")
if ! test "x$LUA_VERSION" = "x"; then
echo "v${LUA_VERSION}"
else
@ -567,7 +567,7 @@ if test "x$PCRE2_FOUND" = "x0"; then
echo " + PCRE2 ....not found"
fi
if test "x$PCRE2_FOUND" = "x1"; then
echo -n " + PCRE2 ....found "
AS_ECHO_N(" + PCRE2 ....found ")
if ! test "x$PCRE2_VERSION" = "x"; then
echo "v${PCRE2_VERSION}"
else

View file

@ -190,7 +190,7 @@ namespace modsecurity {
#define MODSECURITY_MAJOR "3"
#define MODSECURITY_MINOR "0"
#define MODSECURITY_PATCHLEVEL "9"
#define MODSECURITY_PATCHLEVEL "10"
#define MODSECURITY_TAG ""
#define MODSECURITY_TAG_NUM "100"
@ -198,7 +198,7 @@ namespace modsecurity {
MODSECURITY_MINOR "." MODSECURITY_PATCHLEVEL \
MODSECURITY_TAG
#define MODSECURITY_VERSION_NUM 3090100
#define MODSECURITY_VERSION_NUM 30100100
#define MODSECURITY_CHECK_VERSION(a) (MODSECURITY_VERSION_NUM <= a)

View file

@ -379,6 +379,7 @@ class RulesSetProperties {
from->m_responseBodyLimitAction,
PropertyNotSetBodyLimitAction);
to->m_pcreMatchLimit.merge(&from->m_pcreMatchLimit);
to->m_uploadFileLimit.merge(&from->m_uploadFileLimit);
to->m_uploadFileMode.merge(&from->m_uploadFileMode);
to->m_uploadDirectory.merge(&from->m_uploadDirectory);
@ -470,6 +471,7 @@ class RulesSetProperties {
ConfigDouble m_requestBodyLimit;
ConfigDouble m_requestBodyNoFilesLimit;
ConfigDouble m_responseBodyLimit;
ConfigInt m_pcreMatchLimit;
ConfigInt m_uploadFileLimit;
ConfigInt m_uploadFileMode;
DebugLog *m_debugLog;

View file

@ -134,6 +134,8 @@ class TransactionAnchoredVariables {
m_variableInboundDataError(t, "INBOUND_DATA_ERROR"),
m_variableMatchedVar(t, "MATCHED_VAR"),
m_variableMatchedVarName(t, "MATCHED_VAR_NAME"),
m_variableMscPcreError(t, "MSC_PCRE_ERROR"),
m_variableMscPcreLimitsExceeded(t, "MSC_PCRE_LIMITS_EXCEEDED"),
m_variableMultipartBoundaryQuoted(t, "MULTIPART_BOUNDARY_QUOTED"),
m_variableMultipartBoundaryWhiteSpace(t,
"MULTIPART_BOUNDARY_WHITESPACE"),
@ -219,6 +221,8 @@ class TransactionAnchoredVariables {
AnchoredVariable m_variableInboundDataError;
AnchoredVariable m_variableMatchedVar;
AnchoredVariable m_variableMatchedVarName;
AnchoredVariable m_variableMscPcreError;
AnchoredVariable m_variableMscPcreLimitsExceeded;
AnchoredVariable m_variableMultipartBoundaryQuoted;
AnchoredVariable m_variableMultipartBoundaryWhiteSpace;
AnchoredVariable m_variableMultipartCrlfLFLines;

View file

@ -1,6 +1,6 @@
/*
* ModSecurity, http://www.modsecurity.org/
* Copyright (c) 2015 - 2021 Trustwave Holdings, Inc. (http://www.trustwave.com/)
* Copyright (c) 2015 - 2023 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License. You may obtain a copy of the License at
@ -15,12 +15,7 @@
#include "src/actions/transformations/remove_comments_char.h"
#include <iostream>
#include <string>
#include <algorithm>
#include <functional>
#include <cctype>
#include <locale>
#include "modsecurity/transaction.h"
#include "src/actions/transformations/transformation.h"
@ -37,39 +32,40 @@ RemoveCommentsChar::RemoveCommentsChar(const std::string &action)
std::string RemoveCommentsChar::evaluate(const std::string &val,
Transaction *transaction) {
int64_t i;
std::string value(val);
size_t i = 0;
std::string transformed_value;
transformed_value.reserve(val.size());
i = 0;
while (i < value.size()) {
if (value.at(i) == '/'
&& (i+1 < value.size()) && value.at(i+1) == '*') {
value.erase(i, 2);
} else if (value.at(i) == '*'
&& (i+1 < value.size()) && value.at(i+1) == '/') {
value.erase(i, 2);
} else if (value.at(i) == '<'
&& (i+1 < value.size())
&& value.at(i+1) == '!'
&& (i+2 < value.size())
&& value.at(i+2) == '-'
&& (i+3 < value.size())
&& value.at(i+3) == '-') {
value.erase(i, 4);
} else if (value.at(i) == '-'
&& (i+1 < value.size()) && value.at(i+1) == '-'
&& (i+2 < value.size()) && value.at(i+2) == '>') {
value.erase(i, 3);
} else if (value.at(i) == '-'
&& (i+1 < value.size()) && value.at(i+1) == '-') {
value.erase(i, 2);
} else if (value.at(i) == '#') {
value.erase(i, 1);
while (i < val.size()) {
if (val.at(i) == '/'
&& (i+1 < val.size()) && val.at(i+1) == '*') {
i += 2;
} else if (val.at(i) == '*'
&& (i+1 < val.size()) && val.at(i+1) == '/') {
i += 2;
} else if (val.at(i) == '<'
&& (i+1 < val.size())
&& val.at(i+1) == '!'
&& (i+2 < val.size())
&& val.at(i+2) == '-'
&& (i+3 < val.size())
&& val.at(i+3) == '-') {
i += 4;
} else if (val.at(i) == '-'
&& (i+1 < val.size()) && val.at(i+1) == '-'
&& (i+2 < val.size()) && val.at(i+2) == '>') {
i += 3;
} else if (val.at(i) == '-'
&& (i+1 < val.size()) && val.at(i+1) == '-') {
i += 2;
} else if (val.at(i) == '#') {
i += 1;
} else {
transformed_value += val.at(i);
i++;
}
}
return value;
return transformed_value;
}
} // namespace transformations

View file

@ -1,6 +1,6 @@
/*
* ModSecurity, http://www.modsecurity.org/
* Copyright (c) 2015 - 2021 Trustwave Holdings, Inc. (http://www.trustwave.com/)
* Copyright (c) 2015 - 2023 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License. You may obtain a copy of the License at
@ -17,12 +17,7 @@
#include <string.h>
#include <iostream>
#include <string>
#include <algorithm>
#include <functional>
#include <cctype>
#include <locale>
#include "modsecurity/transaction.h"
#include "src/actions/transformations/transformation.h"
@ -35,19 +30,20 @@ namespace transformations {
std::string RemoveNulls::evaluate(const std::string &val,
Transaction *transaction) {
int64_t i;
std::string value(val);
size_t i = 0;
std::string transformed_value;
transformed_value.reserve(val.size());
i = 0;
while (i < value.size()) {
if (value.at(i) == '\0') {
value.erase(i, 1);
while (i < val.size()) {
if (val.at(i) == '\0') {
// do nothing; continue on to next char in original val
} else {
i++;
transformed_value += val.at(i);
}
i++;
}
return value;
return transformed_value;
}

View file

@ -1,6 +1,6 @@
/*
* ModSecurity, http://www.modsecurity.org/
* Copyright (c) 2015 - 2021 Trustwave Holdings, Inc. (http://www.trustwave.com/)
* Copyright (c) 2015 - 2023 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License. You may obtain a copy of the License at
@ -15,12 +15,7 @@
#include "src/actions/transformations/remove_whitespace.h"
#include <iostream>
#include <string>
#include <algorithm>
#include <functional>
#include <cctype>
#include <locale>
#include "modsecurity/transaction.h"
#include "src/actions/transformations/transformation.h"
@ -37,28 +32,27 @@ RemoveWhitespace::RemoveWhitespace(const std::string &action)
std::string RemoveWhitespace::evaluate(const std::string &val,
Transaction *transaction) {
std::string value(val);
std::string transformed_value;
transformed_value.reserve(val.size());
int64_t i = 0;
size_t i = 0;
const char nonBreakingSpaces = 0xa0;
const char nonBreakingSpaces2 = 0xc2;
// loop through all the chars
while (i < value.size()) {
while (i < val.size()) {
// remove whitespaces and non breaking spaces (NBSP)
if (std::isspace(static_cast<unsigned char>(value[i]))
|| (value[i] == nonBreakingSpaces)
|| value[i] == nonBreakingSpaces2) {
value.erase(i, 1);
if (std::isspace(static_cast<unsigned char>(val[i]))
|| (val[i] == nonBreakingSpaces)
|| val[i] == nonBreakingSpaces2) {
// don't copy; continue on to next char in original val
} else {
/* if the space is not a whitespace char, increment counter
counter should not be incremented if a character is erased because
the index erased will be replaced by the following character */
i++;
transformed_value += val.at(i);
}
i++;
}
return value;
return transformed_value;
}
} // namespace transformations

View file

@ -1,6 +1,6 @@
/*
* ModSecurity, http://www.modsecurity.org/
* Copyright (c) 2015 - 2021 Trustwave Holdings, Inc. (http://www.trustwave.com/)
* Copyright (c) 2015 - 2023 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License. You may obtain a copy of the License at
@ -15,12 +15,7 @@
#include "src/actions/transformations/replace_nulls.h"
#include <iostream>
#include <string>
#include <algorithm>
#include <functional>
#include <cctype>
#include <locale>
#include "modsecurity/transaction.h"
#include "src/actions/transformations/transformation.h"
@ -43,8 +38,7 @@ std::string ReplaceNulls::evaluate(const std::string &val,
i = 0;
while (i < value.size()) {
if (value.at(i) == '\0') {
value.erase(i, 1);
value.insert(i, " ", 1);
value[i] = ' ';
} else {
i++;
}

View file

@ -37,7 +37,7 @@ namespace backend {
#ifdef WITH_LMDB
LMDB::LMDB(std::string name) :
LMDB::LMDB(const std::string &name) :
Collection(name), m_env(NULL), isOpen(false) {}
int LMDB::txn_begin(unsigned int flags, MDB_txn **ret) {
@ -60,7 +60,7 @@ void LMDB::string2val(const std::string& str, MDB_val *val) {
}
void LMDB::lmdb_debug(int rc, std::string op, std::string scope) {
void LMDB::lmdb_debug(int rc, const std::string &op, const std::string &scope) {
#ifndef LMDB_STDOUT_COUT
return;
#else

View file

@ -97,7 +97,7 @@ class MDBEnvProvider {
class LMDB :
public Collection {
public:
explicit LMDB(std::string name);
explicit LMDB(const std::string &name);
void store(std::string key, std::string value) override;
bool storeOrUpdateFirst(const std::string &key,
@ -122,7 +122,7 @@ class LMDB :
private:
int txn_begin(unsigned int flags, MDB_txn **ret);
void string2val(const std::string& str, MDB_val *val);
void inline lmdb_debug(int rc, std::string op, std::string scope);
void inline lmdb_debug(int rc, const std::string &op, const std::string &scope);
MDB_env *m_env;
MDB_dbi m_dbi;

View file

@ -51,12 +51,38 @@ bool Rx::evaluate(Transaction *transaction, RuleWithActions *rule,
re = m_re;
}
std::vector<Utils::SMatchCapture> captures;
if (re->hasError()) {
ms_dbg_a(transaction, 3, "Error with regular expression: \"" + re->pattern + "\"");
return false;
}
re->searchOneMatch(input, captures);
Utils::RegexResult regex_result;
std::vector<Utils::SMatchCapture> captures;
if (transaction && transaction->m_rules->m_pcreMatchLimit.m_set) {
unsigned long match_limit = transaction->m_rules->m_pcreMatchLimit.m_value;
regex_result = re->searchOneMatch(input, captures, match_limit);
} else {
regex_result = re->searchOneMatch(input, captures);
}
// FIXME: DRY regex error reporting. This logic is currently duplicated in other operators.
if (regex_result != Utils::RegexResult::Ok) {
transaction->m_variableMscPcreError.set("1", transaction->m_variableOffset);
std::string regex_error_str = "OTHER";
if (regex_result == Utils::RegexResult::ErrorMatchLimit) {
regex_error_str = "MATCH_LIMIT";
transaction->m_variableMscPcreLimitsExceeded.set("1", transaction->m_variableOffset);
transaction->m_collections.m_tx_collection->storeOrUpdateFirst("MSC_PCRE_LIMITS_EXCEEDED", "1");
ms_dbg_a(transaction, 7, "Set TX.MSC_PCRE_LIMITS_EXCEEDED to 1");
}
ms_dbg_a(transaction, 1, "rx: regex error '" + regex_error_str + "' for pattern '" + re->pattern + "'");
return false;
}
if (rule && rule->hasCaptureAction() && transaction) {
for (const Utils::SMatchCapture& capture : captures) {

View file

@ -51,8 +51,32 @@ bool RxGlobal::evaluate(Transaction *transaction, RuleWithActions *rule,
re = m_re;
}
Utils::RegexResult regex_result;
std::vector<Utils::SMatchCapture> captures;
re->searchGlobal(input, captures);
if (transaction && transaction->m_rules->m_pcreMatchLimit.m_set) {
unsigned long match_limit = transaction->m_rules->m_pcreMatchLimit.m_value;
regex_result = re->searchGlobal(input, captures, match_limit);
} else {
regex_result = re->searchGlobal(input, captures);
}
// FIXME: DRY regex error reporting. This logic is currently duplicated in other operators.
if (regex_result != Utils::RegexResult::Ok) {
transaction->m_variableMscPcreError.set("1", transaction->m_variableOffset);
std::string regex_error_str = "OTHER";
if (regex_result == Utils::RegexResult::ErrorMatchLimit) {
regex_error_str = "MATCH_LIMIT";
transaction->m_variableMscPcreLimitsExceeded.set("1", transaction->m_variableOffset);
transaction->m_collections.m_tx_collection->storeOrUpdateFirst("MSC_PCRE_LIMITS_EXCEEDED", "1");
ms_dbg_a(transaction, 7, "Set TX.MSC_PCRE_LIMITS_EXCEEDED to 1");
}
ms_dbg_a(transaction, 1, "rxGlobal: regex error '" + regex_error_str + "' for pattern '" + re->pattern + "'");
return false;
}
if (rule && rule->hasCaptureAction() && transaction) {
for (const Utils::SMatchCapture& capture : captures) {

View file

@ -43,7 +43,7 @@ Driver::~Driver() {
}
int Driver::addSecMarker(std::string marker, std::unique_ptr<std::string> fileName, int lineNumber) {
int Driver::addSecMarker(const std::string& marker, std::unique_ptr<std::string> fileName, int lineNumber) {
// FIXME: we might move this to the parser.
for (int i = 0; i < modsecurity::Phases::NUMBER_OF_PHASES; i++) {
RuleMarker *r = new RuleMarker(marker, std::unique_ptr<std::string>(new std::string(*fileName)), lineNumber);

View file

@ -60,7 +60,7 @@ class Driver : public RulesSetProperties {
int addSecRule(std::unique_ptr<RuleWithActions> rule);
int addSecAction(std::unique_ptr<RuleWithActions> rule);
int addSecMarker(std::string marker, std::unique_ptr<std::string> fileName, int lineNumber);
int addSecMarker(const std::string& marker, std::unique_ptr<std::string> fileName, int lineNumber);
int addSecRuleScript(std::unique_ptr<RuleScript> rule);
bool scan_begin();

View file

@ -1,4 +1,4 @@
// A Bison parser, made by GNU Bison 3.7.6.
// A Bison parser, made by GNU Bison 3.8.2.
// Locations for Bison parsers in C++

View file

@ -1,4 +1,4 @@
// A Bison parser, made by GNU Bison 3.7.6.
// A Bison parser, made by GNU Bison 3.8.2.
// Starting with Bison 3.2, this file is useless: the structure it
// used to define is now defined in "location.hh".

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -184,6 +184,8 @@ class Driver;
#include "src/variables/matched_vars.h"
#include "src/variables/matched_vars_names.h"
#include "src/variables/modsec_build.h"
#include "src/variables/msc_pcre_error.h"
#include "src/variables/msc_pcre_limits_exceeded.h"
#include "src/variables/multipart_boundary_quoted.h"
#include "src/variables/multipart_boundary_whitespace.h"
#include "src/variables/multipart_crlf_lf_lines.h"
@ -368,6 +370,8 @@ using namespace modsecurity::operators;
VARIABLE_INBOUND_DATA_ERROR "INBOUND_DATA_ERROR"
VARIABLE_MATCHED_VAR "MATCHED_VAR"
VARIABLE_MATCHED_VAR_NAME "MATCHED_VAR_NAME"
VARIABLE_MSC_PCRE_ERROR "MSC_PCRE_ERROR"
VARIABLE_MSC_PCRE_LIMITS_EXCEEDED "MSC_PCRE_LIMITS_EXCEEDED"
VARIABLE_MULTIPART_BOUNDARY_QUOTED
VARIABLE_MULTIPART_BOUNDARY_WHITESPACE
VARIABLE_MULTIPART_CRLF_LF_LINES "MULTIPART_CRLF_LF_LINES"
@ -1648,10 +1652,10 @@ expression:
YYERROR;
*/
| CONFIG_DIR_PCRE_MATCH_LIMIT
/* Parser error disabled to avoid breaking default installations with modsecurity.conf-recommended
driver.error(@0, "SecPcreMatchLimit is not currently supported. Default PCRE values are being used for now");
YYERROR;
*/
{
driver.m_pcreMatchLimit.m_set = true;
driver.m_pcreMatchLimit.m_value = atoi($1.c_str());
}
| CONGIG_DIR_RESPONSE_BODY_MP
{
std::istringstream buf($1);
@ -2321,6 +2325,14 @@ var:
{
VARIABLE_CONTAINER($$, new variables::MatchedVarName());
}
| VARIABLE_MSC_PCRE_ERROR
{
VARIABLE_CONTAINER($$, new variables::MscPcreError());
}
| VARIABLE_MSC_PCRE_LIMITS_EXCEEDED
{
VARIABLE_CONTAINER($$, new variables::MscPcreLimitsExceeded());
}
| VARIABLE_MULTIPART_BOUNDARY_QUOTED
{
VARIABLE_CONTAINER($$, new variables::MultipartBoundaryQuoted());

File diff suppressed because it is too large Load diff

View file

@ -186,6 +186,8 @@ VARIABLE_GLOBAL (?i:GLOBAL)
VARIABLE_INBOUND_DATA_ERROR (?i:INBOUND_DATA_ERROR)
VARIABLE_MATCHED_VAR (?i:MATCHED_VAR)
VARIABLE_MATCHED_VAR_NAME (?i:MATCHED_VAR_NAME)
VARIABLE_MSC_PCRE_ERROR (?i:MSC_PCRE_ERROR)
VARIABLE_MSC_PCRE_LIMITS_EXCEEDED (?i:MSC_PCRE_LIMITS_EXCEEDED)
VARIABLE_MULTIPART_BOUNDARY_QUOTED (?i:MULTIPART_BOUNDARY_QUOTED)
VARIABLE_MULTIPART_BOUNDARY_WHITESPACE (?i:MULTIPART_BOUNDARY_WHITESPACE)
VARIABLE_MULTIPART_CRLF_LF_LINES (?i:MULTIPART_CRLF_LF_LINES)
@ -910,6 +912,8 @@ EQUALS_MINUS (?i:=\-)
{VARIABLE_INBOUND_DATA_ERROR} { return p::make_VARIABLE_INBOUND_DATA_ERROR(*driver.loc.back()); }
{VARIABLE_MATCHED_VAR_NAME} { return p::make_VARIABLE_MATCHED_VAR_NAME(*driver.loc.back()); }
{VARIABLE_MATCHED_VAR} { return p::make_VARIABLE_MATCHED_VAR(*driver.loc.back()); }
{VARIABLE_MSC_PCRE_ERROR} { return p::make_VARIABLE_MSC_PCRE_ERROR(*driver.loc.back()); }
{VARIABLE_MSC_PCRE_LIMITS_EXCEEDED} { return p::make_VARIABLE_MSC_PCRE_LIMITS_EXCEEDED(*driver.loc.back()); }
{VARIABLE_MULTIPART_BOUNDARY_QUOTED} { return p::make_VARIABLE_MULTIPART_BOUNDARY_QUOTED(*driver.loc.back()); }
{VARIABLE_MULTIPART_BOUNDARY_WHITESPACE} { return p::make_VARIABLE_MULTIPART_BOUNDARY_WHITESPACE(*driver.loc.back()); }
{VARIABLE_MULTIPART_CRLF_LF_LINES} { return p::make_VARIABLE_MULTIPART_CRLF_LF_LINES(*driver.loc.back()); }
@ -1271,9 +1275,9 @@ EQUALS_MINUS (?i:=\-)
{CONFIG_INCLUDE}[ \t]+["]{CONFIG_VALUE_PATH}["] {
std::string err;
const char *tmpStr = yytext + strlen("include");
const char *file = tmpStr + strspn( tmpStr, " \t");
char *f = strdup(file);
std::string fi = modsecurity::utils::find_resource(f, *driver.loc.back()->end.filename, &err);
const char *afterWhitespace = tmpStr + strspn( tmpStr, " \t");
std::string file(afterWhitespace+1, strlen(afterWhitespace)-2);
std::string fi = modsecurity::utils::find_resource(file, *driver.loc.back()->end.filename, &err);
if (fi.empty() == true) {
BEGIN(INITIAL);
driver.error (*driver.loc.back(), "", file + std::string(": Not able to open file. ") + err);
@ -1296,7 +1300,6 @@ EQUALS_MINUS (?i:=\-)
}
yypush_buffer_state(yy_create_buffer( yyin, YY_BUF_SIZE ));
}
free(f);
}
{CONFIG_SEC_REMOTE_RULES}[ ][^ ]+[ ][^\n\r ]+ {

View file

@ -1,4 +1,4 @@
// A Bison parser, made by GNU Bison 3.7.6.
// A Bison parser, made by GNU Bison 3.8.2.
// Starting with Bison 3.2, this file is useless: the structure it
// used to define is now defined with the parser itself.

View file

@ -935,7 +935,7 @@ int Multipart::process_part_header(std::string *error, int offset) {
"Multipart: Added part header \"" + header_name \
+ "\" \"" + header_value + "\".");
if (len_without_termination > 0) {
m_mpp->m_last_header_line.assign(m_buf);
m_mpp->m_last_header_line.assign(m_buf, len_without_termination);
} else {
m_mpp->m_last_header_line.assign("");
}
@ -1198,15 +1198,9 @@ int Multipart::multipart_complete(std::string *error) {
size_t offset = m_transaction->m_variableOffset + 1;
if (m->m_type == MULTIPART_FILE) {
std::string tmp_name;
std::string name;
if (m->m_tmp_file && !m->m_tmp_file->getFilename().empty()) {
tmp_name.assign(m->m_tmp_file->getFilename());
m_transaction->m_variableFilesTmpNames.set(m->m_tmp_file->getFilename(),
m->m_tmp_file->getFilename(), m->m_filenameOffset);
}
if (!m->m_filename.empty()) {
name.assign(m->m_filename);
if (m->m_tmp_file && !m->m_tmp_file->getFilename().empty()) {
m_transaction->m_variableFilesTmpNames.set(m->m_tmp_file->getFilename(),
m->m_tmp_file->getFilename(), m->m_filenameOffset);
}
m_transaction->m_variableFiles.set(m->m_name,

View file

@ -219,7 +219,7 @@ void RuleWithActions::executeActionsIndependentOfChainedRuleResult(Transaction *
}
}
if (m_containsMultiMatchAction && !m_isChained) {
if (m_containsMultiMatchAction && m_chainedRuleParent == nullptr) {
if (m_severity) {
m_severity->evaluate(this, trans, ruleMessage);
}
@ -229,6 +229,9 @@ void RuleWithActions::executeActionsIndependentOfChainedRuleResult(Transaction *
if (m_msg) {
m_msg->evaluate(this, trans, ruleMessage);
}
for (actions::Tag *a : m_actionsTag) {
a->evaluate(this, trans, ruleMessage);
}
}
}

View file

@ -167,6 +167,8 @@ Transaction::Transaction(ModSecurity *ms, RulesSet *rules, void *logCbData)
+ std::to_string(modsecurity::utils::generate_transaction_unique_id())));
m_variableUrlEncodedError.set("0", 0);
m_variableMscPcreError.set("0", 0);
m_variableMscPcreLimitsExceeded.set("0", 0);
ms_dbg(4, "Initializing transaction");
@ -238,6 +240,8 @@ Transaction::Transaction(ModSecurity *ms, RulesSet *rules, char *id, void *logCb
TransactionAnchoredVariables(this) {
m_variableUrlEncodedError.set("0", 0);
m_variableMscPcreError.set("0", 0);
m_variableMscPcreLimitsExceeded.set("0", 0);
ms_dbg(4, "Initializing transaction");

View file

@ -258,11 +258,13 @@ int InsertNetmask(TreeNode *node, TreeNode *parent, TreeNode *new_node,
}
node->count++;
node->netmasks = reinterpret_cast<unsigned char *>(malloc(node->count * sizeof(unsigned char)));
if(node->netmasks == NULL) {
return 0;
}
memset(node->netmasks, 0, (node->count * sizeof(unsigned char)));
if(node->netmasks == NULL)
return 0;
if ((node->count-1) == 0) {
node->netmasks[0] = netmask;
return 1;

View file

@ -25,12 +25,38 @@
#ifndef WITH_PCRE2
#if PCRE_HAVE_JIT
#define pcre_study_opt PCRE_STUDY_JIT_COMPILE
// NOTE: Add PCRE_STUDY_EXTRA_NEEDED so studying always yields a pcre_extra strucure
// and we can selectively override match limits using a copy of that structure at runtime.
#define pcre_study_opt PCRE_STUDY_JIT_COMPILE | PCRE_STUDY_EXTRA_NEEDED
#else
#define pcre_study_opt 0
// NOTE: Add PCRE_STUDY_EXTRA_NEEDED so studying always yields a pcre_extra strucure
// and we can selectively override match limits using a copy of that structure at runtime.
#define pcre_study_opt PCRE_STUDY_EXTRA_NEEDED
#endif
#endif
#ifdef WITH_PCRE2
class Pcre2MatchContextPtr {
public:
Pcre2MatchContextPtr()
: m_match_context(pcre2_match_context_create(NULL)) {}
Pcre2MatchContextPtr(const Pcre2MatchContextPtr&) = delete;
Pcre2MatchContextPtr& operator=(const Pcre2MatchContextPtr&) = delete;
~Pcre2MatchContextPtr() {
pcre2_match_context_free(m_match_context);
}
operator pcre2_match_context*() const {
return m_match_context;
}
private:
pcre2_match_context *m_match_context;
};
#endif
namespace modsecurity {
namespace Utils {
@ -163,24 +189,39 @@ std::list<SMatch> Regex::searchAll(const std::string& s) const {
return retList;
}
bool Regex::searchOneMatch(const std::string& s, std::vector<SMatchCapture>& captures) const {
RegexResult Regex::searchOneMatch(const std::string& s, std::vector<SMatchCapture>& captures, unsigned long match_limit) const {
#ifdef WITH_PCRE2
Pcre2MatchContextPtr match_context;
if (match_limit > 0) {
// TODO: What if setting the match limit fails?
pcre2_set_match_limit(match_context, match_limit);
}
PCRE2_SPTR pcre2_s = reinterpret_cast<PCRE2_SPTR>(s.c_str());
pcre2_match_data *match_data = pcre2_match_data_create_from_pattern(m_pc, NULL);
int rc = 0;
if (m_pcje == 0) {
rc = pcre2_jit_match(m_pc, pcre2_s, s.length(), 0, 0, match_data, NULL);
rc = pcre2_jit_match(m_pc, pcre2_s, s.length(), 0, 0, match_data, match_context);
}
if (m_pcje != 0 || rc == PCRE2_ERROR_JIT_STACKLIMIT) {
rc = pcre2_match(m_pc, pcre2_s, s.length(), 0, PCRE2_NO_JIT, match_data, NULL);
rc = pcre2_match(m_pc, pcre2_s, s.length(), 0, PCRE2_NO_JIT, match_data, match_context);
}
PCRE2_SIZE *ovector = pcre2_get_ovector_pointer(match_data);
#else
const char *subject = s.c_str();
int ovector[OVECCOUNT];
pcre_extra local_pce;
pcre_extra *pce = m_pce;
int rc = pcre_exec(m_pc, m_pce, subject, s.size(), 0, 0, ovector, OVECCOUNT);
if (m_pce != NULL && match_limit > 0) {
local_pce = *m_pce;
local_pce.match_limit = match_limit;
local_pce.flags |= PCRE_EXTRA_MATCH_LIMIT;
pce = &local_pce;
}
int rc = pcre_exec(m_pc, pce, subject, s.size(), 0, 0, ovector, OVECCOUNT);
#endif
for (int i = 0; i < rc; i++) {
@ -197,12 +238,18 @@ bool Regex::searchOneMatch(const std::string& s, std::vector<SMatchCapture>& cap
#ifdef WITH_PCRE2
pcre2_match_data_free(match_data);
#endif
return (rc > 0);
return to_regex_result(rc);
}
bool Regex::searchGlobal(const std::string& s, std::vector<SMatchCapture>& captures) const {
RegexResult Regex::searchGlobal(const std::string& s, std::vector<SMatchCapture>& captures, unsigned long match_limit) const {
bool prev_match_zero_length = false;
#ifdef WITH_PCRE2
Pcre2MatchContextPtr match_context;
if (match_limit > 0) {
// TODO: What if setting the match limit fails?
pcre2_set_match_limit(match_context, match_limit);
}
PCRE2_SPTR pcre2_s = reinterpret_cast<PCRE2_SPTR>(s.c_str());
PCRE2_SIZE startOffset = 0;
@ -213,11 +260,21 @@ bool Regex::searchGlobal(const std::string& s, std::vector<SMatchCapture>& captu
pcre2_options = PCRE2_NOTEMPTY_ATSTART | PCRE2_ANCHORED;
}
int rc = pcre2_match(m_pc, pcre2_s, s.length(),
startOffset, pcre2_options, match_data, NULL);
startOffset, pcre2_options, match_data, match_context);
PCRE2_SIZE *ovector = pcre2_get_ovector_pointer(match_data);
#else
const char *subject = s.c_str();
pcre_extra local_pce;
pcre_extra *pce = m_pce;
if (m_pce != NULL && match_limit > 0) {
local_pce = *m_pce;
local_pce.match_limit = match_limit;
local_pce.flags |= PCRE_EXTRA_MATCH_LIMIT;
pce = &local_pce;
}
int startOffset = 0;
while (startOffset <= s.length()) {
@ -226,7 +283,12 @@ bool Regex::searchGlobal(const std::string& s, std::vector<SMatchCapture>& captu
if (prev_match_zero_length) {
pcre_options = PCRE_NOTEMPTY_ATSTART | PCRE_ANCHORED;
}
int rc = pcre_exec(m_pc, m_pce, subject, s.length(), startOffset, pcre_options, ovector, OVECCOUNT);
int rc = pcre_exec(m_pc, pce, subject, s.length(), startOffset, pcre_options, ovector, OVECCOUNT);
RegexResult regex_result = to_regex_result(rc);
if (regex_result != RegexResult::Ok) {
return regex_result;
}
#endif
if (rc > 0) {
@ -278,7 +340,7 @@ bool Regex::searchGlobal(const std::string& s, std::vector<SMatchCapture>& captu
#ifdef WITH_PCRE2
pcre2_match_data_free(match_data);
#endif
return (captures.size() > 0);
return RegexResult::Ok;
}
int Regex::search(const std::string& s, SMatch *match) const {
@ -340,5 +402,30 @@ int Regex::search(const std::string& s) const {
#endif
}
RegexResult Regex::to_regex_result(int pcre_exec_result) const {
if (
pcre_exec_result > 0 ||
#ifdef WITH_PCRE2
pcre_exec_result == PCRE2_ERROR_NOMATCH
#else
pcre_exec_result == PCRE_ERROR_NOMATCH
#endif
) {
return RegexResult::Ok;
} else if(
#ifdef WITH_PCRE2
pcre_exec_result == PCRE2_ERROR_MATCHLIMIT
#else
pcre_exec_result == PCRE_ERROR_MATCHLIMIT
#endif
) {
return RegexResult::ErrorMatchLimit;
} else {
// Note that this can include the case where the PCRE result was zero.
// Zero is returned if the offset vector is not large enough and can be considered an error.
return RegexResult::ErrorOther;
}
}
} // namespace Utils
} // namespace modsecurity

View file

@ -34,6 +34,12 @@ namespace Utils {
#define OVECCOUNT 900
enum class RegexResult {
Ok,
ErrorMatchLimit,
ErrorOther,
};
class SMatch {
public:
SMatch() :
@ -76,13 +82,15 @@ class Regex {
return (m_pc == NULL);
}
std::list<SMatch> searchAll(const std::string& s) const;
bool searchOneMatch(const std::string& s, std::vector<SMatchCapture>& captures) const;
bool searchGlobal(const std::string& s, std::vector<SMatchCapture>& captures) const;
RegexResult searchOneMatch(const std::string& s, std::vector<SMatchCapture>& captures, unsigned long match_limit = 0) const;
RegexResult searchGlobal(const std::string& s, std::vector<SMatchCapture>& captures, unsigned long match_limit = 0) const;
int search(const std::string &s, SMatch *match) const;
int search(const std::string &s) const;
const std::string pattern;
private:
RegexResult to_regex_result(int pcre_exec_result) const;
#if WITH_PCRE2
pcre2_code *m_pc;
int m_pcje;

View file

@ -225,7 +225,7 @@ void chomp(std::string *str) {
}
unsigned char x2c(unsigned char *what) {
unsigned char x2c(const unsigned char *what) {
unsigned char digit;
digit = (what[0] >= 'A' ? ((what[0] & 0xdf) - 'A') + 10 : (what[0] - '0'));
@ -239,7 +239,7 @@ unsigned char x2c(unsigned char *what) {
/**
* Converts a single hexadecimal digit into a decimal value.
*/
unsigned char xsingle2c(unsigned char *what) {
unsigned char xsingle2c(const unsigned char *what) {
unsigned char digit;
digit = (what[0] >= 'A' ? ((what[0] & 0xdf) - 'A') + 10 : (what[0] - '0'));

View file

@ -73,8 +73,8 @@ void replaceAll(std::string *str, const std::string& from,
std::string removeWhiteSpacesIfNeeded(std::string a);
std::string parserSanitizer(std::string a);
unsigned char x2c(unsigned char *what);
unsigned char xsingle2c(unsigned char *what);
unsigned char x2c(const unsigned char *what);
unsigned char xsingle2c(const unsigned char *what);
unsigned char *c2x(unsigned what, unsigned char *where);
} // namespace string

View file

@ -106,8 +106,8 @@ class Global_DynamicElement : public Variable {
t->m_rules->m_secWebAppId.m_value);
}
static void storeOrUpdateFirst(Transaction *t, std::string var,
std::string value) {
static void storeOrUpdateFirst(Transaction *t, const std::string &var,
const std::string &value) {
t->m_collections.m_global_collection->storeOrUpdateFirst(
var, t->m_collections.m_global_collection_key,
t->m_rules->m_secWebAppId.m_value,

View file

@ -0,0 +1,39 @@
/*
* ModSecurity, http://www.modsecurity.org/
* Copyright (c) 2015 - 2022 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Trustwave Holdings, Inc.
* directly using the email address security@modsecurity.org.
*
*/
#include <iostream>
#include <string>
#include <vector>
#include <list>
#include <utility>
#ifndef SRC_VARIABLES_MSC_PCRE_ERROR_H_
#define SRC_VARIABLES_MSC_PCRE_ERROR_H_
#include "src/variables/variable.h"
namespace modsecurity {
class Transaction;
namespace variables {
DEFINE_VARIABLE(MscPcreError, MSC_PCRE_ERROR, m_variableMscPcreError)
} // namespace variables
} // namespace modsecurity
#endif // SRC_VARIABLES_MSC_PCRE_ERROR_H_

View file

@ -0,0 +1,39 @@
/*
* ModSecurity, http://www.modsecurity.org/
* Copyright (c) 2015 - 2022 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Trustwave Holdings, Inc.
* directly using the email address security@modsecurity.org.
*
*/
#include <iostream>
#include <string>
#include <vector>
#include <list>
#include <utility>
#ifndef SRC_VARIABLES_MSC_PCRE_LIMITS_EXCEEDED_H_
#define SRC_VARIABLES_MSC_PCRE_LIMITS_EXCEEDED_H_
#include "src/variables/variable.h"
namespace modsecurity {
class Transaction;
namespace variables {
DEFINE_VARIABLE(MscPcreLimitsExceeded, MSC_PCRE_LIMITS_EXCEEDED, m_variableMscPcreLimitsExceeded)
} // namespace variables
} // namespace modsecurity
#endif // SRC_VARIABLES_MSC_PCRE_LIMITS_EXCEEDED_H_

View file

@ -1,6 +1,6 @@
/*
* ModSecurity, http://www.modsecurity.org/
* Copyright (c) 2015 - 2021 Trustwave Holdings, Inc. (http://www.trustwave.com/)
* Copyright (c) 2015 - 2023 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License. You may obtain a copy of the License at
@ -179,163 +179,201 @@ 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, "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, "MULTIPART_PART_HEADERS")) {
anchoredSetVariable = &t->m_variableMultipartPartHeaders;
} 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.");
}
}
@ -365,6 +403,10 @@ class VariableMonkeyResolution {
vv = t->m_variableMatchedVar.resolveFirst();
} else if (comp(variable, "MATCHED_VAR_NAME")) {
vv = t->m_variableMatchedVarName.resolveFirst();
} else if (comp(variable, "MSC_PCRE_ERROR")) {
vv = t->m_variableMscPcreError.resolveFirst();
} else if (comp(variable, "MSC_PCRE_LIMITS_EXCEEDED")) {
vv = t->m_variableMscPcreLimitsExceeded.resolveFirst();
} else if (comp(variable, "MULTIPART_CRLF_LF_LINES")) {
vv = t->m_variableMultipartCrlfLFLines.resolveFirst();
} else if (comp(variable, "MULTIPART_DATA_AFTER")) {
@ -513,6 +555,8 @@ class VariableMonkeyResolution {
vv = t->m_variableRequestCookiesNames.resolveFirst(var);
} else if (comp(col, "FILES_TMPNAMES")) {
vv = t->m_variableFilesTmpNames.resolveFirst(var);
} else if (comp(col, "MULTIPART_PART_HEADERS")) {
vv = t->m_variableMultipartPartHeaders.resolveFirst(var);
} else if (comp(col, "TX")) {
vv = t->m_collections.m_tx_collection->resolveFirst(var);
} else if (comp(col, "RESOURCE")) {
@ -608,7 +652,7 @@ class Variables : public std::vector<Variable *> {
public:
bool contains(Variable *v) {
return std::find_if(begin(), end(),
[v](Variable *m) -> bool { return *v == *m; }) != end();
[v](const Variable *m) -> bool { return *v == *m; }) != end();
};
bool contains(const VariableValue *v) {
return std::find_if(begin(), end(),

View file

@ -53,14 +53,11 @@ duplicateBranch:src/request_body_processor/multipart.cc:93
danglingTempReference:src/modsecurity.cc:206
knownConditionTrueFalse:src/operators/validate_url_encoding.cc:77
knownConditionTrueFalse:src/operators/verify_svnr.cc:87
rethrowNoCurrentException:headers/modsecurity/transaction.h:309
rethrowNoCurrentException:headers/modsecurity/transaction.h:313
rethrowNoCurrentException:src/rule_with_actions.cc:127
ctunullpointer:src/rule_with_actions.cc:241
ctunullpointer:src/rule_with_actions.cc:244
ctunullpointer:src/rule_with_operator.cc:135
ctunullpointer:src/rule_with_operator.cc:95
passedByValue:src/variables/global.h:109
passedByValue:src/variables/global.h:110
passedByValue:src/parser/driver.cc:46
passedByValue:test/common/modsecurity_test.cc:49
passedByValue:test/common/modsecurity_test.cc:98
unreadVariable:src/rule_with_operator.cc:219
@ -68,28 +65,33 @@ unreadVariable:src/rule_with_operator.cc:219
uninitvar:src/operators/verify_cpf.cc:77
uninitvar:src/operators/verify_svnr.cc:67
functionConst:src/collection/backend/lmdb.h:86
unusedLabel:src/collection/backend/lmdb.cc:297
variableScope:src/operators/rx.cc
variableScope:src/operators/rx_global.cc
noExplicitConstructor:seclang-parser.hh
constParameter:seclang-parser.hh
accessMoved:seclang-parser.hh
returnTempReference:seclang-parser.hh
unreadVariable:src/operators/rx.cc
unreadVariable:src/operators/rx_global.cc
unusedFunction
missingIncludeSystem
useStlAlgorithm
preprocessorErrorDirective
funcArgNamesDifferent
unmatchedSuppression
missingInclude
purgedConfiguration
constParameter
nullPointerRedundantCheck
knownConditionTrueFalse
cstyleCast
functionStatic
variableScope
shadowFunction
constVariable

View file

@ -1,4 +1,5 @@
127.0.0.1
# Comment line
10.10.10.1
::1

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

@ -253,14 +253,14 @@
"body": ""
},
"expected": {
"audit_log": "\\[msg \"testmsg\"\\]",
"audit_log": "\\[msg \"testmsg\"\\] \\[data \"testdata\"\\] \\[severity \"7\"\\] \\[ver \"\"\\] \\[maturity \"0\"\\] \\[accuracy \"0\"\\] \\[tag \"testtag1\"\\] \\[tag \"testtag2\"\\]",
"error_log": "",
"http_code": 403
},
"rules": [
"SecRuleEngine On",
"SecDefaultAction \"phase:1,nolog,auditlog,deny,status:403\"",
"SecRule ARGS \"@contains test2\" \"id:1557,phase:1,multiMatch,block,log,t:none,t:urlDecode,t:lowercase,msg:'testmsg'\"",
"SecRule ARGS \"@contains test2\" \"id:1557,phase:1,multiMatch,block,log,t:none,t:urlDecode,t:lowercase,msg:'testmsg',logdata:'testdata',severity:'DEBUG',tag:'testtag1',tag:'testtag2'\"",
"SecAuditEngine RelevantOnly",
"SecAuditLogParts ABCFHZ",
"SecAuditLog /tmp/test/modsec_audit_multimatch_1.log",
@ -302,14 +302,14 @@
"body": ""
},
"expected": {
"audit_log": "\\[msg \"tstmsg\"\\]",
"audit_log": "\\[msg \"testmsg\"\\] \\[data \"testdata\"\\] \\[severity \"7\"\\] \\[ver \"\"\\] \\[maturity \"0\"\\] \\[accuracy \"0\"\\] \\[tag \"testtag1\"\\] \\[tag \"testtag2\"\\]",
"error_log": "",
"http_code": 403
},
"rules": [
"SecRuleEngine On",
"SecDefaultAction \"phase:1,nolog,auditlog,deny,status:403\"",
"SecRule ARGS \"@streq tEst2\" \"id:1558,phase:1,multiMatch,block,log,t:none,t:trim,t:lowercase,msg:'tstmsg'\"",
"SecRule ARGS \"@streq tEst2\" \"id:1558,phase:1,multiMatch,block,log,t:none,t:trim,t:lowercase,msg:'testmsg',logdata:'testdata',severity:'DEBUG',tag:'testtag1',tag:'testtag2'\"",
"SecAuditEngine RelevantOnly",
"SecAuditLogParts ABCFHZ",
"SecAuditLog /tmp/test/modsec_audit_multimatch_2.log",
@ -318,5 +318,105 @@
"SecAuditLogType Serial",
"SecAuditLogRelevantStatus \"^(?:5|4(?!04))\""
]
},
{
"enabled": 1,
"version_min": 300000,
"version_max": 0,
"title": "auditlog : rule chain, multiMatch data, match after last transform",
"client": {
"ip": "200.249.12.31",
"port": 2313
},
"server": {
"ip": "200.249.12.31",
"port": 80
},
"request": {
"headers": {
"Host": "www.modsecurity.org",
"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",
"Pragma": "no-cache",
"Cache-Control": "no-cache"
},
"uri": "\/test.pl?param1=test&param2=tEst2",
"method": "GET",
"http_version": 1.1,
"body": ""
},
"expected": {
"audit_log": "\\[msg \"testmsg\"\\] \\[data \"testdata\"\\] \\[severity \"7\"\\] \\[ver \"\"\\] \\[maturity \"0\"\\] \\[accuracy \"0\"\\] \\[tag \"testtag1\"\\] \\[tag \"testtag2\"\\]",
"error_log": "",
"http_code": 403
},
"rules": [
"SecRuleEngine On",
"SecDefaultAction \"phase:1,nolog,auditlog,deny,status:403\"",
"SecRule ARGS \"@contains test2\" \"id:1559,phase:1,multiMatch,block,log,t:none,t:urlDecode,t:lowercase,msg:'testmsg',logdata:'testdata',severity:'DEBUG',tag:'testtag1',tag:'testtag2',chain\"",
"SecRule REQUEST_METHOD \"@streq GET\" \"t:none\"",
"SecAuditEngine RelevantOnly",
"SecAuditLogParts ABCFHZ",
"SecAuditLog /tmp/test/modsec_audit_multimatch_3.log",
"SecAuditLogDirMode 0766",
"SecAuditLogFileMode 0666",
"SecAuditLogType Serial",
"SecAuditLogRelevantStatus \"^(?:5|4(?!04))\""
]
},
{
"enabled": 1,
"version_min": 300000,
"version_max": 0,
"title": "auditlog : rule chain, multiMatch data, match only after intermediate transform",
"client": {
"ip": "200.249.12.31",
"port": 2313
},
"server": {
"ip": "200.249.12.31",
"port": 80
},
"request": {
"headers": {
"Host": "www.modsecurity.org",
"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",
"Pragma": "no-cache",
"Cache-Control": "no-cache"
},
"uri": "\/test.pl?param1=test&param2=%20tEst2",
"method": "GET",
"http_version": 1.1,
"body": ""
},
"expected": {
"audit_log": "\\[msg \"testmsg\"\\] \\[data \"testdata\"\\] \\[severity \"7\"\\] \\[ver \"\"\\] \\[maturity \"0\"\\] \\[accuracy \"0\"\\] \\[tag \"testtag1\"\\] \\[tag \"testtag2\"\\]",
"error_log": "",
"http_code": 403
},
"rules": [
"SecRuleEngine On",
"SecDefaultAction \"phase:1,nolog,auditlog,deny,status:403\"",
"SecRule ARGS \"@streq tEst2\" \"id:1560,phase:1,multiMatch,block,log,t:none,t:trim,t:lowercase,msg:'testmsg',logdata:'testdata',severity:'DEBUG',tag:'testtag1',tag:'testtag2',chain\"",
"SecRule REQUEST_METHOD \"@streq GET\" \"t:none\"",
"SecAuditEngine RelevantOnly",
"SecAuditLogParts ABCFHZ",
"SecAuditLog /tmp/test/modsec_audit_multimatch_4.log",
"SecAuditLogDirMode 0766",
"SecAuditLogFileMode 0666",
"SecAuditLogType Serial",
"SecAuditLogRelevantStatus \"^(?:5|4(?!04))\""
]
}
]

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\""
]
}
]

View file

@ -2,7 +2,7 @@
{
"enabled":1,
"version_min":300000,
"title":"Include (1/7)",
"title":"Include (1/8)",
"client":{
"ip":"200.249.12.31",
"port":123
@ -42,7 +42,7 @@
{
"enabled":1,
"version_min":300000,
"title":"Include (2/7)",
"title":"Include (2/8)",
"client":{
"ip":"200.249.12.31",
"port":123
@ -82,7 +82,7 @@
{
"enabled":1,
"version_min":300000,
"title":"Include (3/7)",
"title":"Include (3/8)",
"client":{
"ip":"200.249.12.31",
"port":123
@ -122,7 +122,7 @@
{
"enabled":1,
"version_min":300000,
"title":"Include (4/7)",
"title":"Include (4/8)",
"client":{
"ip":"200.249.12.31",
"port":123
@ -162,7 +162,7 @@
{
"enabled":1,
"version_min":300000,
"title":"Include (5/7)",
"title":"Include (5/8)",
"client":{
"ip":"200.249.12.31",
"port":123
@ -203,7 +203,7 @@
{
"enabled":1,
"version_min":300000,
"title":"Include (6/7)",
"title":"Include (6/8)",
"client":{
"ip":"200.249.12.31",
"port":123
@ -243,7 +243,7 @@
{
"enabled":1,
"version_min":300000,
"title":"Include (7/7)",
"title":"Include (7/8)",
"client":{
"ip":"200.249.12.31",
"port":123
@ -279,5 +279,45 @@
"Include test-cases/data/conasdffig_example2.txt",
"SecRule ARGS \"@contains test\" \"id:9,pass,t:trim\""
]
},
{
"enabled":1,
"version_min":300000,
"title":"Include (8/8) -- quoted with wildcard",
"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",
"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":"Executing operator \"Contains\" with param \"config_example2\" against ARGS."
},
"rules":[
"SecRuleEngine On",
"Include \"test-cases/data/config_ex*ple2.txt\"",
"SecRule ARGS \"@contains test\" \"id:9,pass,t:trim\""
]
}
]

View file

@ -127,5 +127,140 @@
"SecRuleEngine On",
"SecRule REQUEST_HEADERS:Content-Type \"@rx a(b\" \"id:1,phase:2,pass,t:trim,block\""
]
},
{
"enabled":1,
"version_min":300000,
"title":"Testing Operator :: @rx with PCRE error",
"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":"/?rxtest=wwwwwwwwwwwwwwwwwwwwwowwwwwwwwwww",
"method":"HEAD",
"body": [ ]
},
"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":"rx: regex error 'MATCH_LIMIT' for pattern",
"error_log":"Matched \"Operator `StrEq' with parameter `1' against variable `MSC_PCRE_ERROR'"
},
"rules":[
"SecRuleEngine On",
"SecPcreMatchLimit 2",
"SecRule ARGS:rxtest \"@rx (w+)+$\" \"id:1,phase:1,pass,t:trim,block\"",
"SecRule MSC_PCRE_ERROR \"@streq 1\" \"id:2,phase:1,pass,t:trim,block\""
]
},
{
"enabled":1,
"version_min":300000,
"title":"Testing Operator :: @rx with PCRE match limits exceeded",
"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":"/?rxtest=wwwwwwwwwwwwwwwwwwwwwowwwwwwwwwww",
"method":"HEAD",
"body": [ ]
},
"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":"rx: regex error 'MATCH_LIMIT' for pattern",
"error_log":"Matched \"Operator `StrEq' with parameter `1' against variable `MSC_PCRE_LIMITS_EXCEEDED'"
},
"rules":[
"SecRuleEngine On",
"SecPcreMatchLimit 2",
"SecRule ARGS:rxtest \"@rx (w+)+$\" \"id:1,phase:1,pass,t:trim,block\"",
"SecRule MSC_PCRE_LIMITS_EXCEEDED \"@streq 1\" \"id:2,phase:1,pass,t:trim,block\""
]
},
{
"enabled":1,
"version_min":300000,
"title":"Testing Operator :: @rx with PCRE match limits exceeded",
"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":"/?rxtest=wwwwwwwwwwwwwwwwwwwwwowwwwwwwwwww",
"method":"HEAD",
"body": [ ]
},
"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":"rx: regex error 'MATCH_LIMIT' for pattern",
"error_log":"Matched \"Operator `StrEq' with parameter `1' against variable `TX:MSC_PCRE_LIMITS_EXCEEDED'"
},
"rules":[
"SecRuleEngine On",
"SecPcreMatchLimit 2",
"SecRule ARGS:rxtest \"@rx (w+)+$\" \"id:1,phase:1,pass,t:trim,block\"",
"SecRule TX:MSC_PCRE_LIMITS_EXCEEDED \"@streq 1\" \"id:2,phase:1,pass,t:trim,block\""
]
}
]

View file

@ -162,6 +162,57 @@
"SecRuleEngine On",
"SecRule MULTIPART_PART_HEADERS:parm2 \"@rx content-type:.*jpeg\" \"phase:2,deny,status:403,id:500074,t:lowercase\""
]
},
{
"enabled":1,
"version_min":300000,
"title":"Testing Variables :: MULTIPART_PART_HEADERS (check EOL)",
"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":"249",
"Content-Type":"multipart/form-data; boundary=-----------------------------69343412719991675451336310646",
"Expect":"100-continue"
},
"uri":"/",
"method":"POST",
"body":[
"-------------------------------69343412719991675451336310646",
"Content-Disposition: form-data; name=\"file\"; filename=\"New Text Document.txt\"",
"Content-Type: text/plain; charset=utf-8\r\n",
"",
"1",
"-------------------------------69343412719991675451336310646--"
]
},
"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":{
"http_code": 200
},
"rules":[
"SecRuleEngine On",
"SecRule MULTIPART_PART_HEADERS \"@rx ^content-type\\s*+:\\s*+(.*)$\" \"id:922110,phase:2,deny,capture,t:none,t:lowercase,chain\"",
"SecRule TX:1 \"!@rx ^text/plain; charset=(?:iso-8859-15?|windows-1252|utf-8)$\" \"t:lowercase\""
]
}
]