Improvements, fixes and new features

This commit is contained in:
brenosilva 2011-03-25 13:51:13 +00:00
parent 4f1ab2f713
commit 49732256f6
37 changed files with 612 additions and 106 deletions

View File

@ -42,9 +42,9 @@
* Data structures for acmp parser
*/
/**
* One node in trie
*/
/**
* One node in trie
*/
typedef struct acmp_node_t acmp_node_t;
typedef struct acmp_btree_node_t acmp_btree_node_t;
struct acmp_node_t {
@ -79,9 +79,9 @@ struct acmp_btree_node_t {
* Data related to parser, not to individual nodes
*/
struct ACMP {
#ifdef ACMP_USE_UTF8
#ifdef ACMP_USE_UTF8
int is_utf8;
#endif
#endif
int is_case_sensitive;
apr_pool_t *parent_pool;
apr_pool_t *pool;
@ -188,11 +188,11 @@ static long utf8_lcase(acmp_utf8_char_t ucs_code) {
* Returns length of given string for parser's encoding
*/
static size_t acmp_strlen(ACMP *parser, const char *str) {
#ifdef ACMP_USE_UTF8
#ifdef ACMP_USE_UTF8
return (parser->is_utf8 == 0) ? strlen(str) : utf8_strlen(str);
#else
#else
return strlen(str);
#endif
#endif
}
/**
@ -205,14 +205,14 @@ static void acmp_strtoucs(ACMP *parser, const char *str, acmp_utf8_char_t *ucs_c
int i;
const char *c = str;
#ifdef ACMP_USE_UTF8
#ifdef ACMP_USE_UTF8
if (parser->is_utf8) {
for (i = 0; i < len; i++) {
*(ucs_chars++) = utf8_decodechar(c);
c += utf8_seq_len(c);
}
} else
#endif
#endif
{
for (i = 0; i < len; i++) {
*(ucs_chars++) = *(c++);
@ -341,7 +341,7 @@ static void acmp_connect_other_matches(ACMP *parser, acmp_node_t *node) {
* Adds leaves to binary tree, working from sorted array of keyword tree nodes
*/
static void acmp_add_btree_leaves(acmp_btree_node_t *node, acmp_node_t *nodes[],
int pos, int lb, int rb, apr_pool_t *pool) {
int pos, int lb, int rb, apr_pool_t *pool) {
int left = 0, right = 0;
if ((pos - lb) > 1) {
@ -350,9 +350,9 @@ static void acmp_add_btree_leaves(acmp_btree_node_t *node, acmp_node_t *nodes[],
/* ENH: Check alloc succeded */
node->left->node = nodes[left];
node->left->letter = nodes[left]->letter;
#ifdef DEBUG_ACMP
#ifdef DEBUG_ACMP
fprintf(stderr, "%lc ->left %lc\n", (wint_t)node->node->letter, (wint_t)node->left->node->letter);
#endif
#endif
}
if ((rb - pos) > 1) {
right = pos + (rb - pos) / 2;
@ -360,9 +360,9 @@ static void acmp_add_btree_leaves(acmp_btree_node_t *node, acmp_node_t *nodes[],
/* ENH: Check alloc succeded */
node->right->node = nodes[right];
node->right->letter = nodes[right]->letter;
#ifdef DEBUG_ACMP
#ifdef DEBUG_ACMP
fprintf(stderr, "%lc ->right %lc\n", (wint_t)node->node->letter, (wint_t)node->right->node->letter);
#endif
#endif
}
if (node->right != NULL) {
acmp_add_btree_leaves(node->right, nodes, right, pos, rb, pool);
@ -436,9 +436,9 @@ static apr_status_t acmp_connect_fail_branches(ACMP *parser) {
for (child = parser->root_node->child; child != NULL; child = child->sibling) {
child->fail = parser->root_node;
*(acmp_node_t **)apr_array_push(arr) = child;
#ifdef DEBUG_ACMP
#ifdef DEBUG_ACMP
fprintf(stderr, "fail direction: *%s* => *%s*\n", child->text, child->fail->text);
#endif
#endif
}
for (;;) {
@ -449,9 +449,9 @@ static apr_status_t acmp_connect_fail_branches(ACMP *parser) {
goto_node = acmp_child_for_code(node->parent->fail, node->letter);
node->fail = (goto_node != NULL) ? goto_node : parser->root_node;
}
#ifdef DEBUG_ACMP
#ifdef DEBUG_ACMP
fprintf(stderr, "fail direction: *%s* => *%s*\n", node->text, node->fail->text);
#endif
#endif
child = node->child;
while (child != NULL) {
*(acmp_node_t **)apr_array_push(arr2) = child;
@ -486,8 +486,8 @@ static void acmp_clear_hit_count_recursive(acmp_node_t *node) {
static void acmp_found(ACMP *parser, acmp_node_t *node) {
if (node->callback) {
node->callback(parser, node->callback_data,
parser->bp_buffer[(parser->char_pos - node->depth - 1) % parser->bp_buff_len],
parser->char_pos - node->depth - 1);
parser->bp_buffer[(parser->char_pos - node->depth - 1) % parser->bp_buff_len],
parser->char_pos - node->depth - 1);
}
node->hit_count++;
parser->hit_count++;
@ -516,9 +516,9 @@ ACMP *acmp_create(int flags, apr_pool_t *pool) {
/* ENH: Check alloc succeded */
parser->pool = p;
parser->parent_pool = pool;
#ifdef ACMP_USE_UTF8
#ifdef ACMP_USE_UTF8
parser->is_utf8 = (flags & ACMP_FLAG_UTF8) == 0 ? 0 : 1;
#endif
#endif
parser->is_case_sensitive = (flags & ACMP_FLAG_CASE_SENSITIVE) == 0 ? 0 : 1;
parser->root_node = apr_pcalloc(p, sizeof(acmp_node_t));
/* ENH: Check alloc succeded */
@ -554,9 +554,9 @@ ACMP *acmp_duplicate(ACMP *parser, apr_pool_t *pool) {
/* ENH: Check alloc succeded */
new_parser->pool = p;
new_parser->parent_pool = pool;
#ifdef ACMP_USE_UTF8
#ifdef ACMP_USE_UTF8
new_parser->is_utf8 = parser->is_utf8;
#endif
#endif
new_parser->is_case_sensitive = parser->is_case_sensitive;
new_parser->root_node = apr_pcalloc(p, sizeof(acmp_node_t));
/* ENH: Check alloc succeded */
@ -596,7 +596,7 @@ apr_status_t acmp_prepare(ACMP *parser) {
* len - Length of pattern in characters, if zero string length is used.
*/
apr_status_t acmp_add_pattern(ACMP *parser, const char *pattern,
acmp_callback_t callback, void *data, apr_size_t len)
acmp_callback_t callback, void *data, apr_size_t len)
{
size_t length, i, j;
acmp_utf8_char_t *ucs_chars;
@ -654,9 +654,9 @@ apr_status_t acmp_add_pattern(ACMP *parser, const char *pattern,
*/
apr_status_t acmp_process(ACMP *parser, const char *data, apr_size_t len) {
acmp_node_t *node, *go_to;
#ifdef ACMP_USE_UTF8
#ifdef ACMP_USE_UTF8
apr_size_t seq_length;
#endif
#endif
const char *end;
if (parser->is_failtree_done == 0) acmp_prepare(parser);
@ -668,7 +668,7 @@ apr_status_t acmp_process(ACMP *parser, const char *data, apr_size_t len) {
acmp_utf8_char_t letter;
parser->bp_buffer[parser->char_pos % parser->bp_buff_len] = parser->byte_pos;
#ifdef ACMP_USE_UTF8
#ifdef ACMP_USE_UTF8
if (parser->is_utf8) {
if (parser->u8buff_len > 0) {
/* Resuming partial utf-8 sequence */
@ -697,7 +697,7 @@ apr_status_t acmp_process(ACMP *parser, const char *data, apr_size_t len) {
}
}
} else
#endif
#endif
{
letter = *data++;
parser->byte_pos++;

View File

@ -16,6 +16,7 @@
* directly using the email address support@trustwave.com.
*
*/
#ifndef ACMP_H_
#define ACMP_H_

View File

@ -16,6 +16,7 @@
* directly using the email address support@trustwave.com.
*
*/
#ifndef _APACHE2_H_
#define _APACHE2_H_

View File

@ -12,10 +12,11 @@
* distribution.
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Breach Security, Inc.
* directly using the email address support@breach.com.
* other questions related to licensing please contact Trustwave Holdings, Inc.
* directly using the email address support@trustwave.com.
*
*/
#include <limits.h>
#include "modsecurity.h"

View File

@ -16,6 +16,7 @@
* directly using the email address support@trustwave.com.
*
*/
#include <util_filter.h>
#include "modsecurity.h"
@ -518,14 +519,14 @@ static int flatten_response_body(modsec_rec *msr) {
msr->resbody_data = apr_palloc(msr->mp, msr->resbody_length + 1);
if (msr->resbody_data == NULL) {
msr_log(msr, 1, "Output filter: Response body data memory allocation failed. Asked for: %" APR_SIZE_T_FMT,
msr->resbody_length + 1);
msr->resbody_length + 1);
return -1;
}
rc = apr_brigade_flatten(msr->of_brigade, msr->resbody_data, &msr->resbody_length);
if (rc != APR_SUCCESS) {
msr_log(msr, 1, "Output filter: Failed to flatten brigade (%d): %s", rc,
get_apr_error(msr->mp, rc));
get_apr_error(msr->mp, rc));
return -1;
}
@ -533,16 +534,16 @@ static int flatten_response_body(modsec_rec *msr) {
msr->resbody_status = RESBODY_STATUS_READ;
if (msr->txcfg->stream_outbody_inspection) {
msr->stream_output_data = (char *)malloc(msr->resbody_length+1);
msr->stream_output_length = msr->resbody_length+1;
msr->stream_output_data = (char *)calloc(sizeof(char),msr->resbody_length+1);
msr->stream_output_length = msr->resbody_length+1;
if (msr->stream_output_data == NULL) {
msr_log(msr, 1, "Output filter: Stream Response body data memory allocation failed. Asked for: %" APR_SIZE_T_FMT,
msr->stream_output_length + 1);
return -1;
}
if (msr->stream_output_data == NULL) {
msr_log(msr, 1, "Output filter: Stream Response body data memory allocation failed. Asked for: %" APR_SIZE_T_FMT,
msr->stream_output_length + 1);
return -1;
}
apr_cpystrn(msr->stream_output_data,msr->resbody_data,msr->stream_output_length);
apr_cpystrn(msr->stream_output_data,msr->resbody_data,msr->stream_output_length);
}
return 1;

View File

@ -16,6 +16,7 @@
* directly using the email address support@trustwave.com.
*
*/
#include "modsecurity.h"
#include "apache2.h"
#include "http_core.h"

View File

@ -16,6 +16,7 @@
* directly using the email address support@trustwave.com.
*
*/
#include <limits.h>
#include "http_core.h"
@ -24,6 +25,7 @@
#include "modsecurity.h"
#include "apache2.h"
#include "http_main.h"
#include "http_connection.h"
#include "apr_optional.h"
#include "mod_log_config.h"

View File

@ -16,6 +16,7 @@
* directly using the email address support@trustwave.com.
*
*/
#include <stdlib.h>
#include "apr_global_mutex.h"
@ -371,6 +372,11 @@ apr_status_t modsecurity_tx_init(modsec_rec *msr) {
msr->request_cookies = apr_table_make(msr->mp, 16);
if (msr->request_cookies == NULL) return -1;
/* Initialize matched vars */
msr->matched_vars = apr_table_make(msr->mp, 8);
if (msr->matched_vars == NULL) return -1;
apr_table_clear(msr->matched_vars);
/* Locate the cookie headers and parse them */
arr = apr_table_elts(msr->request_headers);
te = (apr_table_entry_t *)arr->elts;
@ -473,6 +479,7 @@ static apr_status_t modsecurity_process_phase_request_headers(modsec_rec *msr) {
static apr_status_t modsecurity_process_phase_request_body(modsec_rec *msr) {
apr_time_t time_before;
apr_status_t rc = 0;
if ((msr->allow_scope == ACTION_ALLOW_REQUEST)||(msr->allow_scope == ACTION_ALLOW)) {
if (msr->txcfg->debuglog_level >= 4) {

View File

@ -16,6 +16,7 @@
* directly using the email address support@trustwave.com.
*
*/
#ifndef _MODSECURITY_H_
#define _MODSECURITY_H_
@ -386,6 +387,9 @@ struct modsec_rec {
*/
unsigned int allow_scope;
/* matched vars */
apr_table_t *matched_vars;
/* Generic request body processor context to be used by custom parsers. */
void *reqbody_processor_ctx;
};

View File

@ -16,6 +16,7 @@
* directly using the email address support@trustwave.com.
*
*/
#include "msc_geo.h"

View File

@ -16,6 +16,7 @@
* directly using the email address support@trustwave.com.
*
*/
#ifndef _MSC_GEO_H_
#define _MSC_GEO_H_

View File

@ -16,6 +16,7 @@
* directly using the email address support@trustwave.com.
*
*/
#ifndef _MSC_GSB_H_
#define _MSC_GSB_H_
@ -32,6 +33,4 @@ struct gsb_db {
int DSOLOCAL gsb_mal_init(directory_config *dcfg, const char *dbfn, char **error_msg);
//int DSOLOCAL gsb_mal_lookup(modsec_rec *msr, const char *target, char **error_msg);
#endif

View File

@ -17,8 +17,7 @@
*
*/
#include "modsecurity_config.h"
#include "modsecurity.h"
#include <sys/stat.h>
#include "re.h"
@ -1125,8 +1124,27 @@ void sec_audit_logger(modsec_rec *msr) {
}
/* AUDITLOG_PART_UPLOADS */
/* ENH: Implement */
if ((strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_UPLOADS) != NULL) && (msr->mpd != NULL)) {
text = apr_psprintf(msr->mp, "\n--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_UPLOADS);
sec_auditlog_write(msr, text, strlen(text));
multipart_part **parts = NULL;
unsigned int total_size = 0;
int cfiles = 0;
parts = (multipart_part **)msr->mpd->parts->elts;
for(cfiles = 0; cfiles < msr->mpd->parts->nelts; cfiles++) {
if (parts[cfiles]->type == MULTIPART_FILE) {
if(parts[cfiles]->filename != NULL) {
text = apr_psprintf(msr->mp, "#%d Filename: %s - Size: %u - ContentType: %s\n", cfiles, log_escape_nq(msr->mp, parts[cfiles]->filename), parts[cfiles]->tmp_file_size, log_escape_nq(msr->mp, parts[cfiles]->content_type ? parts[cfiles]->content_type : "<Unknown ContentType>"));
sec_auditlog_write(msr, text, strlen(text));
total_size += parts[cfiles]->tmp_file_size;
}
}
}
text = apr_psprintf(msr->mp, "Total upload size: %u\n", total_size);
sec_auditlog_write(msr, text, strlen(text));
}
/* AUDITLOG_PART_MATCHEDRULES */

View File

@ -16,6 +16,7 @@
* directly using the email address support@trustwave.com.
*
*/
#ifndef _MSC_LOGGING_H_
#define _MSC_LOGGING_H_

View File

@ -16,6 +16,7 @@
* directly using the email address support@trustwave.com.
*
*/
#if defined(WITH_LUA)
#include "msc_lua.h"

View File

@ -16,6 +16,7 @@
* directly using the email address support@trustwave.com.
*
*/
#if defined(WITH_LUA)
#ifndef _MSC_LUA_H_

View File

@ -16,8 +16,8 @@
* directly using the email address support@trustwave.com.
*
*/
#include "modsecurity_config.h"
#include "modsecurity.h"
#include <ctype.h>
#include <sys/stat.h>

View File

@ -16,6 +16,7 @@
* directly using the email address support@trustwave.com.
*
*/
#ifndef _MSC_MULTIPART_H_
#define _MSC_MULTIPART_H_

View File

@ -16,6 +16,7 @@
* directly using the email address support@trustwave.com.
*
*/
#include "msc_parsers.h"
#include <ctype.h>

View File

@ -16,6 +16,7 @@
* directly using the email address support@trustwave.com.
*
*/
#ifndef _MSC_PARSERS_H_
#define _MSC_PARSERS_H_

View File

@ -16,6 +16,7 @@
* directly using the email address support@trustwave.com.
*
*/
#include "msc_pcre.h"
#include "apr_strings.h"

View File

@ -16,6 +16,7 @@
* directly using the email address support@trustwave.com.
*
*/
#ifndef _MSC_PCRE_H_
#define _MSC_PCRE_H_

View File

@ -16,6 +16,7 @@
* directly using the email address support@trustwave.com.
*
*/
#ifndef _MSC_RELEASE_H_
#define _MSC_RELEASE_H_

View File

@ -16,6 +16,7 @@
* directly using the email address support@trustwave.com.
*
*/
#include "modsecurity.h"
#include "re.h"
#include "msc_parsers.h"
@ -400,7 +401,7 @@ static apr_status_t modsecurity_request_body_to_stream(modsec_rec *msr, char **e
msr->stream_input_length = msr->msc_reqbody_length;
msr->stream_input_data = malloc(msr->stream_input_length + 1);
msr->stream_input_data = (char *)calloc(sizeof(char), msr->stream_input_length + 1);
if (msr->stream_input_data== NULL) {
*error_msg = apr_psprintf(msr->mp, "Unable to allocate memory to hold request body on stream. Asked for %u bytes.",
msr->stream_input_length + 1);

View File

@ -16,8 +16,8 @@
* directly using the email address support@trustwave.com.
*
*/
#include "modsecurity_config.h"
#include "modsecurity.h"
#include <ctype.h>
#include <fcntl.h>
#include <stdlib.h>

View File

@ -16,6 +16,7 @@
* directly using the email address support@trustwave.com.
*
*/
#ifndef _UTIL_H_
#define _UTIL_H_

View File

@ -16,6 +16,7 @@
* directly using the email address support@trustwave.com.
*
*/
#include "msc_xml.h"

View File

@ -16,6 +16,7 @@
* directly using the email address support@trustwave.com.
*
*/
#ifndef _MSC_XML_H_
#define _MSC_XML_H_

View File

@ -16,6 +16,7 @@
* directly using the email address support@trustwave.com.
*
*/
#include "persist_dbm.h"
#include "apr_sdbm.h"

View File

@ -16,6 +16,7 @@
* directly using the email address support@trustwave.com.
*
*/
#ifndef _PERSIST_DBM_H_
#define _PERSIST_DBM_H_

View File

@ -12,10 +12,11 @@
* distribution.
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Breach Security, Inc.
* directly using the email address support@breach.com.
* other questions related to licensing please contact Trustwave Holdings, Inc.
* directly using the email address support@trustwave.com.
*
*/
#include <ctype.h>
#include "re.h"
@ -918,6 +919,8 @@ apr_status_t msre_ruleset_process_phase(msre_ruleset *ruleset, modsec_rec *msr)
msr_log(msr, 9, "This phase consists of %d rule(s).", arr->nelts);
}
apr_table_clear(msr->matched_vars);
/* Loop through the rules in the selected set. */
skip = 0;
skipped = 0;
@ -1116,6 +1119,7 @@ apr_status_t msre_ruleset_process_phase(msre_ruleset *ruleset, modsec_rec *msr)
}
}
apr_table_clear(msr->matched_vars);
skipped = 0;
saw_starter = 0;
}
@ -1152,6 +1156,7 @@ apr_status_t msre_ruleset_process_phase(msre_ruleset *ruleset, modsec_rec *msr)
}
apr_table_clear(msr->matched_vars);
return 1;
}
@ -1205,7 +1210,9 @@ apr_status_t msre_ruleset_process_phase(msre_ruleset *ruleset, modsec_rec *msr)
else if (rc < 0) {
msr_log(msr, 1, "Rule processing failed.");
if (msr->txcfg->reqintercept_oe == 1) {
apr_table_clear(msr->matched_vars);
return -1;
} else {
if (rule->actionset->is_chained) {
@ -1226,18 +1233,20 @@ apr_status_t msre_ruleset_process_phase(msre_ruleset *ruleset, modsec_rec *msr)
}
}
apr_table_clear(msr->matched_vars);
skipped = 0;
saw_starter = 0;
}
}
else {
msr_log(msr, 1, "Rule processing failed with unknown return code: %d.", rc);
apr_table_clear(msr->matched_vars);
return -1;
}
}
/* ENH warn if chained rules are missing. */
apr_table_clear(msr->matched_vars);
return 0;
}
@ -1831,6 +1840,7 @@ static int execute_operator(msre_var *var, msre_rule *rule, modsec_rec *msr,
apr_time_t time_before_op = 0;
char *my_error_msg = NULL;
const char *full_varname = NULL;
char *parm = NULL;
int rc;
/* determine the full var name if not already resolved
@ -1920,6 +1930,32 @@ static int execute_operator(msre_var *var, msre_rule *rule, modsec_rec *msr,
msr->matched_var->value = apr_pmemdup(msr->mp, var->value, var->value_len);
msr->matched_var->value_len = var->value_len;
parm = strchr(msr->matched_var->name,':');
if(parm) {
parm++;
msc_string *mvar = apr_palloc(msr->mp, sizeof(msc_string));
mvar->name = apr_pstrdup(msr->mp, parm);
mvar->name_len = strlen(mvar->name);
mvar->value = apr_pmemdup(msr->mp, var->value, var->value_len);
mvar->value_len = var->value_len;
apr_table_unset(msr->matched_vars, parm);
apr_table_setn(msr->matched_vars, parm, (void *)mvar);
} else {
msc_string *mvar = apr_palloc(msr->mp, sizeof(msc_string));
mvar->name = apr_pstrdup(msr->mp, var->name);
mvar->name_len = strlen(mvar->name);
mvar->value = apr_pmemdup(msr->mp, var->value, var->value_len);
mvar->value_len = var->value_len;
apr_table_unset(msr->matched_vars, mvar->name);
apr_table_setn(msr->matched_vars, mvar->name, (void *)mvar);
}
/* Keep track of the highest severity matched so far */
if ((acting_actionset->severity > 0) && (acting_actionset->severity < msr->highest_severity))
{

View File

@ -190,6 +190,8 @@ struct msre_rule {
ap_regex_t *sub_regex;
char *sub_str;
char *re_str;
int re_precomp;
msre_ipmatch *ip_op;
};

View File

@ -1,6 +1,6 @@
/*
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
* Copyright (c) 2004-2008 Trustwave Holdings, Inc. (http://www.trustwave.com/)
* Copyright (c) 2004-2010 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* This product is released under the terms of the General Public Licence,
* version 2 (GPLv2). Please refer to the file LICENSE (included with this
@ -16,6 +16,7 @@
* directly using the email address support@trustwave.com.
*
*/
#include "re.h"
#include <ctype.h>
#include "apr_lib.h"
@ -572,6 +573,34 @@ static apr_status_t msre_action_redirect_execute(modsec_rec *msr, apr_pool_t *mp
return 1;
}
/* tag */
/*
* \brief Execution function to tag action
*
* \param msr Pointer internal modsec request structure
* \param mptmp Pointer to memory pool
* \param rule Pointer to the rule
* \param action Pointer to action structure
*
* \retval 1 On Success
*/
static apr_status_t msre_action_tag_execute(modsec_rec *msr, apr_pool_t *mptmp,
msre_rule *rule, msre_action *action)
{
msc_string *var = NULL;
var = apr_pcalloc(mptmp, sizeof(msc_string));
if (var == NULL) return -1;
var->value = (char *)action->param;
var->value_len = strlen(var->value);
expand_macros(msr, var, rule, mptmp);
action->param = apr_pstrmemdup(msr->mp, var->value, var->value_len);
return 1;
}
/* proxy */
static char *msre_action_proxy_validate(msre_engine *engine, msre_action *action) {
@ -2355,6 +2384,19 @@ void msre_engine_register_default_actions(msre_engine *engine) {
);
/* sanitiseMatchedBytes */
msre_engine_action_register(engine,
"sanitiseMatchedBytes",
ACTION_NON_DISRUPTIVE,
0, 1,
NO_PLUS_MINUS,
ACTION_CARDINALITY_MANY,
ACTION_CGROUP_NONE,
NULL,
msre_action_sanitizeMatchedBytes_init,
msre_action_sanitizeMatched_execute
);
/* sanitizeMatchedBytes */
msre_engine_action_register(engine,
"sanitizeMatchedBytes",
ACTION_NON_DISRUPTIVE,
@ -2586,7 +2628,7 @@ void msre_engine_register_default_actions(msre_engine *engine) {
ACTION_CGROUP_NONE,
NULL,
NULL,
NULL
msre_action_tag_execute
);
/* prepend */

View File

@ -16,13 +16,19 @@
* directly using the email address support@trustwave.com.
*
*/
#include "re.h"
#include "msc_pcre.h"
#include "msc_geo.h"
#include "apr_lib.h"
#include "apr_strmatch.h"
#include "acmp.h"
#if defined(WIN32) || defined(WINNT)
#include "pcre.h"
#else
#include <regex.h>
#endif
#define PARSE_REGEX_IP "([0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+)(?:(\\/[0-9]+))?|([0-9a-f]+\\:[0-9a-f]+\\:[0-9a-f]+\\:[0-9a-f]+\\:[0-9a-f]+\\:[0-9a-f]+\\:[0-9a-f]+\\:[0-9a-f]+)(?:(\\/[0-9]+))?"
#define MAX_SUBSTRINGS 30
@ -79,6 +85,15 @@ static int msre_op_nomatch_execute(modsec_rec *msr, msre_rule *rule,
/* ipmatch */
#if !defined(WIN32) || !defined(WINNT)
/*
* \brief Init function to ipmatch operator
*
* \param rule Pointer to the rule
* \param error_msg Pointer to error msg
*
* \retval 1 On Success
* \retval 0 On Fail
*/
static int msre_op_ipmatch_param_init(msre_rule *rule, char **error_msg) {
const char *errptr = NULL;
int erroffset;
@ -103,6 +118,9 @@ static int msre_op_ipmatch_param_init(msre_rule *rule, char **error_msg) {
unsigned long ipmask = 0, network = 0, hostmask = 0, broadcast = 0;
int maskbits = 0;
if (error_msg == NULL) return -1;
*error_msg = NULL;
parse_regex = pcre_compile(PARSE_REGEX_IP, opts, &eb, &eo, NULL);
if(parse_regex == NULL) {
@ -394,6 +412,18 @@ static int msre_op_ipmatch_param_init(msre_rule *rule, char **error_msg) {
return 1;
}
/*
* \brief Execution function to ipmatch operator
*
* \param msr Pointer internal modsec request structure
* \param rule Pointer to the rule
* \param var Pointer to variable structure
* \param error_msg Pointer to error msg
*
* \retval -1 On Failure
* \retval 1 On Match
* \retval 0 On No Match
*/
static int msre_op_ipmatch_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) {
const char *errptr = NULL;
int erroffset;
@ -403,13 +433,16 @@ static int msre_op_ipmatch_execute(modsec_rec *msr, msre_rule *rule, msre_var *v
int i;
msre_ipmatch *ipdata = rule->ip_op;
if (error_msg == NULL) return -1;
*error_msg = NULL;
if(var == NULL || (strcmp(var->name,"REMOTE_ADDR") != 0 ) || (strcmp(var->name,"SERVER_ADDR") != 0 )) {
msr_log(msr,9,"Operator ipmatch only works with REMOTE_ADDR and SERVER_ADDR variable");
return -1;
*error_msg = "Internal Error: Operator ipmatch only works with REMOTE_ADDR and SERVER_ADDR variable.";
return 0;
}
if(ipdata == NULL) {
msr_log(msr,9,"Ipmatch operator struct is NULL");
*error_msg = "Internal Error: ipmatch is null.";
return -1;
}
@ -469,6 +502,36 @@ static int msre_op_ipmatch_execute(modsec_rec *msr, msre_rule *rule, msre_var *v
/* rsub */
static char *remove_escape(msre_rule *rule, char *str, int len) {
char *parm = apr_palloc(rule->ruleset->mp, len);;
char *ret = parm;
for(;*str!='\0';str++) {
if(*str != '\\') {
*parm++ = *str;
} else {
str++;
if(*str != '/') {
str--;
*parm++ = *str;
} else {
*parm++ = *str;
}
}
}
return ret;
}
/*
* \brief Init function to rsub operator
*
* \param rule Pointer to the rule
* \param error_msg Pointer to error msg
*
* \retval 1 On Success
* \retval 0 On Fail
*/
static int msre_op_rsub_param_init(msre_rule *rule, char **error_msg) {
const char *errptr = NULL;
int erroffset;
@ -477,15 +540,20 @@ static int msre_op_rsub_param_init(msre_rule *rule, char **error_msg) {
const char *line = NULL;
char *reg_pattern = NULL;
char *replace = NULL;
char *e_pattern = NULL;
char *e_replace = NULL;
char *flags = NULL;
char *data;
char *data = NULL;
char delim;
int ignore_case = 0;
if (error_msg == NULL) return -1;
*error_msg = NULL;
line = rule->op_param;
if (apr_tolower(*line) != 's') {
*error_msg = apr_psprintf(rule->ruleset->mp, "Error rsub operator format, must be s/// pattern",
*error_msg = apr_psprintf(rule->ruleset->mp, "Error rsub operator format, must be s/ pattern",
erroffset, errptr);
return 0;
}
@ -495,30 +563,59 @@ static int msre_op_rsub_param_init(msre_rule *rule, char **error_msg) {
if (delim)
reg_pattern = ++data;
if (reg_pattern) {
if (*data != delim) {
while (*++data && *data != delim);
for(;*data != '\0' ;data++) {
if(*data == delim) {
data--;
if(*data == '\\') {
data++;
continue;
}
break;
}
}
}
if (*data) {
*data = '\0';
replace = ++data;
}
}
if (replace) {
if (*data != delim) {
while (*++data && *data != delim);
}
if (*data) {
*data = '\0';
flags = ++data;
*++data = '\0';
++data;
replace = data;
}
}
if (!delim || !reg_pattern || !*reg_pattern || !replace) {
if (replace) {
if (*data != delim) {
for(;*data != '\0' ;data++) {
if(*data == delim) {
data--;
if(*data == '\\') {
data++;
continue;
}
break;
}
}
}
if (*data) {
*++data = '\0';
flags = ++data;
}
}
if (!delim || !reg_pattern || !replace) {
*error_msg = apr_psprintf(rule->ruleset->mp, "Error rsub operator format - must be s/regex/str/[flags]",
erroffset, errptr);
return 0;
return -1;
}
e_pattern = remove_escape(rule, reg_pattern, strlen(reg_pattern));
e_replace = remove_escape(rule, replace, strlen(replace));
if (flags) {
while (*flags) {
delim = apr_tolower(*flags);
@ -531,21 +628,37 @@ static int msre_op_rsub_param_init(msre_rule *rule, char **error_msg) {
}
}
if (error_msg == NULL) return -1;
*error_msg = NULL;
pattern = apr_pstrdup(rule->ruleset->mp, e_pattern);
rule->sub_str = apr_pstrdup(rule->ruleset->mp, e_replace);
pattern = apr_pstrdup(rule->ruleset->mp, reg_pattern);
rule->sub_str = apr_pstrdup(rule->ruleset->mp, replace);
if(strstr(pattern,"%{") == NULL) {
regex = ap_pregcomp(rule->ruleset->mp, pattern, AP_REG_EXTENDED |
(ignore_case ? AP_REG_ICASE : 0));
rule->sub_regex = regex;
} else {
rule->re_precomp = 1;
rule->re_str = apr_pstrdup(rule->ruleset->mp, reg_pattern);
rule->sub_regex = NULL;
}
regex = ap_pregcomp(rule->ruleset->mp, pattern, AP_REG_EXTENDED |
(ignore_case ? AP_REG_ICASE : 0));
rule->sub_regex = regex;
return 1; /* OK */
}
/*
* \brief Execution function to rsub operator
*
* \param msr Pointer internal modsec request structure
* \param rule Pointer to the rule
* \param var Pointer to variable structure
* \param error_msg Pointer to error msg
*
* \retval -1 On Failure
* \retval 1 On Match
* \retval 0 On No Match
*/
static int msre_op_rsub_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) {
ap_regex_t *regex = rule->sub_regex;
msc_string *str = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
msc_string *re_pattern = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
char *offset = NULL;
int sub = 0, so = 0, p_len = 0;
char *replace = NULL;
@ -554,6 +667,8 @@ static int msre_op_rsub_execute(modsec_rec *msr, msre_rule *rule, msre_var *var,
int output_body = 0, input_body = 0, count = 0;
ap_regmatch_t pmatch[AP_MAX_REG_MATCH];
if (error_msg == NULL) return -1;
*error_msg = NULL;
if(strcmp(var->name,"STREAM_OUTPUT_BODY") == 0 ) {
output_body = 1;
@ -564,11 +679,37 @@ static int msre_op_rsub_execute(modsec_rec *msr, msre_rule *rule, msre_var *var,
return -1;
}
replace = apr_pstrdup(rule->ruleset->mp, rule->sub_str);;
if(rule->re_precomp == 1) {
re_pattern->value = (char *)rule->re_str;
re_pattern->value_len = strlen(re_pattern->value);
expand_macros(msr, re_pattern, rule, msr->mp);
if(strlen(re_pattern->value) > 0)
rule->sub_regex = ap_pregcomp(rule->ruleset->mp, re_pattern->value, AP_REG_EXTENDED);
else
rule->sub_regex = NULL;
rule->re_precomp = 0;
}
if(rule->sub_regex == NULL) {
*error_msg = "Internal Error: regex data is null.";
return -1;
}
str->value = (char *)rule->sub_str;
str->value_len = strlen(str->value);
expand_macros(msr, str, rule, msr->mp);
replace = apr_pstrdup(rule->ruleset->mp, str->value);
data = apr_pcalloc(msr->mp, var->value_len+(AP_MAX_REG_MATCH*strlen(replace))+1);
if(replace == NULL || data == NULL)
return 0;
if(replace == NULL || data == NULL) {
*error_msg = "Internal Error: cannot allocate memory";
return -1;
}
memcpy(data,var->value,var->value_len);
size += (AP_MAX_REG_MATCH*strlen(replace)+2);
@ -585,7 +726,7 @@ static int msre_op_rsub_execute(modsec_rec *msr, msre_rule *rule, msre_var *var,
offset = offset + p_len - 2;
}
sub = pmatch [1].rm_so;
sub = -1;
for (offset = data; !ap_regexec(rule->sub_regex, offset, 1, pmatch, 0); ) {
p_len = pmatch [0].rm_eo - pmatch [0].rm_so;
@ -595,6 +736,7 @@ static int msre_op_rsub_execute(modsec_rec *msr, msre_rule *rule, msre_var *var,
memmove (offset + strlen (replace), offset + p_len, strlen (offset) - p_len + 1);
memmove (offset, replace, strlen (replace));
offset += strlen (replace);
if (sub >= 0) break;
}
size -= ((AP_MAX_REG_MATCH - count)*(strlen(replace)) + ((strlen(replace) - p_len)*(count+AP_MAX_REG_MATCH) - (AP_MAX_REG_MATCH+4)));
@ -791,7 +933,7 @@ static int msre_op_rx_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, c
if (rc != PCRE_ERROR_NOMATCH) { /* Match. */
/* We no longer escape the pattern here as it is done when logging */
char *pattern = apr_pstrdup(msr->mp, regex->pattern);
char *pattern = apr_pstrdup(msr->mp, log_escape(msr->mp, regex->pattern ? regex->pattern : "<Unknown Match>"));
/* This message will be logged. */
if (strlen(pattern) > 252) {
@ -1004,6 +1146,17 @@ static int msre_op_pm_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, c
/* gsbLookup */
/*
* \brief Verify function to gsbLookup operator
*
* \param rule Pointer to the rule
* \param match Pointer to input data
* \param match_length Input size
*
* \retval -1 On Failure
* \retval 1 On Match
* \retval 0 On No Match
*/
static int verify_gsb(gsb_db *gsb, msre_rule *rule, const char *match, unsigned int match_length) {
apr_md5_ctx_t ctx;
apr_status_t rc;
@ -1032,6 +1185,15 @@ static int verify_gsb(gsb_db *gsb, msre_rule *rule, const char *match, unsigned
return 0;
}
/*
* \brief Init function to gsbLookup operator
*
* \param rule Pointer to the rule
* \param error_msg Pointer to error msg
*
* \retval 1 On Success
* \retval 0 On Fail
*/
static int msre_op_gsbLookup_param_init(msre_rule *rule, char **error_msg) {
const char *errptr = NULL;
int erroffset;
@ -1054,6 +1216,18 @@ static int msre_op_gsbLookup_param_init(msre_rule *rule, char **error_msg) {
return 1; /* OK */
}
/*
* \brief Execution function to gsbLookup operator
*
* \param msr Pointer internal modsec request structure
* \param rule Pointer to the rule
* \param var Pointer to variable structure
* \param error_msg Pointer to error msg
*
* \retval -1 On Failure
* \retval 1 On Match
* \retval 0 On No Match
*/
static int msre_op_gsbLookup_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) {
msc_regex_t *regex = (msc_regex_t *)rule->op_param_data;
char *my_error_msg = NULL;
@ -1071,26 +1245,23 @@ static int msre_op_gsbLookup_execute(modsec_rec *msr, msre_rule *rule, msre_var
char *str = NULL, *entire = NULL;
int capture;
if (error_msg == NULL) return -1;
*error_msg = NULL;
if(regex == NULL) {
if (msr->txcfg->debuglog_level >= 8) {
msr_log(msr, 8, "GSB: regex is null");
}
*error_msg = "Internal Error: regex data is null.";
return -1;
}
if(gsb == NULL) {
if (msr->txcfg->debuglog_level >= 8) {
msr_log(msr, 8, "GSB: gsb is null");
}
*error_msg = "Internal Error: gsb data is null.";
return -1;
}
data = apr_pcalloc(msr->mp, var->value_len+1);
if(data == NULL) {
if (msr->txcfg->debuglog_level >= 8) {
msr_log(msr, 8, "GSB: Fail to alloc memory for input data");
}
*error_msg = "Internal Error: cannot allocate memory for data.";
return -1;
}
@ -1105,11 +1276,7 @@ static int msre_op_gsbLookup_execute(modsec_rec *msr, msre_rule *rule, msre_var
match = apr_psprintf(rule->ruleset->mp, "%.*s", ovector[2*i+1] - ovector[2*i], data + ovector[2*i]);
if (match == NULL) {
if (msr->txcfg->debuglog_level >= 8) {
msr_log(msr, 8, "GSB: Fail to alloc memory for match string");
}
*error_msg = "Internal Error: cannot allocate memory for match.";
return -1;
}
@ -1147,7 +1314,7 @@ static int msre_op_gsbLookup_execute(modsec_rec *msr, msre_rule *rule, msre_var
ret = verify_gsb(gsb, rule, canon, canon_length);
if(ret > 0) {
set_match_to_tx(msr, capture, canon);
set_match_to_tx(msr, capture, match);
if (! *error_msg) {
*error_msg = apr_psprintf(msr->mp, "Gsb lookup for \"%s\" succeeded.",
log_escape_nq(msr->mp, canon));
@ -2018,7 +2185,7 @@ static int msre_op_verifyCC_execute(modsec_rec *msr, msre_rule *rule, msre_var *
static int cpf_verify(const char *cpfnumber, int len, msre_rule *rule) {
int factor, part_1, part_2, var_len = len;
int sum = 0, i = 0, cpf_len = 11;
int sum = 0, i = 0, cpf_len = 11, c;
int cpf[11];
char s_cpf[11];
char bad_cpf[11][11] = { "00000000000",
@ -2060,7 +2227,7 @@ static int cpf_verify(const char *cpfnumber, int len, msre_rule *rule) {
part_1 = convert_to_int(s_cpf[cpf_len-2]);
part_2 = convert_to_int(s_cpf[cpf_len-1]);
int c = cpf_len;
c = cpf_len;
for(i = 0; i < 9; i++) {
sum += (cpf[i] * --c);

View File

@ -16,6 +16,7 @@
* directly using the email address support@trustwave.com.
*
*/
#include <ctype.h>
#include "apr_md5.h"
@ -25,6 +26,57 @@
#include "re.h"
#include "msc_util.h"
/* cmdline */
static int msre_fn_cmdline_execute(apr_pool_t *mptmp, unsigned char *input,
long int input_len, char **rval, long int *rval_len)
{
int space = 0;
unsigned char *s = input;
if (rval == NULL) return -1;
*rval = (char *)input;
/* Check characters */
for ( ; *input; input++ ) {
switch(*input) {
/* remove some characters */
case '"':
case '\'':
case '\\':
case '^':
continue;
/* replace some characters to space (only one) */
case ' ':
case ',':
case ';':
case '\t':
case '\r':
case '\n':
if (!space) {
*s++ = ' ';
space++;
}
break;
case '/':
case '(':
/* remove space before / or ( */
if (space) s--;
space = 0;
*s++ = *input;
break;
/* copy normal characters */
default :
*s++ = tolower(*input);
space = 0;
}
}
*s = 0;
*rval_len = strlen(*rval);
return 1;
}
/* lowercase */
static int msre_fn_lowercase_execute(apr_pool_t *mptmp, unsigned char *input,
@ -786,6 +838,11 @@ void msre_engine_register_default_tfns(msre_engine *engine) {
msre_fn_trimLeft_execute
);
msre_engine_tfn_register(engine,
"cmdline",
msre_fn_cmdline_execute
);
/* trimRight */
msre_engine_tfn_register(engine,
"trimRight",

View File

@ -16,6 +16,7 @@
* directly using the email address support@trustwave.com.
*
*/
#include "http_core.h"
#include "modsecurity.h"
@ -456,6 +457,18 @@ static int var_request_uri_raw_generate(modsec_rec *msr, msre_var *var, msre_rul
return var_simple_generate(var, vartab, mptmp, msr->r->unparsed_uri);
}
/* UNIQUE_ID */
static int var_uniqueid_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
apr_table_t *vartab, apr_pool_t *mptmp)
{
char *value = get_env_var(msr->r, "UNIQUE_ID");
if (value != NULL) {
return var_simple_generate(var, vartab, mptmp, value);
}
}
/* REQUEST_URI */
static int var_request_uri_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
@ -1833,6 +1846,107 @@ static int var_request_body_length_generate(modsec_rec *msr, msre_var *var, msre
return var_simple_generate(var, vartab, mptmp, value);
}
/* MATCHED_VARS_NAMES */
static int var_matched_vars_names_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
apr_table_t *vartab, apr_pool_t *mptmp)
{
const apr_array_header_t *arr = NULL;
const apr_table_entry_t *te = NULL;
int i, count = 0;
arr = apr_table_elts(msr->matched_vars);
te = (apr_table_entry_t *)arr->elts;
for (i = 0; i < arr->nelts; i++) {
int match = 0;
msc_string *str = (msc_string *)te[i].val;
/* Figure out if we want to include this variable. */
if (var->param == NULL) match = 1;
else {
if (var->param_data != NULL) { /* Regex. */
char *my_error_msg = NULL;
if (!(msc_regexec((msc_regex_t *)var->param_data, str->name,
strlen(str->name), &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1;
} else { /* Simple comparison. */
if (strcasecmp(str->name, var->param) == 0) match = 1;
}
}
/* If we had a match add this argument to the collection. */
if (match && (strncmp(str->name,"MATCHED_VARS:",13) != 0) && (strncmp(str->name,"MATCHED_VARS_NAMES:",19))) {
msre_var *rvar = apr_palloc(mptmp, sizeof(msre_var));
rvar->value = apr_pstrndup(mptmp, str->name, strlen(str->name));
rvar->value_len = strlen(rvar->value);
rvar->name = apr_psprintf(mptmp, "MATCHED_VARS_NAMES:%s",
log_escape_nq(mptmp, str->name));
apr_table_setn(vartab, rvar->name, (void *)rvar);
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "Set variable \"%s\" value \"%s\" size %d to collection.", rvar->name, rvar->value, rvar->value_len);
}
count++;
}
}
return count;
}
/* MATCHED_VARS */
static int var_matched_vars_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
apr_table_t *vartab, apr_pool_t *mptmp)
{
const apr_array_header_t *arr = NULL;
const apr_table_entry_t *te = NULL;
int i, count = 0;
arr = apr_table_elts(msr->matched_vars);
te = (apr_table_entry_t *)arr->elts;
for (i = 0; i < arr->nelts; i++) {
int match = 0;
msc_string *str = (msc_string *)te[i].val;
/* Figure out if we want to include this variable. */
if (var->param == NULL) match = 1;
else {
if (var->param_data != NULL) { /* Regex. */
char *my_error_msg = NULL;
if (!(msc_regexec((msc_regex_t *)var->param_data, str->name,
strlen(str->name), &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1;
} else { /* Simple comparison. */
if (strcasecmp(str->name, var->param) == 0) match = 1;
}
}
/* If we had a match add this argument to the collection. */
if (match && (strncmp(str->name,"MATCHED_VARS:",13) != 0) && (strncmp(str->name,"MATCHED_VARS_NAMES:",19))) {
//msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var));
msre_var *rvar = apr_palloc(mptmp, sizeof(msre_var));
rvar->value = apr_pstrndup(mptmp, str->value, str->value_len);
rvar->value_len = str->value_len;
rvar->name = apr_psprintf(mptmp, "MATCHED_VARS:%s",
log_escape_nq(mptmp, str->name));
apr_table_setn(vartab, rvar->name, (void *)rvar);
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "Set variable \"%s\" value \"%s\" size %d to collection.", rvar->name, rvar->value, rvar->value_len);
}
count++;
}
}
return count;
}
/* REQUEST_COOKIES */
static int var_request_cookies_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
@ -1863,7 +1977,7 @@ static int var_request_cookies_generate(modsec_rec *msr, msre_var *var, msre_rul
if (match) {
msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var));
rvar->value = te[i].val;
rvar->value = te[i].key;
rvar->value_len = strlen(rvar->value);
rvar->name = apr_psprintf(mptmp, "REQUEST_COOKIES:%s",
log_escape_nq(mptmp, te[i].key));
@ -2928,6 +3042,28 @@ void msre_engine_register_default_variables(msre_engine *engine) {
PHASE_REQUEST_BODY
);
/* MATCHED_VARS_NAMES */
msre_engine_variable_register(engine,
"MATCHED_VARS_NAMES",
VAR_LIST,
0, 1,
var_generic_list_validate,
var_matched_vars_names_generate,
VAR_CACHE,
PHASE_REQUEST_HEADERS
);
/* MATCHED_VARS */
msre_engine_variable_register(engine,
"MATCHED_VARS",
VAR_LIST,
0, 1,
var_generic_list_validate,
var_matched_vars_generate,
VAR_CACHE,
PHASE_REQUEST_HEADERS
);
/* REQUEST_COOKIES */
msre_engine_variable_register(engine,
"REQUEST_COOKIES",
@ -3038,6 +3174,18 @@ void msre_engine_register_default_variables(msre_engine *engine) {
PHASE_REQUEST_HEADERS
);
/* UNIQUE_ID */
msre_engine_variable_register(engine,
"UNIQUE_ID",
VAR_SIMPLE,
0, 0,
NULL,
var_uniqueid_generate,
VAR_CACHE,
PHASE_REQUEST_HEADERS
);
/* STREAM_OUTPUT_BODY */
msre_engine_variable_register(engine,
"STREAM_OUTPUT_BODY",

View File

@ -16,6 +16,8 @@
* directly using the email address support@trustwave.com.
*
*/
#ifndef UTF8TABLES_H_
#define UTF8TABLES_H_