mirror of
https://github.com/owasp-modsecurity/ModSecurity.git
synced 2025-09-29 19:24:29 +03:00
Adds first PoC for the operator offset feature
This commit is contained in:
committed by
Felipe Zimmerle
parent
9a8fc3116a
commit
ecbf292f6d
@@ -24,7 +24,8 @@ namespace modsecurity {
|
||||
namespace operators {
|
||||
|
||||
|
||||
bool BeginsWith::evaluate(Transaction *transaction, const std::string &str) {
|
||||
bool BeginsWith::evaluate(Transaction *transaction, Rule *rule,
|
||||
const std::string &str, RuleMessage *ruleMessage) {
|
||||
bool ret = false;
|
||||
|
||||
std::string p = MacroExpansion::expand(m_param, transaction);
|
||||
@@ -32,6 +33,7 @@ bool BeginsWith::evaluate(Transaction *transaction, const std::string &str) {
|
||||
if (str.size() < p.size()) {
|
||||
ret = false;
|
||||
} else if (!str.compare(0, p.size(), p)) {
|
||||
logOffset(ruleMessage, 0, p.size());
|
||||
ret = true;
|
||||
}
|
||||
|
||||
|
@@ -32,7 +32,8 @@ class BeginsWith : public Operator {
|
||||
explicit BeginsWith(std::string param)
|
||||
: Operator("BeginsWith", param) { }
|
||||
|
||||
bool evaluate(Transaction *transaction, const std::string &str) override;
|
||||
bool evaluate(Transaction *transaction, Rule *rule, const std::string &str,
|
||||
RuleMessage *ruleMessage) override;
|
||||
};
|
||||
|
||||
} // namespace operators
|
||||
|
@@ -22,11 +22,15 @@
|
||||
namespace modsecurity {
|
||||
namespace operators {
|
||||
|
||||
bool Contains::evaluate(Transaction *transaction, const std::string &input) {
|
||||
bool Contains::evaluate(Transaction *transaction, Rule *rule,
|
||||
const std::string &input, RuleMessage *ruleMessage) {
|
||||
std::string p = MacroExpansion::expand(m_param, transaction);
|
||||
bool contains = input.find(p) != std::string::npos;
|
||||
size_t offset = input.find(p);
|
||||
|
||||
bool contains = offset != std::string::npos;
|
||||
|
||||
if (contains && transaction) {
|
||||
logOffset(ruleMessage, offset, p.size());
|
||||
transaction->m_matched.push_back(p);
|
||||
}
|
||||
|
||||
|
@@ -20,6 +20,7 @@
|
||||
#include <list>
|
||||
|
||||
#include "modsecurity/transaction.h"
|
||||
#include "modsecurity/rule_message.h"
|
||||
#include "src/operators/operator.h"
|
||||
|
||||
|
||||
@@ -33,7 +34,8 @@ class Contains : public Operator {
|
||||
: Operator(op, param, negation) { }
|
||||
explicit Contains(std::string param)
|
||||
: Operator("Contains", param) { }
|
||||
bool evaluate(Transaction *transaction, const std::string &exp) override;
|
||||
bool evaluate(Transaction *transaction, Rule *rule,
|
||||
const std::string &str, RuleMessage *ruleMessage) override;
|
||||
};
|
||||
|
||||
} // namespace operators
|
||||
|
@@ -19,6 +19,7 @@
|
||||
|
||||
#include "src/operators/operator.h"
|
||||
#include "src/macro_expansion.h"
|
||||
#include "modsecurity/rule_message.h"
|
||||
|
||||
namespace modsecurity {
|
||||
namespace operators {
|
||||
@@ -36,8 +37,8 @@ bool ContainsWord::acceptableChar(const std::string& a, size_t pos) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ContainsWord::evaluate(Transaction *transaction,
|
||||
const std::string& input) {
|
||||
bool ContainsWord::evaluate(Transaction *transaction, Rule *rule,
|
||||
const std::string &input, RuleMessage *ruleMessage) {
|
||||
std::string paramTarget = MacroExpansion::expand(m_param, transaction);
|
||||
|
||||
if (paramTarget.empty()) {
|
||||
@@ -53,14 +54,17 @@ bool ContainsWord::evaluate(Transaction *transaction,
|
||||
size_t pos = input.find(paramTarget);
|
||||
while (pos != std::string::npos) {
|
||||
if (pos == 0 && acceptableChar(input, paramTarget.size())) {
|
||||
logOffset(ruleMessage, 0, paramTarget.size());
|
||||
return true;
|
||||
}
|
||||
if (pos + paramTarget.size() == input.size() &&
|
||||
acceptableChar(input, pos - 1)) {
|
||||
logOffset(ruleMessage, pos, paramTarget.size());
|
||||
return true;
|
||||
}
|
||||
if (acceptableChar(input, pos - 1) &&
|
||||
acceptableChar(input, pos + paramTarget.size())) {
|
||||
logOffset(ruleMessage, pos, paramTarget.size());
|
||||
return true;
|
||||
}
|
||||
pos = input.find(paramTarget, pos + 1);
|
||||
|
@@ -19,7 +19,7 @@
|
||||
#include <string>
|
||||
|
||||
#include "src/operators/operator.h"
|
||||
|
||||
#include "modsecurity/rule_message.h"
|
||||
|
||||
namespace modsecurity {
|
||||
namespace operators {
|
||||
@@ -31,7 +31,8 @@ class ContainsWord : public Operator {
|
||||
: Operator(op, param, negation) { }
|
||||
explicit ContainsWord(std::string param)
|
||||
: Operator("ContainsWord", param) { }
|
||||
bool evaluate(Transaction *transaction, const std::string &str);
|
||||
bool evaluate(Transaction *transaction, Rule *rule,
|
||||
const std::string &str, RuleMessage *ruleMessage) override;
|
||||
|
||||
bool acceptableChar(const std::string& a, size_t pos);
|
||||
};
|
||||
|
@@ -24,13 +24,18 @@ namespace modsecurity {
|
||||
namespace operators {
|
||||
|
||||
|
||||
bool EndsWith::evaluate(Transaction *transaction, const std::string &input) {
|
||||
bool EndsWith::evaluate(Transaction *transaction, Rule *rule,
|
||||
const std::string &input, RuleMessage *ruleMessage) {
|
||||
bool ret = false;
|
||||
std::string p = MacroExpansion::expand(m_param, transaction);
|
||||
|
||||
if (input.length() >= p.length()) {
|
||||
ret = (0 == input.compare(input.length() - p.length(),
|
||||
p.length(), p));
|
||||
if (ret) {
|
||||
logOffset(ruleMessage, input.length() - p.length(),
|
||||
p.size());
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@@ -31,7 +31,8 @@ class EndsWith : public Operator {
|
||||
: Operator(op, param, negation) { }
|
||||
explicit EndsWith(std::string param)
|
||||
: Operator("EndsWith", param) { }
|
||||
bool evaluate(Transaction *transaction, const std::string &str) override;
|
||||
bool evaluate(Transaction *transaction, Rule *rule,
|
||||
const std::string &str, RuleMessage *ruleMessage) override;
|
||||
};
|
||||
|
||||
|
||||
|
@@ -74,6 +74,16 @@ bool Operator::debug(Transaction *transaction, int x, std::string a) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Operator::evaluateInternal(Transaction *transaction,
|
||||
Rule *rule, const std::string& a, RuleMessage *rm) {
|
||||
bool res = evaluate(transaction, rule, a, rm);
|
||||
|
||||
if (m_negation) {
|
||||
return !res;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool Operator::evaluateInternal(Transaction *transaction,
|
||||
Rule *rule, const std::string& a) {
|
||||
|
@@ -20,7 +20,7 @@
|
||||
|
||||
#include "modsecurity/transaction.h"
|
||||
#include "modsecurity/rule.h"
|
||||
|
||||
#include "modsecurity/rule_message.h"
|
||||
|
||||
namespace modsecurity {
|
||||
namespace operators {
|
||||
@@ -62,12 +62,30 @@ class Operator {
|
||||
bool evaluateInternal(Transaction *t, const std::string& a);
|
||||
bool evaluateInternal(Transaction *t, Rule *rule,
|
||||
const std::string& a);
|
||||
bool evaluateInternal(Transaction *t, Rule *rule,
|
||||
const std::string& a, RuleMessage *ruleMessage);
|
||||
|
||||
|
||||
virtual bool evaluate(Transaction *transaction, const std::string &str);
|
||||
virtual bool evaluate(Transaction *transaction, Rule *rule,
|
||||
const std::string &str) {
|
||||
return evaluate(transaction, str);
|
||||
}
|
||||
virtual bool evaluate(Transaction *transaction, Rule *rule,
|
||||
const std::string &str, RuleMessage *ruleMessage) {
|
||||
return evaluate(transaction, str);
|
||||
}
|
||||
|
||||
static void logOffset(RuleMessage *ruleMessage, int offset, int len) {
|
||||
if (ruleMessage) {
|
||||
if (ruleMessage->m_reference.empty() == false) {
|
||||
ruleMessage->m_reference.append(";");
|
||||
}
|
||||
ruleMessage->m_reference.append("op:"
|
||||
+ std::to_string(offset) + ","
|
||||
+ std::to_string(len));
|
||||
}
|
||||
}
|
||||
|
||||
std::string m_match_message;
|
||||
bool m_negation;
|
||||
|
@@ -79,7 +79,7 @@ void Pm::postOrderTraversal(acmp_btree_node_t *node) {
|
||||
|
||||
|
||||
bool Pm::evaluate(Transaction *transaction, Rule *rule,
|
||||
const std::string &input) {
|
||||
const std::string &input, RuleMessage *ruleMessage) {
|
||||
int rc = 0;
|
||||
ACMPT pt;
|
||||
pt.parser = m_p;
|
||||
@@ -89,7 +89,8 @@ bool Pm::evaluate(Transaction *transaction, Rule *rule,
|
||||
rc = acmp_process_quick(&pt, &match, input.c_str(), input.length());
|
||||
bool capture = rule && rule->getActionsByName("capture").size() > 0;
|
||||
|
||||
if (rc == 1 && transaction) {
|
||||
if (rc > 0 && transaction) {
|
||||
logOffset(ruleMessage, rc, input.size());
|
||||
transaction->m_matched.push_back(std::string(match));
|
||||
}
|
||||
|
||||
@@ -100,7 +101,7 @@ bool Pm::evaluate(Transaction *transaction, Rule *rule,
|
||||
std::string(match));
|
||||
}
|
||||
|
||||
return rc == 1;
|
||||
return rc > 0;
|
||||
}
|
||||
|
||||
|
||||
|
@@ -44,11 +44,8 @@ class Pm : public Operator {
|
||||
}
|
||||
~Pm();
|
||||
bool evaluate(Transaction *transaction, Rule *rule,
|
||||
const std::string &input) override;
|
||||
bool evaluate(Transaction *transaction,
|
||||
const std::string &input) override {
|
||||
return evaluate(transaction, NULL, input);
|
||||
}
|
||||
const std::string &str, RuleMessage *ruleMessage) override;
|
||||
|
||||
|
||||
bool init(const std::string &file, std::string *error) override;
|
||||
void postOrderTraversal(acmp_btree_node_t *node);
|
||||
|
@@ -21,6 +21,7 @@
|
||||
#include "src/operators/operator.h"
|
||||
#include "src/macro_expansion.h"
|
||||
#include "modsecurity/rule.h"
|
||||
#include "modsecurity/rule_message.h"
|
||||
|
||||
namespace modsecurity {
|
||||
namespace operators {
|
||||
@@ -28,7 +29,7 @@ namespace operators {
|
||||
|
||||
|
||||
bool Rx::evaluate(Transaction *transaction, Rule *rule,
|
||||
const std::string& input) {
|
||||
const std::string& input, RuleMessage *ruleMessage) {
|
||||
SMatch match;
|
||||
std::list<SMatch> matches;
|
||||
|
||||
@@ -50,6 +51,10 @@ bool Rx::evaluate(Transaction *transaction, Rule *rule,
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto & i : matches) {
|
||||
logOffset(ruleMessage, i.m_offset, i.m_length);
|
||||
}
|
||||
|
||||
if (matches.size() > 0) {
|
||||
return true;
|
||||
}
|
||||
|
@@ -51,11 +51,15 @@ class Rx : public Operator {
|
||||
delete m_re;
|
||||
}
|
||||
bool evaluate(Transaction *transaction, Rule *rule,
|
||||
const std::string &input) override;
|
||||
const std::string &input) override {
|
||||
return evaluate(transaction, NULL, input, NULL);
|
||||
}
|
||||
bool evaluate(Transaction *transaction,
|
||||
const std::string &input) override {
|
||||
return evaluate(transaction, NULL, input);
|
||||
}
|
||||
bool evaluate(Transaction *transaction, Rule *rule,
|
||||
const std::string& input, RuleMessage *ruleMessage) override;
|
||||
|
||||
private:
|
||||
Regex *m_re;
|
||||
|
@@ -109,8 +109,8 @@ bool ValidateByteRange::init(const std::string &file,
|
||||
}
|
||||
|
||||
|
||||
bool ValidateByteRange::evaluate(Transaction *transaction,
|
||||
const std::string &input) {
|
||||
bool ValidateByteRange::evaluate(Transaction *transaction, Rule *rule,
|
||||
const std::string &input, RuleMessage *ruleMessage) {
|
||||
bool ret = true;
|
||||
|
||||
size_t count = 0;
|
||||
@@ -119,6 +119,7 @@ bool ValidateByteRange::evaluate(Transaction *transaction,
|
||||
if (!(table[x >> 3] & (1 << (x & 0x7)))) {
|
||||
// debug(9, "Value " + std::to_string(x) + " in " +
|
||||
// input + " ouside range: " + param);
|
||||
logOffset(ruleMessage, i, 1);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
@@ -39,7 +39,8 @@ class ValidateByteRange : public Operator {
|
||||
}
|
||||
~ValidateByteRange() override { }
|
||||
|
||||
bool evaluate(Transaction *transaction, const std::string &input) override;
|
||||
bool evaluate(Transaction *transaction, Rule *rule,
|
||||
const std::string &input, RuleMessage *ruleMessage) override;
|
||||
bool getRange(const std::string &rangeRepresentation, std::string *error);
|
||||
bool init(const std::string& file, std::string *error) override;
|
||||
private:
|
||||
|
@@ -24,8 +24,9 @@ namespace operators {
|
||||
|
||||
|
||||
int ValidateUrlEncoding::validate_url_encoding(const char *input,
|
||||
uint64_t input_length) {
|
||||
uint64_t input_length, size_t *offset) {
|
||||
int i;
|
||||
*offset = 0;
|
||||
|
||||
if ((input == NULL) || (input_length <= 0)) {
|
||||
return -1;
|
||||
@@ -35,6 +36,7 @@ int ValidateUrlEncoding::validate_url_encoding(const char *input,
|
||||
while (i < input_length) {
|
||||
if (input[i] == '%') {
|
||||
if (i + 2 >= input_length) {
|
||||
*offset = i;
|
||||
/* Not enough bytes. */
|
||||
return -3;
|
||||
} else {
|
||||
@@ -53,6 +55,7 @@ int ValidateUrlEncoding::validate_url_encoding(const char *input,
|
||||
i += 3;
|
||||
} else {
|
||||
/* Non-hexadecimal characters used in encoding. */
|
||||
*offset = i;
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
@@ -65,15 +68,16 @@ int ValidateUrlEncoding::validate_url_encoding(const char *input,
|
||||
}
|
||||
|
||||
|
||||
bool ValidateUrlEncoding::evaluate(Transaction *transaction,
|
||||
const std::string &input) {
|
||||
bool ValidateUrlEncoding::evaluate(Transaction *transaction, Rule *rule,
|
||||
const std::string &input, RuleMessage *ruleMessage) {
|
||||
size_t offset = 0;
|
||||
bool res = false;
|
||||
|
||||
if (input.empty() == true) {
|
||||
return res;
|
||||
}
|
||||
|
||||
int rc = validate_url_encoding(input.c_str(), input.size());
|
||||
int rc = validate_url_encoding(input.c_str(), input.size(), &offset);
|
||||
switch (rc) {
|
||||
case 1 :
|
||||
/* Encoding is valid */
|
||||
@@ -90,6 +94,7 @@ bool ValidateUrlEncoding::evaluate(Transaction *transaction,
|
||||
transaction->debug(7, "Invalid URL Encoding: Non-hexadecimal "
|
||||
"digits used at '" + input + "'");
|
||||
#endif
|
||||
logOffset(ruleMessage, offset, input.size());
|
||||
}
|
||||
res = true; /* Invalid match. */
|
||||
break;
|
||||
@@ -99,6 +104,7 @@ bool ValidateUrlEncoding::evaluate(Transaction *transaction,
|
||||
transaction->debug(7, "Invalid URL Encoding: Not enough " \
|
||||
"characters at the end of input at '" + input + "'");
|
||||
#endif
|
||||
logOffset(ruleMessage, offset, input.size());
|
||||
}
|
||||
res = true; /* Invalid match. */
|
||||
break;
|
||||
@@ -110,6 +116,7 @@ bool ValidateUrlEncoding::evaluate(Transaction *transaction,
|
||||
"Error (rc = " + std::to_string(rc) + ") at '" +
|
||||
input + "'");
|
||||
#endif
|
||||
logOffset(ruleMessage, offset, input.size());
|
||||
}
|
||||
res = true;
|
||||
break;
|
||||
|
@@ -32,8 +32,10 @@ class ValidateUrlEncoding : public Operator {
|
||||
ValidateUrlEncoding()
|
||||
: Operator("ValidateUrlEncoding") { }
|
||||
|
||||
bool evaluate(Transaction *transaction, const std::string &input) override;
|
||||
int validate_url_encoding(const char *input, uint64_t input_length);
|
||||
bool evaluate(Transaction *transaction, Rule *rule,
|
||||
const std::string &input, RuleMessage *ruleMessage) override;
|
||||
int validate_url_encoding(const char *input, uint64_t input_length,
|
||||
size_t *offset);
|
||||
};
|
||||
|
||||
} // namespace operators
|
||||
|
@@ -113,8 +113,8 @@ int ValidateUtf8Encoding::detect_utf8_character(
|
||||
return unicode_len;
|
||||
}
|
||||
|
||||
bool ValidateUtf8Encoding::evaluate(Transaction *transaction,
|
||||
const std::string &str) {
|
||||
bool ValidateUtf8Encoding::evaluate(Transaction *transaction, Rule *rule,
|
||||
const std::string &str, RuleMessage *ruleMessage) {
|
||||
unsigned int i, bytes_left;
|
||||
|
||||
const char *str_c = str.c_str();
|
||||
@@ -143,6 +143,7 @@ bool ValidateUtf8Encoding::evaluate(Transaction *transaction,
|
||||
"at " + str + ". [offset \"" +
|
||||
std::to_string(i) + "\"]");
|
||||
#endif
|
||||
logOffset(ruleMessage, i, str.size());
|
||||
}
|
||||
return true;
|
||||
break;
|
||||
@@ -154,6 +155,7 @@ bool ValidateUtf8Encoding::evaluate(Transaction *transaction,
|
||||
"at " + str + ". [offset \"" +
|
||||
std::to_string(i) + "\"]");
|
||||
#endif
|
||||
logOffset(ruleMessage, i, str.size());
|
||||
}
|
||||
return true;
|
||||
break;
|
||||
@@ -165,6 +167,7 @@ bool ValidateUtf8Encoding::evaluate(Transaction *transaction,
|
||||
"at " + str + ". [offset \"" +
|
||||
std::to_string(i) + "\"]");
|
||||
#endif
|
||||
logOffset(ruleMessage, i, str.size());
|
||||
}
|
||||
return true;
|
||||
break;
|
||||
@@ -175,6 +178,7 @@ bool ValidateUtf8Encoding::evaluate(Transaction *transaction,
|
||||
"at " + str + ". [offset \"" +
|
||||
std::to_string(i) + "\"]");
|
||||
#endif
|
||||
logOffset(ruleMessage, i, str.size());
|
||||
}
|
||||
return true;
|
||||
break;
|
||||
@@ -187,6 +191,7 @@ bool ValidateUtf8Encoding::evaluate(Transaction *transaction,
|
||||
"at " + str + ". [offset \"" +
|
||||
std::to_string(i) + "\"]");
|
||||
#endif
|
||||
logOffset(ruleMessage, i, str.size());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@@ -39,7 +39,8 @@ class ValidateUtf8Encoding : public Operator {
|
||||
ValidateUtf8Encoding()
|
||||
: Operator("ValidateUtf8Encoding") { }
|
||||
|
||||
bool evaluate(Transaction *transaction, const std::string &input) override;
|
||||
bool evaluate(Transaction *transaction, Rule *rule,
|
||||
const std::string &str, RuleMessage *ruleMessage) override;
|
||||
|
||||
int detect_utf8_character(const unsigned char *p_read,
|
||||
unsigned int length);
|
||||
|
@@ -24,15 +24,21 @@ namespace modsecurity {
|
||||
namespace operators {
|
||||
|
||||
|
||||
bool Within::evaluate(Transaction *transaction, const std::string &str) {
|
||||
bool Within::evaluate(Transaction *transaction, Rule *rule,
|
||||
const std::string &str, RuleMessage *ruleMessage) {
|
||||
bool res = false;
|
||||
std::string paramTarget = MacroExpansion::expand(m_param, transaction);
|
||||
size_t pos = 0;
|
||||
|
||||
if (str.empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
res = paramTarget.find(str) != std::string::npos;
|
||||
pos = paramTarget.find(str);
|
||||
res = pos != std::string::npos;
|
||||
if (res) {
|
||||
logOffset(ruleMessage, pos, str.size());
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
@@ -31,7 +31,8 @@ class Within : public Operator {
|
||||
: Operator(op, param, negation) { }
|
||||
explicit Within(std::string param)
|
||||
: Operator("Within", param) { }
|
||||
bool evaluate(Transaction *transaction, const std::string &str);
|
||||
bool evaluate(Transaction *transaction, Rule *rule,
|
||||
const std::string &str, RuleMessage *ruleMessage);
|
||||
};
|
||||
|
||||
} // namespace operators
|
||||
|
Reference in New Issue
Block a user