Adds checks for the NO_LOGS definition and improved the vars resolution time

This commit is contained in:
Felipe Zimmerle 2015-09-17 17:41:38 -03:00
parent 3e067e7409
commit ed86c24df6
46 changed files with 294 additions and 62 deletions

View File

@ -136,7 +136,7 @@ class ModSecurityStringVariables :
l.push_back(pair); l.push_back(pair);
} }
if (l.size() == 0) { if (l.size() == 0 && key.find(":") == std::string::npos) {
for (auto& x : *this) { for (auto& x : *this) {
if ((x.first.substr(0, key.size() + 1).compare(key + ":") != 0) if ((x.first.substr(0, key.size() + 1).compare(key + ":") != 0)
&& (x.first != key)) { && (x.first != key)) {
@ -144,10 +144,8 @@ class ModSecurityStringVariables :
} }
std::list<std::pair<std::string, std::string>> t; std::list<std::pair<std::string, std::string>> t;
t = this->resolveVariable(x.first); t = this->resolveVariable(x.first);
for (std::pair<std::string, std::string> z : t) { if (t.empty() == false) {
pair = std::make_pair(std::string(z.first), l.insert(l.end(), t.begin(), t.end());
std::string(z.second));
l.push_back(pair);
} }
} }
} }
@ -239,8 +237,9 @@ class Assay {
ModSecurityStringVariables m_variables_strings; ModSecurityStringVariables m_variables_strings;
std::unordered_map<std::string, ModSecurityStringVariables *> collections; std::unordered_map<std::string, ModSecurityStringVariables *> collections;
#ifndef NO_LOGS
void debug(int, std::string); void debug(int, std::string);
#endif
void serverLog(const std::string& msg); void serverLog(const std::string& msg);
std::vector<actions::Action *> actions; std::vector<actions::Action *> actions;

View File

@ -33,7 +33,9 @@ Block::Block(std::string action)
bool Block::evaluate(Rule *rule, Assay *assay) { bool Block::evaluate(Rule *rule, Assay *assay) {
#ifndef NO_LOGS
assay->debug(8, "Running action block"); assay->debug(8, "Running action block");
#endif
for (Action *a : rule->actions_runtime_pos) { for (Action *a : rule->actions_runtime_pos) {
if (a->isDisruptive() == true) { if (a->isDisruptive() == true) {
assay->actions.push_back(a); assay->actions.push_back(a);

View File

@ -35,17 +35,16 @@ bool Capture::evaluate(Rule *rule, Assay *assay) {
std::list<std::string> match; std::list<std::string> match;
operators::Pm *pm = dynamic_cast<operators::Pm *>(op); operators::Pm *pm = dynamic_cast<operators::Pm *>(op);
operators::Rx *rx = dynamic_cast<operators::Rx *>(op);
operators::Contains *contains = dynamic_cast<operators::Contains *>(op);
if (pm != NULL) { if (pm != NULL) {
match = pm->matched; match = pm->matched;
} }
operators::Rx *rx = dynamic_cast<operators::Rx *>(op);
if (rx != NULL) { if (rx != NULL) {
match = rx->matched; match = rx->matched;
} }
operators::Contains *contains = dynamic_cast<operators::Contains *>(op);
if (contains != NULL) { if (contains != NULL) {
match = contains->matched; match = contains->matched;
} }

View File

@ -31,7 +31,9 @@ Deny::Deny(std::string action)
bool Deny::evaluate(Rule *rule, Assay *assay) { bool Deny::evaluate(Rule *rule, Assay *assay) {
#ifndef NO_LOGS
assay->debug(8, "Running action deny"); assay->debug(8, "Running action deny");
#endif
assay->actions.push_back(this); assay->actions.push_back(this);
return true; return true;
} }

View File

@ -36,7 +36,9 @@ LogData::LogData(std::string action)
bool LogData::evaluate(Rule *rule, Assay *assay) { bool LogData::evaluate(Rule *rule, Assay *assay) {
std::string msg = MacroExpansion::expand(m_data, assay); std::string msg = MacroExpansion::expand(m_data, assay);
#ifndef NO_LOGS
assay->debug(9, "Saving msg: " + msg); assay->debug(9, "Saving msg: " + msg);
#endif
assay->rulesMessages.push_back(msg); assay->rulesMessages.push_back(msg);
assay->serverLog(msg); assay->serverLog(msg);
return true; return true;

View File

@ -36,7 +36,9 @@ Msg::Msg(std::string action)
bool Msg::evaluate(Rule *rule, Assay *assay) { bool Msg::evaluate(Rule *rule, Assay *assay) {
std::string msg = MacroExpansion::expand(m_msg, assay); std::string msg = MacroExpansion::expand(m_msg, assay);
#ifndef NO_LOGS
assay->debug(9, "Saving msg: " + msg); assay->debug(9, "Saving msg: " + msg);
#endif
assay->rulesMessages.push_back(msg); assay->rulesMessages.push_back(msg);
assay->serverLog(msg); assay->serverLog(msg);
return true; return true;

View File

@ -21,6 +21,7 @@
#include "modsecurity/assay.h" #include "modsecurity/assay.h"
#include "src/rule.h" #include "src/rule.h"
#include "src/macro_expansion.h" #include "src/macro_expansion.h"
#include "src/utils.h"
namespace ModSecurity { namespace ModSecurity {
namespace actions { namespace actions {
@ -57,6 +58,7 @@ bool SetVar::init(std::string *error) {
pos = action.find("."); pos = action.find(".");
if (pos != std::string::npos) { if (pos != std::string::npos) {
collectionName = std::string(action, 0, pos); collectionName = std::string(action, 0, pos);
collectionName = toupper(collectionName);
} else { } else {
error->assign("Missing the collection and/or variable name"); error->assign("Missing the collection and/or variable name");
return false; return false;
@ -140,8 +142,10 @@ bool SetVar::evaluate(Rule *rule, Assay *assay) {
break; break;
} }
#ifndef NO_LOGS
assay->debug(8, "Saving variable: " + collectionName + ":" + \ assay->debug(8, "Saving variable: " + collectionName + ":" + \
variableName + " with value: " + targetValue); variableName + " with value: " + targetValue);
#endif
assay->setCollection(collectionName, variableName, targetValue); assay->setCollection(collectionName, variableName, targetValue);
return true; return true;

View File

@ -51,9 +51,11 @@ Severity::Severity(std::string action)
bool Severity::evaluate(Rule *rule, Assay *assay) { bool Severity::evaluate(Rule *rule, Assay *assay) {
#ifndef NO_LOGS
assay->debug(9, "This rule severity is: " + \ assay->debug(9, "This rule severity is: " + \
std::to_string(this->m_severity) + " current assay is: " + \ std::to_string(this->m_severity) + " current assay is: " + \
std::to_string(assay->highest_severity)); std::to_string(assay->highest_severity));
#endif
if (assay->highest_severity > this->m_severity) { if (assay->highest_severity > this->m_severity) {
assay->highest_severity = this->m_severity; assay->highest_severity = this->m_severity;

View File

@ -32,7 +32,9 @@ SkipAfter::SkipAfter(std::string action)
bool SkipAfter::evaluate(Rule *rule, Assay *assay) { bool SkipAfter::evaluate(Rule *rule, Assay *assay) {
#ifndef NO_LOGS
assay->debug(5, "Setting skipAfter for: " + m_marker); assay->debug(5, "Setting skipAfter for: " + m_marker);
#endif
assay->m_marker = m_marker; assay->m_marker = m_marker;
return true; return true;
} }

View File

@ -36,7 +36,9 @@ Tag::Tag(std::string action)
bool Tag::evaluate(Rule *rule, Assay *assay) { bool Tag::evaluate(Rule *rule, Assay *assay) {
std::string tag = MacroExpansion::expand(m_tag, assay); std::string tag = MacroExpansion::expand(m_tag, assay);
#ifndef NO_LOGS
assay->debug(9, "Rule tag: " + tag); assay->debug(9, "Rule tag: " + tag);
#endif
assay->ruleTags.push_back(tag); assay->ruleTags.push_back(tag);
return true; return true;
} }

View File

@ -41,7 +41,9 @@ std::string Base64Decode::evaluate(std::string value,
* @todo Implement the transformation base64decode * @todo Implement the transformation base64decode
*/ */
if (assay) { if (assay) {
#ifndef NO_LOGS
assay->debug(4, "Transformation 64 is not implemented yet."); assay->debug(4, "Transformation 64 is not implemented yet.");
#endif
} }
return value; return value;
} }

View File

@ -41,8 +41,10 @@ std::string Base64DecodeExt::evaluate(std::string value,
* @todo Implement the transformation Base64DecodeExt * @todo Implement the transformation Base64DecodeExt
*/ */
if (assay) { if (assay) {
#ifndef NO_LOGS
assay->debug(4, "Transformation Base64DecodeExt is" \ assay->debug(4, "Transformation Base64DecodeExt is" \
" not implemented yet."); " not implemented yet.");
#endif
} }
return value; return value;
} }

View File

@ -41,7 +41,9 @@ std::string CmdLine::evaluate(std::string value,
* @todo Implement the transformation CmdLine * @todo Implement the transformation CmdLine
*/ */
if (assay) { if (assay) {
#ifndef NO_LOGS
assay->debug(4, "Transformation CmdLine is not implemented yet."); assay->debug(4, "Transformation CmdLine is not implemented yet.");
#endif
} }
return value; return value;
} }

View File

@ -41,8 +41,10 @@ std::string CompressWhitespace::evaluate(std::string value,
* @todo Implement the transformation CompressWhitespace * @todo Implement the transformation CompressWhitespace
*/ */
if (assay) { if (assay) {
#ifndef NO_LOGS
assay->debug(4, "Transformation CompressWhitespace is " \ assay->debug(4, "Transformation CompressWhitespace is " \
"not implemented yet."); "not implemented yet.");
#endif
} }
return value; return value;
} }

View File

@ -41,8 +41,10 @@ std::string EscapeSeqDecode::evaluate(std::string value,
* @todo Implement the transformation EscapeSeqDecode * @todo Implement the transformation EscapeSeqDecode
*/ */
if (assay) { if (assay) {
#ifndef NO_LOGS
assay->debug(4, "Transformation EscapeSeqDecode is " \ assay->debug(4, "Transformation EscapeSeqDecode is " \
"not implemented yet."); "not implemented yet.");
#endif
} }
return value; return value;
} }

View File

@ -41,7 +41,9 @@ std::string HexDecode::evaluate(std::string value,
* @todo Implement the transformation HexDecode * @todo Implement the transformation HexDecode
*/ */
if (assay) { if (assay) {
#ifndef NO_LOGS
assay->debug(4, "Transformation HexDecode is not implemented yet."); assay->debug(4, "Transformation HexDecode is not implemented yet.");
#endif
} }
return value; return value;
} }

View File

@ -41,7 +41,9 @@ std::string HexEncode::evaluate(std::string value,
* @todo Implement the transformation HexEncode * @todo Implement the transformation HexEncode
*/ */
if (assay) { if (assay) {
#ifndef NO_LOGS
assay->debug(4, "Transformation HexEncode is not implemented yet."); assay->debug(4, "Transformation HexEncode is not implemented yet.");
#endif
} }
return value; return value;
} }

View File

@ -41,7 +41,9 @@ std::string Length::evaluate(std::string value,
* @todo Implement the transformation Length * @todo Implement the transformation Length
*/ */
if (assay) { if (assay) {
#ifndef NO_LOGS
assay->debug(4, "Transformation Length is not implemented yet."); assay->debug(4, "Transformation Length is not implemented yet.");
#endif
} }
return value; return value;
} }

View File

@ -41,7 +41,9 @@ std::string Md5::evaluate(std::string value,
* @todo Implement the transformation Md5 * @todo Implement the transformation Md5
*/ */
if (assay) { if (assay) {
#ifndef NO_LOGS
assay->debug(4, "Transformation Md5 is not implemented yet."); assay->debug(4, "Transformation Md5 is not implemented yet.");
#endif
} }
return value; return value;
} }

View File

@ -41,8 +41,10 @@ std::string NormalisePath::evaluate(std::string value,
* @todo Implement the transformation NormalisePath * @todo Implement the transformation NormalisePath
*/ */
if (assay) { if (assay) {
#ifndef NO_LOGS
assay->debug(4, "Transformation NormalisePath is not" \ assay->debug(4, "Transformation NormalisePath is not" \
" implemented yet."); " implemented yet.");
#endif
} }
return value; return value;
} }

View File

@ -41,8 +41,10 @@ std::string ParityEven7bit::evaluate(std::string value,
* @todo Implement the transformation ParityEven7bit * @todo Implement the transformation ParityEven7bit
*/ */
if (assay) { if (assay) {
#ifndef NO_LOGS
assay->debug(4, "Transformation ParityEven7bit is not" \ assay->debug(4, "Transformation ParityEven7bit is not" \
" implemented yet."); " implemented yet.");
#endif
} }
return value; return value;
} }

View File

@ -41,8 +41,10 @@ std::string ParityOdd7bit::evaluate(std::string value,
* @todo Implement the transformation ParityOdd7bit * @todo Implement the transformation ParityOdd7bit
*/ */
if (assay) { if (assay) {
#ifndef NO_LOGS
assay->debug(4, "Transformation ParityOdd7bit is not " \ assay->debug(4, "Transformation ParityOdd7bit is not " \
"implemented yet."); "implemented yet.");
#endif
} }
return value; return value;
} }

View File

@ -41,8 +41,10 @@ std::string ParityZero7bit::evaluate(std::string value,
* @todo Implement the transformation ParityZero7bit * @todo Implement the transformation ParityZero7bit
*/ */
if (assay) { if (assay) {
#ifndef NO_LOGS
assay->debug(4, "Transformation ParityZero7bit is not" \ assay->debug(4, "Transformation ParityZero7bit is not" \
"implemented yet."); "implemented yet.");
#endif
} }
return value; return value;
} }

View File

@ -41,8 +41,10 @@ std::string RemoveComments::evaluate(std::string value,
* @todo Implement the transformation RemoveComments * @todo Implement the transformation RemoveComments
*/ */
if (assay) { if (assay) {
#ifndef NO_LOGS
assay->debug(4, "Transformation RemoveComments is not " \ assay->debug(4, "Transformation RemoveComments is not " \
"implemented yet."); "implemented yet.");
#endif
} }
return value; return value;
} }

View File

@ -41,8 +41,10 @@ std::string RemoveCommentsChar::evaluate(std::string value,
* @todo Implement the transformation RemoveCommentsChar * @todo Implement the transformation RemoveCommentsChar
*/ */
if (assay) { if (assay) {
#ifndef NO_LOGS
assay->debug(4, "Transformation RemoveCommentsChar " \ assay->debug(4, "Transformation RemoveCommentsChar " \
"is not implemented yet."); "is not implemented yet.");
#endif
} }
return value; return value;
} }

View File

@ -41,8 +41,10 @@ std::string RemoveWhitespace::evaluate(std::string value,
* @todo Implement the transformation RemoveWhitespace * @todo Implement the transformation RemoveWhitespace
*/ */
if (assay) { if (assay) {
#ifndef NO_LOGS
assay->debug(4, "Transformation RemoveWhitespace is " \ assay->debug(4, "Transformation RemoveWhitespace is " \
"not implemented yet."); "not implemented yet.");
#endif
} }
return value; return value;
} }

View File

@ -41,8 +41,10 @@ std::string ReplaceComments::evaluate(std::string value,
* @todo Implement the transformation ReplaceComments * @todo Implement the transformation ReplaceComments
*/ */
if (assay) { if (assay) {
#ifndef NO_LOGS
assay->debug(4, "Transformation ReplaceComments " \ assay->debug(4, "Transformation ReplaceComments " \
"is not implemented yet."); "is not implemented yet.");
#endif
} }
return value; return value;
} }

View File

@ -41,7 +41,9 @@ std::string ReplaceNulls::evaluate(std::string value,
* @todo Implement the transformation ReplaceNulls * @todo Implement the transformation ReplaceNulls
*/ */
if (assay) { if (assay) {
#ifndef NO_LOGS
assay->debug(4, "Transformation ReplaceNulls is not implemented yet."); assay->debug(4, "Transformation ReplaceNulls is not implemented yet.");
#endif
} }
return value; return value;
} }

View File

@ -41,7 +41,9 @@ std::string Sha1::evaluate(std::string value,
* @todo Implement the transformation Sha1 * @todo Implement the transformation Sha1
*/ */
if (assay) { if (assay) {
#ifndef NO_LOGS
assay->debug(4, "Transformation Sha1 is not implemented yet."); assay->debug(4, "Transformation Sha1 is not implemented yet.");
#endif
} }
return value; return value;
} }

View File

@ -41,7 +41,9 @@ std::string SqlHexDecode::evaluate(std::string value,
* @todo Implement the transformation SqlHexDecode * @todo Implement the transformation SqlHexDecode
*/ */
if (assay) { if (assay) {
#ifndef NO_LOGS
assay->debug(4, "Transformation SqlHexDecode is not implemented yet."); assay->debug(4, "Transformation SqlHexDecode is not implemented yet.");
#endif
} }
return value; return value;
} }

View File

@ -41,7 +41,9 @@ std::string UrlDecode::evaluate(std::string value,
* @todo Implement the transformation UrlDecode * @todo Implement the transformation UrlDecode
*/ */
if (assay) { if (assay) {
#ifndef NO_LOGS
assay->debug(4, "Transformation UrlDecode is not implemented yet."); assay->debug(4, "Transformation UrlDecode is not implemented yet.");
#endif
} }
return value; return value;
} }

View File

@ -41,7 +41,9 @@ std::string UrlEncode::evaluate(std::string value,
* @todo Implement the transformation UrlEncode * @todo Implement the transformation UrlEncode
*/ */
if (assay) { if (assay) {
#ifndef NO_LOGS
assay->debug(4, "Transformation UrlEncode is not implemented yet."); assay->debug(4, "Transformation UrlEncode is not implemented yet.");
#endif
} }
return value; return value;
} }

View File

@ -41,7 +41,9 @@ std::string Utf8Unicode::evaluate(std::string value,
* @todo Implement the transformation Utf8Unicode * @todo Implement the transformation Utf8Unicode
*/ */
if (assay) { if (assay) {
#ifndef NO_LOGS
assay->debug(4, "Transformation Utf8Unicode is not implemented yet."); assay->debug(4, "Transformation Utf8Unicode is not implemented yet.");
#endif
} }
return value; return value;
} }

View File

@ -127,7 +127,9 @@ Assay::Assay(ModSecurity *ms, Rules *rules, void *logCbData)
"RESPONSE_HEADERS_NAMES"); "RESPONSE_HEADERS_NAMES");
collections.emplace("TX", new ModSecurityStringVariables()); collections.emplace("TX", new ModSecurityStringVariables());
#ifndef NO_LOGS
this->debug(4, "Initialising transaction"); this->debug(4, "Initialising transaction");
#endif
} }
@ -157,6 +159,7 @@ Assay::~Assay() {
* @param message Message to be logged. * @param message Message to be logged.
* *
*/ */
#ifndef NO_LOGS
void Assay::debug(int level, std::string message) { void Assay::debug(int level, std::string message) {
if (m_rules == NULL) { if (m_rules == NULL) {
return; return;
@ -164,7 +167,7 @@ void Assay::debug(int level, std::string message) {
m_rules->debug(level, message); m_rules->debug(level, message);
} }
#endif
/** /**
* @name processConnection * @name processConnection
@ -193,8 +196,10 @@ int Assay::processConnection(const char *client, int cPort, const char *server,
this->m_serverIpAddress = server; this->m_serverIpAddress = server;
this->m_clientPort = cPort; this->m_clientPort = cPort;
this->m_serverPort = sPort; this->m_serverPort = sPort;
#ifndef NO_LOGS
debug(4, "Transaction context created."); debug(4, "Transaction context created.");
debug(4, "Starting phase CONNECTION. (SecRules 0)"); debug(4, "Starting phase CONNECTION. (SecRules 0)");
#endif
this->store_variable("REMOTE_HOST", m_clientIpAddress); this->store_variable("REMOTE_HOST", m_clientIpAddress);
this->store_variable("UNIQUE_ID", id); this->store_variable("UNIQUE_ID", id);
@ -232,7 +237,10 @@ int Assay::processConnection(const char *client, int cPort, const char *server,
*/ */
int Assay::processURI(const char *uri, const char *protocol, int Assay::processURI(const char *uri, const char *protocol,
const char *http_version) { const char *http_version) {
#ifndef NO_LOGS
debug(4, "Starting phase URI. (SecRules 0 + 1/2)"); debug(4, "Starting phase URI. (SecRules 0 + 1/2)");
#endif
m_protocol = protocol; m_protocol = protocol;
m_httpVersion = http_version; m_httpVersion = http_version;
@ -326,9 +334,10 @@ int Assay::processURI(const char *uri, const char *protocol,
key.length() + value.length(); key.length() + value.length();
this->m_ARGScombinedSizeStr->assign( this->m_ARGScombinedSizeStr->assign(
std::to_string(this->m_ARGScombinedSize)); std::to_string(this->m_ARGScombinedSize));
#ifndef NO_LOGS
debug(4, "Adding request argument (QUERY_STRING): name \"" + \ debug(4, "Adding request argument (QUERY_STRING): name \"" + \
key + "\", value \"" + value + "\""); key + "\", value \"" + value + "\"");
#endif
} }
} }
return true; return true;
@ -350,10 +359,14 @@ int Assay::processURI(const char *uri, const char *protocol,
* *
*/ */
int Assay::processRequestHeaders() { int Assay::processRequestHeaders() {
#ifndef NO_LOGS
debug(4, "Starting phase REQUEST_HEADERS. (SecRules 1)"); debug(4, "Starting phase REQUEST_HEADERS. (SecRules 1)");
#endif
if (m_rules->secRuleEngine == Rules::DisabledRuleEngine) { if (m_rules->secRuleEngine == Rules::DisabledRuleEngine) {
#ifndef NO_LOGS
debug(4, "Rule engine disabled, returning..."); debug(4, "Rule engine disabled, returning...");
#endif
return true; return true;
} }
@ -502,10 +515,14 @@ int Assay::addRequestHeader(const unsigned char *key, size_t key_n,
* *
*/ */
int Assay::processRequestBody() { int Assay::processRequestBody() {
#ifndef NO_LOGS
debug(4, "Starting phase REQUEST_BODY. (SecRules 2)"); debug(4, "Starting phase REQUEST_BODY. (SecRules 2)");
#endif
if (m_rules->secRuleEngine == Rules::DisabledRuleEngine) { if (m_rules->secRuleEngine == Rules::DisabledRuleEngine) {
#ifndef NO_LOGS
debug(4, "Rule engine disabled, returning..."); debug(4, "Rule engine disabled, returning...");
#endif
return true; return true;
} }
@ -538,41 +555,56 @@ int Assay::processRequestBody() {
store_variable("MULTIPART_CRLF_LF_LINES", "0"); store_variable("MULTIPART_CRLF_LF_LINES", "0");
} }
if (m.boundaryStartsWithWhiteSpace) { if (m.boundaryStartsWithWhiteSpace) {
#ifndef NO_LOGS
debug(9, "Multipart: Boundary starts with white space, " \ debug(9, "Multipart: Boundary starts with white space, " \
"setting MULTIPART_STRICT_ERROR to 1"); "setting MULTIPART_STRICT_ERROR to 1");
#endif
update_variable_first("MULTIPART_STRICT_ERROR", "1"); update_variable_first("MULTIPART_STRICT_ERROR", "1");
} }
if (m.boundaryIsQuoted) { if (m.boundaryIsQuoted) {
#ifndef NO_LOGS
debug(9, "Multipart: Boundary is quoted, " \ debug(9, "Multipart: Boundary is quoted, " \
"setting MULTIPART_STRICT_ERROR to 1"); "setting MULTIPART_STRICT_ERROR to 1");
#endif
update_variable_first("MULTIPART_STRICT_ERROR", "1"); update_variable_first("MULTIPART_STRICT_ERROR", "1");
} }
if (m.containsDataAfter) { if (m.containsDataAfter) {
#ifndef NO_LOGS
debug(9, "Multipart: There is data after the boundary, " \ debug(9, "Multipart: There is data after the boundary, " \
"setting MULTIPART_STRICT_ERROR to 1"); "setting MULTIPART_STRICT_ERROR to 1");
#endif
update_variable_first("MULTIPART_STRICT_ERROR", "1"); update_variable_first("MULTIPART_STRICT_ERROR", "1");
store_variable("MULTIPART_UNMATCHED_BOUNDARY", "1"); store_variable("MULTIPART_UNMATCHED_BOUNDARY", "1");
} else { } else {
store_variable("MULTIPART_UNMATCHED_BOUNDARY", "0"); store_variable("MULTIPART_UNMATCHED_BOUNDARY", "0");
} }
if (m.containsDataBefore) { if (m.containsDataBefore) {
#ifndef NO_LOGS
debug(9, "Multipart: There is data before the boundary, " \ debug(9, "Multipart: There is data before the boundary, " \
"setting MULTIPART_STRICT_ERROR to 1"); "setting MULTIPART_STRICT_ERROR to 1");
#endif
update_variable_first("MULTIPART_STRICT_ERROR", "1"); update_variable_first("MULTIPART_STRICT_ERROR", "1");
} }
if (m.lf) { if (m.lf) {
#ifndef NO_LOGS
debug(9, "Multipart: Lines are LF-terminated, " \ debug(9, "Multipart: Lines are LF-terminated, " \
"setting MULTIPART_STRICT_ERROR to 1"); "setting MULTIPART_STRICT_ERROR to 1");
#endif
update_variable_first("MULTIPART_STRICT_ERROR", "1"); update_variable_first("MULTIPART_STRICT_ERROR", "1");
} }
if (m.missingSemicolon) { if (m.missingSemicolon) {
#ifndef NO_LOGS
debug(9, "Multipart: Boundary missing semicolon, " \ debug(9, "Multipart: Boundary missing semicolon, " \
"setting MULTIPART_STRICT_ERROR to 1"); "setting MULTIPART_STRICT_ERROR to 1");
#endif
update_variable_first("MULTIPART_STRICT_ERROR", "1"); update_variable_first("MULTIPART_STRICT_ERROR", "1");
} }
if (m.invalidQuote) { if (m.invalidQuote) {
#ifndef NO_LOGS
debug(9, "Multipart: Invalid quote, " \ debug(9, "Multipart: Invalid quote, " \
"setting MULTIPART_STRICT_ERROR to 1"); "setting MULTIPART_STRICT_ERROR to 1");
#endif
update_variable_first("MULTIPART_STRICT_ERROR", "1"); update_variable_first("MULTIPART_STRICT_ERROR", "1");
} }
} }
@ -682,7 +714,9 @@ int Assay::requestBodyFromFile(const char *path) {
std::string str; std::string str;
if (request_body.is_open() == false) { if (request_body.is_open() == false) {
#ifndef NO_LOGS
debug(3, "Failed to open request body at: " + std::string(path)); debug(3, "Failed to open request body at: " + std::string(path));
#endif
return false; return false;
} }
@ -695,8 +729,10 @@ int Assay::requestBodyFromFile(const char *path) {
const char *buf = str.c_str(); const char *buf = str.c_str();
int len = request_body.tellg(); int len = request_body.tellg();
#ifndef NO_LOGS
debug(9, "Adding request body: " + std::to_string(len) + " bytes. " \ debug(9, "Adding request body: " + std::to_string(len) + " bytes. " \
"Limit set to: " + std::to_string(this->m_rules->requestBodyLimit)); "Limit set to: " + std::to_string(this->m_rules->requestBodyLimit));
#endif
return appendRequestBody(reinterpret_cast<const unsigned char*>(buf), len); return appendRequestBody(reinterpret_cast<const unsigned char*>(buf), len);
} }
@ -704,25 +740,33 @@ int Assay::requestBodyFromFile(const char *path) {
int Assay::appendRequestBody(const unsigned char *buf, size_t len) { int Assay::appendRequestBody(const unsigned char *buf, size_t len) {
int current_size = this->m_requestBody.tellp(); int current_size = this->m_requestBody.tellp();
#ifndef NO_LOGS
debug(9, "Appending request body: " + std::to_string(len) + " bytes. " \ debug(9, "Appending request body: " + std::to_string(len) + " bytes. " \
"Limit set to: " + std::to_string(this->m_rules->requestBodyLimit)); "Limit set to: " + std::to_string(this->m_rules->requestBodyLimit));
#endif
if (this->m_rules->requestBodyLimit > 0 if (this->m_rules->requestBodyLimit > 0
&& this->m_rules->requestBodyLimit < len + current_size) { && this->m_rules->requestBodyLimit < len + current_size) {
store_variable("INBOUND_DATA_ERROR", "1"); store_variable("INBOUND_DATA_ERROR", "1");
#ifndef NO_LOGS
debug(5, "Request body is bigger than the maximum expected."); debug(5, "Request body is bigger than the maximum expected.");
#endif
if (this->m_rules->requestBodyLimitAction == if (this->m_rules->requestBodyLimitAction ==
Rules::BodyLimitAction::ProcessPartialBodyLimitAction) { Rules::BodyLimitAction::ProcessPartialBodyLimitAction) {
size_t spaceLeft = this->m_rules->requestBodyLimit - current_size; size_t spaceLeft = this->m_rules->requestBodyLimit - current_size;
this->m_requestBody.write(reinterpret_cast<const char*>(buf), this->m_requestBody.write(reinterpret_cast<const char*>(buf),
spaceLeft); spaceLeft);
#ifndef NO_LOGS
debug(5, "Request body limit is marked to process partial"); debug(5, "Request body limit is marked to process partial");
#endif
return false; return false;
} else { } else {
if (this->m_rules->requestBodyLimitAction == if (this->m_rules->requestBodyLimitAction ==
Rules::BodyLimitAction::RejectBodyLimitAction) { Rules::BodyLimitAction::RejectBodyLimitAction) {
#ifndef NO_LOGS
debug(5, "Request body limit is marked to reject the " \ debug(5, "Request body limit is marked to reject the " \
"request"); "request");
#endif
Action *a = new actions::Deny("deny"); Action *a = new actions::Deny("deny");
a->temporaryAction = true; a->temporaryAction = true;
actions.push_back(a); actions.push_back(a);
@ -752,10 +796,14 @@ int Assay::appendRequestBody(const unsigned char *buf, size_t len) {
* *
*/ */
int Assay::processResponseHeaders() { int Assay::processResponseHeaders() {
#ifndef NO_LOGS
debug(4, "Starting phase RESPONSE_HEADERS. (SecRules 3)"); debug(4, "Starting phase RESPONSE_HEADERS. (SecRules 3)");
#endif
if (m_rules->secRuleEngine == Rules::DisabledRuleEngine) { if (m_rules->secRuleEngine == Rules::DisabledRuleEngine) {
#ifndef NO_LOGS
debug(4, "Rule engine disabled, returning..."); debug(4, "Rule engine disabled, returning...");
#endif
return true; return true;
} }
@ -869,10 +917,14 @@ int Assay::addResponseHeader(const unsigned char *key, size_t key_n,
* *
*/ */
int Assay::processResponseBody() { int Assay::processResponseBody() {
#ifndef NO_LOGS
debug(4, "Starting phase RESPONSE_BODY. (SecRules 4)"); debug(4, "Starting phase RESPONSE_BODY. (SecRules 4)");
#endif
if (m_rules->secRuleEngine == Rules::DisabledRuleEngine) { if (m_rules->secRuleEngine == Rules::DisabledRuleEngine) {
#ifndef NO_LOGS
debug(4, "Rule engine disabled, returning..."); debug(4, "Rule engine disabled, returning...");
#endif
return true; return true;
} }
@ -910,26 +962,34 @@ int Assay::processResponseBody() {
int Assay::appendResponseBody(const unsigned char *buf, size_t len) { int Assay::appendResponseBody(const unsigned char *buf, size_t len) {
int current_size = this->m_responseBody.tellp(); int current_size = this->m_responseBody.tellp();
#ifndef NO_LOGS
debug(9, "Appending response body: " + std::to_string(len + current_size) debug(9, "Appending response body: " + std::to_string(len + current_size)
+ " bytes. Limit set to: " + + " bytes. Limit set to: " +
std::to_string(this->m_rules->responseBodyLimit)); std::to_string(this->m_rules->responseBodyLimit));
#endif
if (this->m_rules->responseBodyLimit > 0 if (this->m_rules->responseBodyLimit > 0
&& this->m_rules->responseBodyLimit < len + current_size) { && this->m_rules->responseBodyLimit < len + current_size) {
store_variable("OUTBOUND_DATA_ERROR", "1"); store_variable("OUTBOUND_DATA_ERROR", "1");
#ifndef NO_LOGS
debug(5, "Response body is bigger than the maximum expected."); debug(5, "Response body is bigger than the maximum expected.");
#endif
if (this->m_rules->responseBodyLimitAction == if (this->m_rules->responseBodyLimitAction ==
Rules::BodyLimitAction::ProcessPartialBodyLimitAction) { Rules::BodyLimitAction::ProcessPartialBodyLimitAction) {
size_t spaceLeft = this->m_rules->responseBodyLimit - current_size; size_t spaceLeft = this->m_rules->responseBodyLimit - current_size;
this->m_responseBody.write(reinterpret_cast<const char*>(buf), this->m_responseBody.write(reinterpret_cast<const char*>(buf),
spaceLeft); spaceLeft);
#ifndef NO_LOGS
debug(5, "Response body limit is marked to process partial"); debug(5, "Response body limit is marked to process partial");
#endif
return false; return false;
} else { } else {
if (this->m_rules->responseBodyLimitAction == if (this->m_rules->responseBodyLimitAction ==
Rules::BodyLimitAction::RejectBodyLimitAction) { Rules::BodyLimitAction::RejectBodyLimitAction) {
#ifndef NO_LOGS
debug(5, "Response body limit is marked to reject the " \ debug(5, "Response body limit is marked to reject the " \
"request"); "request");
#endif
Action *a = new actions::Deny("deny"); Action *a = new actions::Deny("deny");
a->temporaryAction = true; a->temporaryAction = true;
actions.push_back(a); actions.push_back(a);
@ -1005,10 +1065,14 @@ int Assay::getResponseBodyLenth() {
* *
*/ */
int Assay::processLogging(int returned_code) { int Assay::processLogging(int returned_code) {
#ifndef NO_LOGS
debug(4, "Starting phase LOGGING. (SecRules 5)"); debug(4, "Starting phase LOGGING. (SecRules 5)");
#endif
if (m_rules->secRuleEngine == Rules::DisabledRuleEngine) { if (m_rules->secRuleEngine == Rules::DisabledRuleEngine) {
#ifndef NO_LOGS
debug(4, "Rule engine disabled, returning..."); debug(4, "Rule engine disabled, returning...");
#endif
return true; return true;
} }
@ -1017,12 +1081,16 @@ int Assay::processLogging(int returned_code) {
/* If relevant, save this assay information at the audit_logs */ /* If relevant, save this assay information at the audit_logs */
if (m_rules != NULL && m_rules->audit_log != NULL) { if (m_rules != NULL && m_rules->audit_log != NULL) {
#ifndef NO_LOGS
debug(8, "Checking if this request is suitable to be saved as an audit log."); debug(8, "Checking if this request is suitable to be saved as an audit log.");
#endif
int parts = -1; int parts = -1;
if (this->auditLogModifier.size() > 0) if (this->auditLogModifier.size() > 0)
{ {
#ifndef NO_LOGS
debug(4, "There was an audit log modifier for this transaction."); debug(4, "There was an audit log modifier for this transaction.");
#endif
std::list<std::pair<int, std::string>>::iterator it; std::list<std::pair<int, std::string>>::iterator it;
parts = this->m_rules->audit_log->m_parts; parts = this->m_rules->audit_log->m_parts;
for (it = auditLogModifier.begin(); it != auditLogModifier.end(); ++it) { for (it = auditLogModifier.begin(); it != auditLogModifier.end(); ++it) {
@ -1034,6 +1102,7 @@ int Assay::processLogging(int returned_code) {
} }
} }
} }
#ifndef NO_LOGS
if (save_in_auditlog) { if (save_in_auditlog) {
debug(8, "This request was marked to be saved via auditlog action."); debug(8, "This request was marked to be saved via auditlog action.");
} }
@ -1042,6 +1111,7 @@ int Assay::processLogging(int returned_code) {
if (saved) { if (saved) {
debug(8, "Request was relevant to be saved."); debug(8, "Request was relevant to be saved.");
} }
#endif
} }
return true; return true;
@ -1079,6 +1149,7 @@ void Assay::cleanup() {
bool Assay::intervention(ModSecurityIntervention *it) { bool Assay::intervention(ModSecurityIntervention *it) {
it->status = 200; it->status = 200;
it->url = NULL; it->url = NULL;
it->disruptive = false;
if (actions.size() > 0) { if (actions.size() > 0) {
for (Action *a : actions) { for (Action *a : actions) {
if (a->action_kind == Action::Kind::RunTimeOnlyIfMatchKind) { if (a->action_kind == Action::Kind::RunTimeOnlyIfMatchKind) {
@ -1405,50 +1476,15 @@ std::list<std::pair<std::string, std::string>>
std::list<std::pair<std::string, std::string>> l; std::list<std::pair<std::string, std::string>> l;
std::pair<std::string, std::string> pair; std::pair<std::string, std::string> pair;
auto range = m_variables_strings.equal_range(var); l = m_variables_strings.resolveVariable(var);
for (auto it = range.first; it != range.second; ++it) {
pair = std::make_pair(std::string(var), std::string(it->second));
l.push_back(pair);
}
if (l.empty()) {
for (auto &x : m_variables_strings) {
if ((x.first.substr(0, var.size() + 1).compare(var + ":") != 0)
&& (x.first != var)) {
continue;
}
std::list<std::pair<std::string, std::string>> t;
t = resolve_variable(x.first);
for (std::pair<std::string, std::string> z : t) {
pair = std::make_pair(std::string(z.first),
std::string(z.second));
l.push_back(pair);
}
}
}
size_t ac = var.find(":");
if (ac != std::string::npos) {
/* It may be a collection */
for (auto &a : collections) { for (auto &a : collections) {
auto range = a.second->equal_range(var); std::list<std::pair<std::string, std::string>> l2 = a.second->resolveVariable(var);
if (l2.empty() == false) {
for (auto it = range.first; it != range.second; ++it) { l.insert(l.end(), l2.begin(), l2.end());
pair = std::make_pair(std::string(var), std::string(it->second));
l.push_back(pair);
}
if (l.empty()) {
for (auto &x : *a.second) {
if ((x.first.substr(0, var.size() + 1).compare(var + ":") != 0)
&& (x.first != var)) {
continue;
}
std::list<std::pair<std::string, std::string>> t;
t = resolve_variable(x.first);
for (std::pair<std::string, std::string> z : t) {
pair = std::make_pair(std::string(z.first),
std::string(z.second));
l.push_back(pair);
}
} }
} }
} }
@ -1500,12 +1536,14 @@ void Assay::setCollection(const std::string& collectionName,
try { try {
ModSecurityStringVariables *collection; ModSecurityStringVariables *collection;
collection = collections.at(toupper(collectionName)); collection = collections.at(collectionName);
collection->storeOrUpdateVariable(toupper(collectionName) + ":" collection->storeOrUpdateVariable(collectionName + ":"
+ variableName, targetValue); + variableName, targetValue);
} catch (...) { } catch (...) {
#ifndef NO_LOGS
debug(9, "don't know any collection named: " debug(9, "don't know any collection named: "
+ collectionName + ". it was created?"); + collectionName + ". it was created?");
#endif
return; return;
} }
} }

View File

@ -35,14 +35,18 @@ bool DetectSQLi::evaluate(Assay *assay, const std::string &input) {
if (issqli) { if (issqli) {
// set_match_to_tx(msr, capture, fingerprint, 0); // set_match_to_tx(msr, capture, fingerprint, 0);
if (assay) { if (assay) {
#ifndef NO_LOGS
assay->debug(4, "detected SQLi using libinjection with " \ assay->debug(4, "detected SQLi using libinjection with " \
"fingerprint '" + std::string(fingerprint) + "' at: '" + "fingerprint '" + std::string(fingerprint) + "' at: '" +
input + "'"); input + "'");
#endif
} }
} else { } else {
if (assay) { if (assay) {
#ifndef NO_LOGS
assay->debug(9, "detected SQLi: not able to find an inject on '" + assay->debug(9, "detected SQLi: not able to find an inject on '" +
input + "'"); input + "'");
#endif
} }
} }

View File

@ -32,12 +32,16 @@ bool DetectXSS::evaluate(Assay *assay, const std::string &input) {
if (is_xss) { if (is_xss) {
if (assay) { if (assay) {
#ifndef NO_LOGS
assay->debug(5, "detected XSS using libinjection."); assay->debug(5, "detected XSS using libinjection.");
#endif
} }
} else { } else {
if (assay) { if (assay) {
#ifndef NO_LOGS
assay->debug(9, "libinjection was not able to " \ assay->debug(9, "libinjection was not able to " \
"find any XSS in: " + input); "find any XSS in: " + input);
#endif
} }
} }

View File

@ -67,18 +67,24 @@ namespace operators {
bool Operator::debug(Assay *assay, int x, std::string a) { bool Operator::debug(Assay *assay, int x, std::string a) {
#ifndef NO_LOGS
assay->debug(x, a); assay->debug(x, a);
#endif
return true; return true;
} }
bool Operator::evaluate(Assay *assay) { bool Operator::evaluate(Assay *assay) {
if (assay) { if (assay) {
#ifndef NO_LOGS
assay->debug(2, "Operator: " + this->op + \ assay->debug(2, "Operator: " + this->op + \
" is not implemented or malfunctioning."); " is not implemented or malfunctioning.");
#endif
} else { } else {
#ifndef NO_LOGS
std::cerr << "Operator: " + this->op + \ std::cerr << "Operator: " + this->op + \
" is not implemented or malfunctioning."; " is not implemented or malfunctioning.";
#endif
} }
return true; return true;
} }
@ -86,11 +92,15 @@ bool Operator::evaluate(Assay *assay) {
bool Operator::evaluate(Assay *assay, const std::string& a) { bool Operator::evaluate(Assay *assay, const std::string& a) {
if (assay) { if (assay) {
#ifndef NO_LOGS
assay->debug(2, "Operator: " + this->op + \ assay->debug(2, "Operator: " + this->op + \
" is not implemented or malfunctioning."); " is not implemented or malfunctioning.");
#endif
} else { } else {
#ifndef NO_LOGS
std::cerr << "Operator: " + this->op + \ std::cerr << "Operator: " + this->op + \
" is not implemented or malfunctioning."; " is not implemented or malfunctioning.";
#endif
} }
return true; return true;

View File

@ -77,29 +77,37 @@ bool ValidateUrlEncoding::evaluate(Assay *assay, const std::string &input) {
case 1 : case 1 :
/* Encoding is valid */ /* Encoding is valid */
if (assay) { if (assay) {
#ifndef NO_LOGS
assay->debug(7, "Valid URL Encoding at '" +input + "'"); assay->debug(7, "Valid URL Encoding at '" +input + "'");
#endif
} }
res = false; res = false;
break; break;
case -2 : case -2 :
if (assay) { if (assay) {
#ifndef NO_LOGS
assay->debug(7, "Invalid URL Encoding: Non-hexadecimal " assay->debug(7, "Invalid URL Encoding: Non-hexadecimal "
"digits used at '" + input + "'"); "digits used at '" + input + "'");
#endif
} }
res = true; /* Invalid match. */ res = true; /* Invalid match. */
break; break;
case -3 : case -3 :
if (assay) { if (assay) {
#ifndef NO_LOGS
assay->debug(7, "Invalid URL Encoding: Not enough characters " assay->debug(7, "Invalid URL Encoding: Not enough characters "
"at the end of input at '" + input + "'"); "at the end of input at '" + input + "'");
#endif
} }
res = true; /* Invalid match. */ res = true; /* Invalid match. */
break; break;
case -1 : case -1 :
default : default :
if (assay) { if (assay) {
#ifndef NO_LOGS
assay->debug(7, "Invalid URL Encoding: Internal Error (rc = " + assay->debug(7, "Invalid URL Encoding: Internal Error (rc = " +
std::to_string(rc) + ") at '" + input + "'"); std::to_string(rc) + ") at '" + input + "'");
#endif
} }
res = true; res = true;
break; break;

View File

@ -125,45 +125,55 @@ bool ValidateUtf8Encoding::evaluate(Assay *assay, const std::string &str) {
switch (rc) { switch (rc) {
case UNICODE_ERROR_CHARACTERS_MISSING : case UNICODE_ERROR_CHARACTERS_MISSING :
if (assay) { if (assay) {
#ifndef NO_LOGS
assay->debug(8, "Invalid UTF-8 encoding: " assay->debug(8, "Invalid UTF-8 encoding: "
"not enough bytes in character " "not enough bytes in character "
"at " + str + ". [offset \"" + "at " + str + ". [offset \"" +
std::to_string(i) + "\"]"); std::to_string(i) + "\"]");
#endif
} }
return true; return true;
break; break;
case UNICODE_ERROR_INVALID_ENCODING : case UNICODE_ERROR_INVALID_ENCODING :
if (assay) { if (assay) {
#ifndef NO_LOGS
assay->debug(8, "Invalid UTF-8 encoding: " assay->debug(8, "Invalid UTF-8 encoding: "
"invalid byte value in character " "invalid byte value in character "
"at " + str + ". [offset \"" + "at " + str + ". [offset \"" +
std::to_string(i) + "\"]"); std::to_string(i) + "\"]");
#endif
} }
return true; return true;
break; break;
case UNICODE_ERROR_OVERLONG_CHARACTER : case UNICODE_ERROR_OVERLONG_CHARACTER :
if (assay) { if (assay) {
#ifndef NO_LOGS
assay->debug(8, "Invalid UTF-8 encoding: " assay->debug(8, "Invalid UTF-8 encoding: "
"overlong character detected " "overlong character detected "
"at " + str + ". [offset \"" + "at " + str + ". [offset \"" +
std::to_string(i) + "\"]"); std::to_string(i) + "\"]");
#endif
} }
return true; return true;
break; break;
case UNICODE_ERROR_RESTRICTED_CHARACTER : case UNICODE_ERROR_RESTRICTED_CHARACTER :
if (assay) { if (assay) {
#ifndef NO_LOGS
assay->debug(8, "Invalid UTF-8 encoding: " assay->debug(8, "Invalid UTF-8 encoding: "
"use of restricted character " "use of restricted character "
"at " + str + ". [offset \"" + "at " + str + ". [offset \"" +
std::to_string(i) + "\"]"); std::to_string(i) + "\"]");
#endif
} }
return true; return true;
break; break;
case UNICODE_ERROR_DECODING_ERROR : case UNICODE_ERROR_DECODING_ERROR :
if (assay) { if (assay) {
#ifndef NO_LOGS
assay->debug(8, "Error validating UTF-8 decoding " assay->debug(8, "Error validating UTF-8 decoding "
"at " + str + ". [offset \"" + "at " + str + ". [offset \"" +
std::to_string(i) + "\"]"); std::to_string(i) + "\"]");
#endif
} }
return true; return true;
break; break;
@ -171,9 +181,11 @@ bool ValidateUtf8Encoding::evaluate(Assay *assay, const std::string &str) {
if (rc <= 0) { if (rc <= 0) {
if (assay) { if (assay) {
#ifndef NO_LOGS
assay->debug(8, "Internal error during UTF-8 validation " assay->debug(8, "Internal error during UTF-8 validation "
"at " + str + ". [offset \"" + "at " + str + ". [offset \"" +
std::to_string(i) + "\"]"); std::to_string(i) + "\"]");
#endif
} }
return true; return true;
} }

View File

@ -79,9 +79,11 @@ bool VerifyCC::evaluate(Assay *assay, const std::string &i) {
is_cc = luhnVerify(match.c_str(), match.size()); is_cc = luhnVerify(match.c_str(), match.size());
if (is_cc) { if (is_cc) {
if (assay) { if (assay) {
#ifndef NO_LOGS
assay->debug(9, "CC# match \"" + param + assay->debug(9, "CC# match \"" + param +
"\" at " + i + ". [offset " + "\" at " + i + ". [offset " +
std::to_string(offset) + "]"); std::to_string(offset) + "]");
#endif
} }
return true; return true;
} }

View File

@ -40,15 +40,19 @@ Multipart::Multipart(std:: string header, Assay *assay)
bool Multipart::init() { bool Multipart::init() {
if (m_header.length() > 1024) { if (m_header.length() > 1024) {
#ifndef NO_LOGS
debug(4, "Multipart: Invalid boundary in Content-Type (length)."); debug(4, "Multipart: Invalid boundary in Content-Type (length).");
#endif
return false; return false;
} }
std::size_t boundary_pos = m_header.find("boundary"); std::size_t boundary_pos = m_header.find("boundary");
if (boundary_pos != std::string::npos && if (boundary_pos != std::string::npos &&
m_header.find("boundary", boundary_pos + 1) != std::string::npos) { m_header.find("boundary", boundary_pos + 1) != std::string::npos) {
#ifndef NO_LOGS
debug(4, "Multipart: Multiple boundary parameters in " \ debug(4, "Multipart: Multiple boundary parameters in " \
"Content-Type."); "Content-Type.");
#endif
return false; return false;
} }
@ -56,35 +60,47 @@ bool Multipart::init() {
std::size_t semicolon_pos = boundary.find(";"); std::size_t semicolon_pos = boundary.find(";");
if (semicolon_pos != std::string::npos if (semicolon_pos != std::string::npos
&& boundary.find(";", semicolon_pos + 1) != std::string::npos) { && boundary.find(";", semicolon_pos + 1) != std::string::npos) {
#ifndef NO_LOGS
debug(4, "Multipart: Invalid boundary in Content-Type. (malformed). " \ debug(4, "Multipart: Invalid boundary in Content-Type. (malformed). " \
"Too many semicolons."); "Too many semicolons.");
#endif
return false; return false;
} }
if (semicolon_pos == std::string::npos) { if (semicolon_pos == std::string::npos) {
#ifndef NO_LOGS
debug(4, "Multipart: Missing semicolon."); debug(4, "Multipart: Missing semicolon.");
#endif
this->missingSemicolon = true; this->missingSemicolon = true;
} }
if (boundary.at(8) != '=') { if (boundary.at(8) != '=') {
#ifndef NO_LOGS
debug(4, "Multipart: Invalid boundary in Content-Type. (malformed). " \ debug(4, "Multipart: Invalid boundary in Content-Type. (malformed). " \
"Missing equals."); "Missing equals.");
#endif
return false; return false;
} }
if (boundary.at(8 + 1) == ' ') { if (boundary.at(8 + 1) == ' ') {
boundaryStartsWithWhiteSpace = true; boundaryStartsWithWhiteSpace = true;
#ifndef NO_LOGS
debug(4, "Multipart: Boundary starts with a white space"); debug(4, "Multipart: Boundary starts with a white space");
#endif
} }
if ((boundaryStartsWithWhiteSpace && boundary.at(8 + 2) == '"') || if ((boundaryStartsWithWhiteSpace && boundary.at(8 + 2) == '"') ||
(!boundaryStartsWithWhiteSpace && boundary.at(8 + 1) == '"')) { (!boundaryStartsWithWhiteSpace && boundary.at(8 + 1) == '"')) {
boundaryIsQuoted = true; boundaryIsQuoted = true;
#ifndef NO_LOGS
debug(4, "Multipart: Boundary inside quotes"); debug(4, "Multipart: Boundary inside quotes");
#endif
} }
if (boundaryIsQuoted && boundary.at(boundary.length()-1) != '"') { if (boundaryIsQuoted && boundary.at(boundary.length()-1) != '"') {
#ifndef NO_LOGS
debug(4, "Multipart: Invalid boundary in Content-type (quote)."); debug(4, "Multipart: Invalid boundary in Content-type (quote).");
#endif
return false; return false;
} }
@ -116,8 +132,10 @@ bool Multipart::init() {
} }
if (boundaryContainsOnlyValidCharacters() == false) { if (boundaryContainsOnlyValidCharacters() == false) {
#ifndef NO_LOGS
debug(4, "Multipart: Invalid boundary in Content-type " \ debug(4, "Multipart: Invalid boundary in Content-type " \
"(invalid characters)."); "(invalid characters).");
#endif
return false; return false;
} }
@ -190,7 +208,9 @@ bool Multipart::process(std::string data) {
double files_size = 0; double files_size = 0;
if (start != 0) { if (start != 0) {
#ifndef NO_LOGS
debug(4, "Multipart: Boundary was not the first thing."); debug(4, "Multipart: Boundary was not the first thing.");
#endif
this->containsDataBefore = true; this->containsDataBefore = true;
} }
while (start != std::string::npos) { while (start != std::string::npos) {
@ -230,7 +250,9 @@ bool Multipart::process(std::string data) {
int i = 0; int i = 0;
for (std::string x : blobs) { for (std::string x : blobs) {
i++; i++;
#ifndef NO_LOGS
debug(5, "Multipart: Inspecting blob: " + std::to_string(i)); debug(5, "Multipart: Inspecting blob: " + std::to_string(i));
#endif
MultipartBlob m(x, this); MultipartBlob m(x, this);
if (m.name.empty() == false) { if (m.name.empty() == false) {
@ -249,11 +271,15 @@ bool Multipart::process(std::string data) {
variables.emplace("FILES_NAMES:" + name, name); variables.emplace("FILES_NAMES:" + name, name);
variables.emplace("FILES_SIZES:" + name, variables.emplace("FILES_SIZES:" + name,
std::to_string(m.content.size())); std::to_string(m.content.size()));
#ifndef NO_LOGS
debug(5, "Multipart: Saving FILES_TMP_CONTENT:" + name + " variable."); debug(5, "Multipart: Saving FILES_TMP_CONTENT:" + name + " variable.");
#endif
variables.emplace("FILES_TMP_CONTENT:" + name, m.content); variables.emplace("FILES_TMP_CONTENT:" + name, m.content);
files_size = files_size + m.content.size(); files_size = files_size + m.content.size();
if (m.invalidQuote) { if (m.invalidQuote) {
#ifndef NO_LOGS
debug(4, "Multipart: Found invalid quoting."); debug(4, "Multipart: Found invalid quoting.");
#endif
this->invalidQuote = true; this->invalidQuote = true;
} }
} }

View File

@ -45,10 +45,11 @@ class Multipart {
bool boundaryIsQuoted; bool boundaryIsQuoted;
bool missingSemicolon; bool missingSemicolon;
bool invalidQuote; bool invalidQuote;
#ifndef NO_LOGS
void debug(int a, std::string str) { void debug(int a, std::string str) {
m_assay->debug(a, str); m_assay->debug(a, str);
} }
#endif
private: private:
std::string m_boundary; std::string m_boundary;
std::string m_header; std::string m_header;

View File

@ -37,14 +37,18 @@ bool MultipartBlob::processContent() {
end = m_blob.find("\n", offset); end = m_blob.find("\n", offset);
if (end == std::string::npos) { if (end == std::string::npos) {
#ifndef NO_LOGS
debug(4, "Missing end of line"); debug(4, "Missing end of line");
#endif
return false; return false;
} }
std::string firstLine = std::string(m_blob, offset, end); std::string firstLine = std::string(m_blob, offset, end);
offset = end + 1; offset = end + 1;
end = m_blob.find("\n", offset); end = m_blob.find("\n", offset);
if (end == std::string::npos) { if (end == std::string::npos) {
#ifndef NO_LOGS
debug(4, "Missing end of line"); debug(4, "Missing end of line");
#endif
return false; return false;
} }
std::string secondLine = std::string(m_blob, offset, end - offset); std::string secondLine = std::string(m_blob, offset, end - offset);
@ -63,7 +67,9 @@ bool MultipartBlob::processContent() {
if (contentType.empty() == false) { if (contentType.empty() == false) {
end = m_blob.find_first_of("\n", offset); end = m_blob.find_first_of("\n", offset);
if (end == std::string::npos) { if (end == std::string::npos) {
#ifndef NO_LOGS
debug(4, "Missing end of line"); debug(4, "Missing end of line");
#endif
return false; return false;
} }
offset = end + 1; offset = end + 1;
@ -94,7 +100,9 @@ bool MultipartBlob::processContentDispositionLine(
if (dispositionLine.size() < 30 || if (dispositionLine.size() < 30 ||
dispositionLine.compare(21, 9, "form-data") != 0) { dispositionLine.compare(21, 9, "form-data") != 0) {
#ifndef NO_LOGS
debug(4, "Multipart: Content-Disposition is unknown"); debug(4, "Multipart: Content-Disposition is unknown");
#endif
return false; return false;
} }

View File

@ -37,9 +37,12 @@ class MultipartBlob {
std::string filename; std::string filename;
std::string contentType; std::string contentType;
std::string content; std::string content;
#ifndef NO_LOGS
void debug(int a, std::string str) { void debug(int a, std::string str) {
m_parent->debug(a, str); m_parent->debug(a, str);
} }
#endif
private: private:
const std::string m_blob; const std::string m_blob;
Multipart *m_parent; Multipart *m_parent;

View File

@ -138,7 +138,9 @@ bool Rule::evaluateActions(Assay *assay) {
} }
} }
#ifndef NO_LOGS
assay->debug(4, "Running unconditional rule."); assay->debug(4, "Running unconditional rule.");
#endif
if (none == 0) { if (none == 0) {
/* /*
@ -172,7 +174,9 @@ bool Rule::evaluateActions(Assay *assay) {
for (Action *a : this->actions_runtime_pos) { for (Action *a : this->actions_runtime_pos) {
if (a->isDisruptive() == false) { if (a->isDisruptive() == false) {
#ifndef NO_LOGS
assay->debug(4, "Running (_non_ disruptive) action: " + a->action); assay->debug(4, "Running (_non_ disruptive) action: " + a->action);
#endif
a->evaluate(this, assay); a->evaluate(this, assay);
} else { } else {
containsDisruptive = true; containsDisruptive = true;
@ -183,28 +187,36 @@ bool Rule::evaluateActions(Assay *assay) {
if (a->action_kind == actions::Action::RunTimeOnlyIfMatchKind) { if (a->action_kind == actions::Action::RunTimeOnlyIfMatchKind) {
if (a->isDisruptive()) { if (a->isDisruptive()) {
if (containsDisruptive) { if (containsDisruptive) {
#ifndef NO_LOGS
assay->debug(4, "(SecDefaultAction) " \ assay->debug(4, "(SecDefaultAction) " \
"_ignoring_ action: " + a->action + \ "_ignoring_ action: " + a->action + \
" (rule contains a disruptive action)"); " (rule contains a disruptive action)");
#endif
} else { } else {
if (assay->m_rules->secRuleEngine if (assay->m_rules->secRuleEngine
== Rules::EnabledRuleEngine) { == Rules::EnabledRuleEngine) {
#ifndef NO_LOGS
assay->debug(4, "(SecDefaultAction) " \ assay->debug(4, "(SecDefaultAction) " \
"Running action: " + a->action + \ "Running action: " + a->action + \
" (rule _does not_ contains a " \ " (rule _does not_ contains a " \
"disruptive action)"); "disruptive action)");
#endif
a->evaluate(this, assay); a->evaluate(this, assay);
} else { } else {
#ifndef NO_LOGS
assay->debug(4, "(SecDefaultAction) " \ assay->debug(4, "(SecDefaultAction) " \
"_Not_ running action: " + a->action + \ "_Not_ running action: " + a->action + \
". Rule _does not_ contains a " \ ". Rule _does not_ contains a " \
"disruptive action, but SecRuleEngine is not On."); "disruptive action, but SecRuleEngine is not On.");
#endif
} }
} }
} else { } else {
#ifndef NO_LOGS
assay->debug(4, "(SecDefaultAction) Running action: " + \ assay->debug(4, "(SecDefaultAction) Running action: " + \
a->action); a->action);
a->evaluate(this, assay); a->evaluate(this, assay);
#endif
} }
} }
} }
@ -212,11 +224,15 @@ bool Rule::evaluateActions(Assay *assay) {
for (Action *a : this->actions_runtime_pos) { for (Action *a : this->actions_runtime_pos) {
if (a->isDisruptive() if (a->isDisruptive()
&& assay->m_rules->secRuleEngine == Rules::EnabledRuleEngine) { && assay->m_rules->secRuleEngine == Rules::EnabledRuleEngine) {
#ifndef NO_LOGS
assay->debug(4, "Running (disruptive) action: " + a->action); assay->debug(4, "Running (disruptive) action: " + a->action);
#endif
a->evaluate(this, assay); a->evaluate(this, assay);
} else if (a->isDisruptive()) { } else if (a->isDisruptive()) {
#ifndef NO_LOGS
assay->debug(4, "Not running disruptive action: " + \ assay->debug(4, "Not running disruptive action: " + \
a->action + ". SecRuleEngine is not On"); a->action + ". SecRuleEngine is not On");
#endif
} }
} }
@ -235,6 +251,7 @@ bool Rule::evaluate(Assay *assay) {
return evaluateActions(assay); return evaluateActions(assay);
} }
#ifndef NO_LOGS
std::string eparam = MacroExpansion::expand(this->op->param, assay); std::string eparam = MacroExpansion::expand(this->op->param, assay);
if (this->op->param != eparam) { if (this->op->param != eparam) {
@ -251,6 +268,7 @@ bool Rule::evaluate(Assay *assay) {
+ Variable::to_s(variables) + "."); + Variable::to_s(variables) + ".");
clock_t begin = clock(); clock_t begin = clock();
#endif
std::list<std::string> exclusions; std::list<std::string> exclusions;
for (int i = 0; i < variables->size(); i++) { for (int i = 0; i < variables->size(); i++) {
@ -281,8 +299,10 @@ bool Rule::evaluate(Assay *assay) {
for (auto &v : e) { for (auto &v : e) {
if (std::find(exclusions.begin(), exclusions.end(), if (std::find(exclusions.begin(), exclusions.end(),
v.first) != exclusions.end()) { v.first) != exclusions.end()) {
#ifndef NO_LOGS
assay->debug(9, "Variable: " + v.first + " is part of the" + assay->debug(9, "Variable: " + v.first + " is part of the" +
" exclusion list, skipping..."); " exclusion list, skipping...");
#endif
continue; continue;
} }
std::string value = v.second; std::string value = v.second;
@ -301,9 +321,11 @@ bool Rule::evaluate(Assay *assay) {
for (Action *a : assay->m_rules->defaultActions[this->phase]) { for (Action *a : assay->m_rules->defaultActions[this->phase]) {
if (a->action_kind == actions::Action::RunTimeBeforeMatchAttemptKind) { if (a->action_kind == actions::Action::RunTimeBeforeMatchAttemptKind) {
value = a->evaluate(value, assay); value = a->evaluate(value, assay);
#ifndef NO_LOGS
assay->debug(9, "(SecDefaultAction) T (" + \ assay->debug(9, "(SecDefaultAction) T (" + \
std::to_string(transformations) + ") " + \ std::to_string(transformations) + ") " + \
a->name + ": \"" + value +"\""); a->name + ": \"" + value +"\"");
#endif
transformations++; transformations++;
} }
} }
@ -313,9 +335,11 @@ bool Rule::evaluate(Assay *assay) {
None *z = dynamic_cast<None *>(a); None *z = dynamic_cast<None *>(a);
if (none == 0) { if (none == 0) {
value = a->evaluate(value, assay); value = a->evaluate(value, assay);
#ifndef NO_LOGS
assay->debug(9, " T (" + \ assay->debug(9, " T (" + \
std::to_string(transformations) + ") " + \ std::to_string(transformations) + ") " + \
a->name + ": \"" + value +"\""); a->name + ": \"" + value +"\"");
#endif
transformations++; transformations++;
} }
if (z != NULL) { if (z != NULL) {
@ -323,27 +347,35 @@ bool Rule::evaluate(Assay *assay) {
} }
} }
#ifndef NO_LOGS
assay->debug(9, "Target value: \"" + limitTo(80, toHexIfNeeded(value)) + \ assay->debug(9, "Target value: \"" + limitTo(80, toHexIfNeeded(value)) + \
"\" (Variable: " + v.first + ")"); "\" (Variable: " + v.first + ")");
#endif
ret = this->op->evaluate(assay, value); ret = this->op->evaluate(assay, value);
#ifndef NO_LOGS
clock_t end = clock(); clock_t end = clock();
double elapsed_secs = static_cast<double>(end - begin) \ double elapsed_secs = static_cast<double>(end - begin) \
/ CLOCKS_PER_SEC; / CLOCKS_PER_SEC;
assay->debug(4, "Operator completed in " + \ assay->debug(4, "Operator completed in " + \
std::to_string(elapsed_secs) + " seconds"); std::to_string(elapsed_secs) + " seconds");
#endif
if (ret) { if (ret) {
bool containsDisruptive = false; bool containsDisruptive = false;
bool chainResult = false; bool chainResult = false;
#ifndef NO_LOGS
assay->debug(4, "Rule returned 1."); assay->debug(4, "Rule returned 1.");
#endif
for (Action *a : for (Action *a :
this->actions_runtime_pos) { this->actions_runtime_pos) {
if (a->isDisruptive() == false) { if (a->isDisruptive() == false) {
#ifndef NO_LOGS
assay->debug(4, "Running (_non_ disruptive) action: " + a->action); assay->debug(4, "Running (_non_ disruptive) action: " + a->action);
#endif
a->evaluate(this, assay); a->evaluate(this, assay);
} else { } else {
containsDisruptive = true; containsDisruptive = true;
@ -351,11 +383,15 @@ bool Rule::evaluate(Assay *assay) {
} }
if (this->chained && this->chainedRule == NULL) { if (this->chained && this->chainedRule == NULL) {
#ifndef NO_LOGS
assay->debug(4, "Rule is marked as chained but there " \ assay->debug(4, "Rule is marked as chained but there " \
"isn't a subsequent rule."); "isn't a subsequent rule.");
#endif
} }
if (this->chained && this->chainedRule != NULL) { if (this->chained && this->chainedRule != NULL) {
#ifndef NO_LOGS
assay->debug(4, "Executing chained rule."); assay->debug(4, "Executing chained rule.");
#endif
if (assay->update_variable_first("MATCHED_VAR", if (assay->update_variable_first("MATCHED_VAR",
value) == false) { value) == false) {
assay->store_variable("MATCHED_VAR", value); assay->store_variable("MATCHED_VAR", value);
@ -378,27 +414,35 @@ bool Rule::evaluate(Assay *assay) {
if (a->action_kind == actions::Action::RunTimeOnlyIfMatchKind) { if (a->action_kind == actions::Action::RunTimeOnlyIfMatchKind) {
if (a->isDisruptive()) { if (a->isDisruptive()) {
if (containsDisruptive) { if (containsDisruptive) {
#ifndef NO_LOGS
assay->debug(4, "(SecDefaultAction) " \ assay->debug(4, "(SecDefaultAction) " \
"_ignoring_ action: " + a->action + \ "_ignoring_ action: " + a->action + \
" (rule contains a disruptive action)"); " (rule contains a disruptive action)");
#endif
} else { } else {
if (assay->m_rules->secRuleEngine if (assay->m_rules->secRuleEngine
== Rules::EnabledRuleEngine) { == Rules::EnabledRuleEngine) {
#ifndef NO_LOGS
assay->debug(4, "(SecDefaultAction) " \ assay->debug(4, "(SecDefaultAction) " \
"Running action: " + a->action + \ "Running action: " + a->action + \
" (rule _does not_ contains a " \ " (rule _does not_ contains a " \
"disruptive action)"); "disruptive action)");
#endif
a->evaluate(this, assay); a->evaluate(this, assay);
} else { } else {
#ifndef NO_LOGS
assay->debug(4, "(SecDefaultAction) " \ assay->debug(4, "(SecDefaultAction) " \
"_Not_ running action: " + a->action + \ "_Not_ running action: " + a->action + \
". Rule _does not_ contains a " \ ". Rule _does not_ contains a " \
"disruptive action, but SecRuleEngine is not On."); "disruptive action, but SecRuleEngine is not On.");
#endif
} }
} }
} else { } else {
#ifndef NO_LOGS
assay->debug(4, "(SecDefaultAction) Running " \ assay->debug(4, "(SecDefaultAction) Running " \
"action: " + a->action + "!!" + std::to_string(a->isDisruptive())); "action: " + a->action + "!!" + std::to_string(a->isDisruptive()));
#endif
a->evaluate(this, assay); a->evaluate(this, assay);
} }
} }
@ -408,19 +452,25 @@ bool Rule::evaluate(Assay *assay) {
if (a->isDisruptive() if (a->isDisruptive()
&& assay->m_rules->secRuleEngine && assay->m_rules->secRuleEngine
== Rules::EnabledRuleEngine) { == Rules::EnabledRuleEngine) {
#ifndef NO_LOGS
assay->debug(4, "Running (disruptive) action: " + \ assay->debug(4, "Running (disruptive) action: " + \
a->action); a->action);
#endif
a->evaluate(this, assay); a->evaluate(this, assay);
} else if (a->isDisruptive()) { } else if (a->isDisruptive()) {
#ifndef NO_LOGS
assay->debug(4, assay->debug(4,
"Not running disruptive action: " + \ "Not running disruptive action: " + \
a->action + ". SecRuleEngine is not On"); a->action + ". SecRuleEngine is not On");
#endif
} }
} }
} }
} else { } else {
#ifndef NO_LOGS
assay->debug(4, "Rule returned 0."); assay->debug(4, "Rule returned 0.");
#endif
} }
} }
} }

View File

@ -66,7 +66,7 @@ char ip[] = "200.249.12.31";
char rules_file[] = "basic_rules.conf"; char rules_file[] = "basic_rules.conf";
#define NUM_REQUESTS 1000 #define NUM_REQUESTS 10000
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
int i = 0; int i = 0;
@ -79,10 +79,14 @@ int main(int argc, char *argv[]) {
" (ModSecurity benchmark utility)"); " (ModSecurity benchmark utility)");
rules = new ModSecurity::Rules(); rules = new ModSecurity::Rules();
rules->loadFromUri(rules_file); if (rules->loadFromUri(rules_file) < 0) {
std::cout << "Problems loading the rules..." << std::endl;
std::cout << rules->parserError.str() << std::endl;
return -1;
}
for (i = 0; i < NUM_REQUESTS; i++) { for (i = 0; i < NUM_REQUESTS; i++) {
std::cout << "Proceding with request " << i << std::endl; std::cout << "Proceeding with request " << i << std::endl;
Assay *modsecAssay = new Assay(modsec, rules, NULL); Assay *modsecAssay = new Assay(modsec, rules, NULL);
modsecAssay->processConnection(ip, 12345, "127.0.0.1", 80); modsecAssay->processConnection(ip, 12345, "127.0.0.1", 80);