Very first commit: libmodsecurity

Check the README.md file for further information about the libmodsecurity.
This commit is contained in:
Felipe Zimmerle
2015-06-26 14:35:15 -03:00
parent 33cbe0452a
commit 95cb4c56ab
153 changed files with 12862 additions and 0 deletions

75
src/parser/driver.cc Normal file
View File

@@ -0,0 +1,75 @@
/**
* ModSecurity, http://www.modsecurity.org/
* Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Trustwave Holdings, Inc.
* directly using the email address security@modsecurity.org.
*
*/
#include "parser/driver.h"
#include "parser/seclang-parser.hh"
Driver::Driver()
: trace_scanning(false), trace_parsing(false) {
}
Driver::~Driver() {
}
int Driver::addSecRule(ModSecurity::Rule *rule) {
if (rule->phase >= ModSecurity::ModSecurity::Phases::NUMBER_OF_PHASES) {
/** TODO: return an error message */
return -1;
}
this->rules[rule->phase].push_back(rule);
return 1;
}
int Driver::parse(const std::string &f) {
file = f;
scan_begin();
yy::seclang_parser parser(*this);
parser.set_debug_level(trace_parsing);
// yy_scan_buffer
int res = parser.parse();
scan_end();
return res;
}
int Driver::parseFile(const std::string &f) {
file = f;
scan_begin();
yy::seclang_parser parser(*this);
parser.set_debug_level(trace_parsing);
int res = parser.parse();
//std::cout << "Leaving the parser: " << res << std::endl;
scan_end();
return res;
}
void Driver::error(const yy::location& l, const std::string& m) {
std::cerr << l << ": " << m << std::endl;
}
void Driver::error(const std::string& m) {
std::cerr << m << std::endl;
}

94
src/parser/driver.h Normal file
View File

@@ -0,0 +1,94 @@
/**
* ModSecurity, http://www.modsecurity.org/
* Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Trustwave Holdings, Inc.
* directly using the email address security@modsecurity.org.
*
*/
#ifdef __cplusplus
#include <string>
#include <map>
#include <stack>
#include <vector>
#endif
#ifndef SRC_PARSER_DRIVER_H_
#define SRC_PARSER_DRIVER_H_
#include "modsecurity/modsecurity.h"
#include "src/rule.h"
#include "parser/seclang-parser.hh"
using ModSecurity::Rule;
# define YY_DECL \
yy::seclang_parser::symbol_type yylex(Driver& driver)
YY_DECL;
#ifdef __cplusplus
class Driver;
#else
typedef struct Driver_t Driver;
#endif
class Driver {
/**
* @todo Place driver and parser under the correct namespace.
*
*/
public:
Driver();
virtual ~Driver();
int addSecRule(Rule *rule);
int result;
// Handling the scanner.
void scan_begin();
void scan_end();
bool trace_scanning;
// Run the parser on file F.
// Return 0 on success.
int parseFile(const std::string& f);
int parse(const std::string& f);
// The name of the file being parsed.
// Used later to pass the file name to the location tracker.
std::string file;
// Whether parser traces should be generated.
bool trace_parsing;
// Error handling.
void error(const yy::location& l, const std::string& m);
void error(const std::string& m);
std::vector<Rule *> rules[7]; // Number of Phases.
int sec_rule_engine;
int sec_audit_type;
bool sec_audit_engine;
bool sec_request_body_access;
bool sec_response_body_access;
std::string audit_log_path;
std::string audit_log_parts;
std::string debug_log_path;
int debug_level;
};
#endif // SRC_PARSER_DRIVER_H_

View File

@@ -0,0 +1,240 @@
%skeleton "lalr1.cc" /* -*- C++ -*- */
%require "3.0.4"
%defines
%define parser_class_name {seclang_parser}
%define api.token.constructor
%define api.value.type variant
%define parse.assert
%code requires
{
# include <string>
class Driver;
#include "actions/action.h"
#include "actions/transformations/transformation.h"
#include "operators/operator.h"
#include "rule.h"
using ModSecurity::actions::Action;
using ModSecurity::actions::transformations::Transformation;
using ModSecurity::operators::Operator;
using ModSecurity::Variable;
using ModSecurity::Rule;
}
// The parsing context.
%param { Driver& driver }
%locations
%initial-action
{
// Initialize the initial location.
@$.begin.filename = @$.end.filename = &driver.file;
};
%define parse.trace
%define parse.error verbose
%code
{
#include "parser/driver.h"
}
%define api.token.prefix {TOK_}
%token
END 0 "end of file"
CONFIG_DIR_VAL "+"
COMMA "*"
QUOTATION_MARK ")"
SPACE
PIPE
NEW_LINE
UNKNOWN
FREE_TEXT
;
%left ARGS CONFIG_VALUE_ON CONFIG_VALUE_OFF CONFIG_VALUE
%token <std::string> DIRECTIVE
%token <std::string> CONFIG_DIRECTIVE
%token <std::string> CONFIG_DIR_RULE_ENG
%token <std::string> CONFIG_DIR_REQ_BODY
%token <std::string> CONFIG_DIR_RES_BODY
%token <std::string> CONFIG_DIR_AUDIT_ENG
%token <std::string> CONFIG_DIR_AUDIT_TPE
%token <std::string> CONFIG_VALUE
%token <std::string> CONFIG_VALUE_ON
%token <std::string> CONFIG_VALUE_OFF
%token <std::string> CONFIG_VALUE_DETC
%token <std::string> CONFIG_VALUE_SERIAL
%token <std::string> CONFIG_VALUE_PARALLEL
%token <std::string> CONFIG_DIR_AUDIT_LOG
%token <std::string> CONFIG_DIR_AUDIT_LOG_P
%token <std::string> CONFIG_DIR_DEBUG_LOG
%token <std::string> CONFIG_DIR_DEBUG_LVL
%token <std::string> OPERATOR
%token <std::string> ACTION
%token <std::string> VARIABLE
%token <std::string> TRANSFORMATION
%type <std::vector<Action *> *> actions
%type <std::vector<Variable> *> variables
%printer { yyoutput << $$; } <*>;
%%
%start secrule;
secrule:
| secrule line
line:
expression NEW_LINE
| SPACE expression NEW_LINE
| NEW_LINE
| SPACE NEW_LINE
| SPACE
expression:
DIRECTIVE SPACE variables SPACE OPERATOR SPACE QUOTATION_MARK actions QUOTATION_MARK
{
Rule *rule = new Rule(
/* op */ Operator::instantiate($5),
/* variables */ $3,
/* actions */ $8
);
driver.addSecRule(rule);
}
| CONFIG_DIR_RULE_ENG SPACE CONFIG_VALUE_OFF
{
driver.sec_rule_engine = 0;
}
| CONFIG_DIR_RULE_ENG SPACE CONFIG_VALUE_ON
{
driver.sec_rule_engine = 1;
}
| CONFIG_DIR_RULE_ENG SPACE CONFIG_VALUE_DETC
{
driver.sec_rule_engine = 2;
}
| CONFIG_DIR_REQ_BODY SPACE CONFIG_VALUE_ON
{
driver.sec_request_body_access = true;
}
| CONFIG_DIR_REQ_BODY SPACE CONFIG_VALUE_OFF
{
driver.sec_request_body_access = false;
}
| CONFIG_DIR_RES_BODY SPACE CONFIG_VALUE_ON
{
driver.sec_request_body_access = true;
}
| CONFIG_DIR_RES_BODY SPACE CONFIG_VALUE_OFF
{
driver.sec_request_body_access = false;
}
| CONFIG_DIR_AUDIT_ENG SPACE CONFIG_VALUE_ON
{
driver.sec_audit_engine = true;
}
| CONFIG_DIR_AUDIT_ENG SPACE CONFIG_VALUE_OFF
{
driver.sec_audit_engine = false;
}
| CONFIG_DIR_AUDIT_TPE SPACE CONFIG_VALUE_SERIAL
{
driver.sec_audit_type = 0;
}
| CONFIG_DIR_AUDIT_TPE SPACE CONFIG_VALUE_PARALLEL
{
driver.sec_audit_type = 1;
}
| CONFIG_DIR_AUDIT_LOG
{
driver.audit_log_path = $1;
}
| CONFIG_DIR_AUDIT_LOG_P
{
driver.audit_log_parts = $1;
}
| CONFIG_DIR_DEBUG_LVL
{
driver.debug_level = atoi($1.c_str());
}
| CONFIG_DIR_DEBUG_LOG
{
driver.debug_log_path = $1;
}
variables:
variables PIPE VARIABLE
{
std::vector<Variable> *v = $1;
v->push_back(Variable($3));
$$ = $1;
}
| VARIABLE
{
std::vector<Variable> *variables = new std::vector<Variable>;
variables->push_back(Variable($1));
$$ = variables;
}
actions:
actions COMMA SPACE ACTION
{
std::vector<Action *> *a = $1;
a->push_back(Action::instantiate($4));
$$ = $1;
}
| actions COMMA ACTION
{
std::vector<Action *> *a = $1;
a->push_back(Action::instantiate($3));
$$ = $1;
}
| SPACE ACTION
{
std::vector<Action *> *actions = new std::vector<Action *>;
actions->push_back(Action::instantiate($2));
$$ = actions;
}
| ACTION
{
std::vector<Action *> *actions = new std::vector<Action *>;
actions->push_back(Action::instantiate($1));
$$ = actions;
}
| actions COMMA SPACE TRANSFORMATION
{
std::vector<Action *> *a = $1;
a->push_back(Transformation::instantiate($4));
$$ = $1;
}
| actions COMMA TRANSFORMATION
{
std::vector<Action *> *a = $1;
a->push_back(Transformation::instantiate($3));
$$ = $1;
}
| SPACE TRANSFORMATION
{
std::vector<Action *> *actions = new std::vector<Action *>;
actions->push_back(Transformation::instantiate($2));
$$ = actions;
}
| TRANSFORMATION
{
std::vector<Action *> *actions = new std::vector<Action *>;
actions->push_back(Transformation::instantiate($1));
$$ = actions;
}
%%
void
yy::seclang_parser::error (const location_type& l,
const std::string& m)
{
driver.error (l, m);
}

126
src/parser/seclang-scanner.ll Executable file
View File

@@ -0,0 +1,126 @@
%{ /* -*- C++ -*- */
# include <cerrno>
# include <climits>
# include <cstdlib>
# include <string>
# include "parser/driver.h"
# include "seclang-parser.hh"
// Work around an incompatibility in flex (at least versions
// 2.5.31 through 2.5.33): it generates code that does
// not conform to C89. See Debian bug 333231
// <http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=333231>.
# undef yywrap
# define yywrap() 1
// The location of the current token.
static yy::location loc;
%}
%option noyywrap nounput batch debug noinput
ACTION (?i:accuracy|allow|append|auditlog|block|capture|chain|ctl|deny|deprecatevar|drop|exec|expirevar|id:[0-9]+|initcol|log|logdata|maturity|msg|multiMatch|noauditlog|nolog|pass|pause|phase:[0-9]+|prepend|proxy|redirect:[A-z0-9_\|\&\:\/\/\.]+|rev|sanitiseArg|sanitiseMatched|sanitiseMatchedBytes|sanitiseRequestHeader|sanitiseResponseHeader|severity|setuid|setrsc|setsid|setenv|setvar|skip|skipAfter|status:[0-9]+|tag|ver|xmlns|t)
DIRECTIVE SecRule
CONFIG_DIRECTIVE SecRequestBodyLimitAction|SecRequestBodyNoFilesLimit|SecRequestBodyInMemoryLimit|SecRequestBodyLimit|SecPcreMatchLimitRecursion|SecPcreMatchLimit|SecResponseBodyMimeType|SecResponseBodyLimitAction|SecResponseBodyLimit|SecTmpDir|SecDataDir|SecAuditLogRelevantStatus|SecAuditLogType|SecArgumentSeparator|SecCookieFormat|SecStatusEngine
CONFIG_DIR_RULE_ENG SecRuleEngine
CONFIG_DIR_REQ_BODY SecRequestBodyAccess
CONFIG_DIR_RES_BODY SecResponseBodyAccess
CONFIG_DIR_AUDIT_ENG SecAuditEngine
CONFIG_DIR_AUDIT_TPE SecAuditLogType
CONFIG_DIR_AUDIT_LOG SecAuditLog
CONFIG_DIR_AUDIT_LOG_P SecAuditLogParts
CONFIG_DIR_DEBUG_LOG SecDebugLog
CONFIG_DIR_DEBUG_LVL SecDebugLogLevel
CONFIG_INCLUDE Include
DICT_ELEMENT [A-Za-z_]+
OPERATOR (?i:(?:@inspectFile|@fuzzyHash|@validateByteRange|@validateDTD|@validateHash|@validateSchema|@verifyCC|@verifyCPF|@verifySSN|@gsbLookup|@rsub)|(?:\!{0,1})(?:@within|@containsWord|@contains|@endsWith|@eq|@ge|@gt|@ipMatchF|@ipMatch|@ipMatchFromFile|@le|@lt|@pmf|@pm|@pmFromFile|@rbl|@rx|@streq|@strmatch|@beginsWith))
OPERATORNOARG (?i:@detectSQLi|@detectXSS|@geoLookup|@validateUrlEncoding|@validateUtf8Encoding)
TRANSFORMATION t:(lowercase|urlDecodeUni|urlDecode|none|compressWhitespace|removeWhitespace|replaceNulls|removeNulls|htmlEntityDecode|jsDecode|cssDecode|trim)
VARIABLE (?i:ARGS_NAMES|ARGS|QUERY_STRING|REMOTE_ADDR|REQUEST_BASENAME|REQUEST_BODY|REQUEST_COOKIES_NAMES|REQUEST_COOKIES|REQUEST_FILENAME|REQUEST_HEADERS_NAMES|REQUEST_HEADERS|REQUEST_METHOD|REQUEST_PROTOCOL|REQUEST_URI|RESPONSE_BODY|RESPONSE_CONTENT_LENGTH|RESPONSE_CONTENT_TYPE|RESPONSE_HEADERS_NAMES|RESPONSE_HEADERS|RESPONSE_PROTOCOL|RESPONSE_STATUS|TX)
VARIABLENOCOLON (?i:REQBODY_ERROR|MULTIPART_STRICT_ERROR|MULTIPART_UNMATCHED_BOUNDARY|REMOTE_ADDR|REQUEST_LINE)
CONFIG_VALUE_ON On
CONFIG_VALUE_OFF Off
CONFIG_VALUE_DETC DetectOnly
CONFIG_VALUE_SERIAL Serial
CONFIG_VALUE_PARALLEL Parallel
CONFIG_VALUE_PATH [A-Za-z_/\.]+
AUDIT_PARTS [ABCDEFHJKZ]+
CONFIG_VALUE_NUMBER [0-9]+
FREE_TEXT [^\"]+
%{
// Code run each time a pattern is matched.
# define YY_USER_ACTION loc.columns (yyleng);
%}
%%
%{
// Code run each time yylex is called.
loc.step ();
%}
{DIRECTIVE} { return yy::seclang_parser::make_DIRECTIVE(yytext, loc); }
{TRANSFORMATION} { return yy::seclang_parser::make_TRANSFORMATION(yytext, loc); }
{CONFIG_DIR_RULE_ENG} { return yy::seclang_parser::make_CONFIG_DIR_RULE_ENG(yytext, loc); }
{CONFIG_DIR_RES_BODY} { return yy::seclang_parser::make_CONFIG_DIR_RES_BODY(yytext, loc); }
{CONFIG_DIR_REQ_BODY} { return yy::seclang_parser::make_CONFIG_DIR_REQ_BODY(yytext, loc); }
{CONFIG_DIR_AUDIT_ENG} { return yy::seclang_parser::make_CONFIG_DIR_REQ_BODY(yytext, loc); }
{CONFIG_DIR_AUDIT_TPE} { return yy::seclang_parser::make_CONFIG_DIR_AUDIT_TPE(yytext, loc); }
{CONFIG_DIR_DEBUG_LOG}[ ]{CONFIG_VALUE_PATH} { return yy::seclang_parser::make_CONFIG_DIR_DEBUG_LOG(strchr(yytext, ' ') + 1, loc); }
{CONFIG_DIR_DEBUG_LVL}[ ]{CONFIG_VALUE_NUMBER} { return yy::seclang_parser::make_CONFIG_DIR_DEBUG_LVL(strchr(yytext, ' ') + 1, loc); }
{CONFIG_DIR_AUDIT_LOG}[ ]{CONFIG_VALUE_PATH} { return yy::seclang_parser::make_CONFIG_DIR_AUDIT_LOG(strchr(yytext, ' ') + 1, loc); }
{CONFIG_DIR_AUDIT_LOG_P}[ ]{AUDIT_PARTS} { return yy::seclang_parser::make_CONFIG_DIR_AUDIT_LOG_P(strchr(yytext, ' ') + 1, loc); }
{CONFIG_VALUE_ON} { return yy::seclang_parser::make_CONFIG_VALUE_ON(yytext, loc); }
{CONFIG_VALUE_OFF} { return yy::seclang_parser::make_CONFIG_VALUE_OFF(yytext, loc); }
{CONFIG_VALUE_SERIAL} { return yy::seclang_parser::make_CONFIG_VALUE_SERIAL(yytext, loc); }
{CONFIG_VALUE_PARALLEL} { return yy::seclang_parser::make_CONFIG_VALUE_PARALLEL(yytext, loc); }
{CONFIG_VALUE_DETC} { return yy::seclang_parser::make_CONFIG_VALUE_DETC(yytext, loc); }
["]{OPERATOR}[ ]{FREE_TEXT}["] { return yy::seclang_parser::make_OPERATOR(yytext, loc); }
["]{OPERATORNOARG}["] { return yy::seclang_parser::make_OPERATOR(yytext, loc); }
{ACTION} { return yy::seclang_parser::make_ACTION(yytext, loc); }
["] { return yy::seclang_parser::make_QUOTATION_MARK(loc); }
[,] { return yy::seclang_parser::make_COMMA(loc); }
[|] { return yy::seclang_parser::make_PIPE(loc); }
{VARIABLE}:?{DICT_ELEMENT}? { return yy::seclang_parser::make_VARIABLE(yytext, loc); }
{VARIABLENOCOLON} { return yy::seclang_parser::make_VARIABLE(yytext, loc); }
[ \t]+ { return yy::seclang_parser::make_SPACE(loc); }
\n { return yy::seclang_parser::make_NEW_LINE(loc); }
. driver.error (loc, "invalid character");
<<EOF>> { return yy::seclang_parser::make_END(loc); }
%%
void
Driver::scan_begin ()
{
yy_flex_debug = trace_scanning;
if (file.empty () || file == "-")
yyin = stdin;
else if (!(yyin = fopen (file.c_str (), "r")))
{
exit (EXIT_FAILURE);
}
}
void
Driver::scan_end ()
{
fclose (yyin);
}