Adds first PoC for the operator offset feature

This commit is contained in:
Felipe Zimmerle
2017-01-19 14:34:48 -03:00
committed by Felipe Zimmerle
parent 9a8fc3116a
commit ecbf292f6d
89 changed files with 2908 additions and 105 deletions

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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);

View File

@@ -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);
};

View File

@@ -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;

View File

@@ -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;
};

View File

@@ -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) {

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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++;
}
}

View File

@@ -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:

View File

@@ -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;

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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