Merge commit 'e0a89a2fcd1d0dd4cc103fc054242e8e8b10b7bf' into dev

This commit is contained in:
Théophile Diot 2023-09-15 14:07:48 +02:00
commit af902fc4ec
No known key found for this signature in database
GPG key ID: 248FEA4BAE400D06
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

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