From 49732256f65cefac69e1da674850f214358ac0f6 Mon Sep 17 00:00:00 2001 From: brenosilva Date: Fri, 25 Mar 2011 13:51:13 +0000 Subject: [PATCH] Improvements, fixes and new features --- apache2/acmp.c | 60 ++++----- apache2/acmp.h | 1 + apache2/apache2.h | 1 + apache2/apache2_config.c | 5 +- apache2/apache2_io.c | 21 +-- apache2/apache2_util.c | 1 + apache2/mod_security2.c | 2 + apache2/modsecurity.c | 7 + apache2/modsecurity.h | 4 + apache2/msc_geo.c | 1 + apache2/msc_geo.h | 1 + apache2/msc_gsb.h | 3 +- apache2/msc_logging.c | 24 +++- apache2/msc_logging.h | 1 + apache2/msc_lua.c | 1 + apache2/msc_lua.h | 1 + apache2/msc_multipart.c | 2 +- apache2/msc_multipart.h | 1 + apache2/msc_parsers.c | 1 + apache2/msc_parsers.h | 1 + apache2/msc_pcre.c | 1 + apache2/msc_pcre.h | 1 + apache2/msc_release.h | 1 + apache2/msc_reqbody.c | 3 +- apache2/msc_util.c | 2 +- apache2/msc_util.h | 1 + apache2/msc_xml.c | 1 + apache2/msc_xml.h | 1 + apache2/persist_dbm.c | 1 + apache2/persist_dbm.h | 1 + apache2/re.c | 42 +++++- apache2/re.h | 2 + apache2/re_actions.c | 46 ++++++- apache2/re_operators.c | 267 +++++++++++++++++++++++++++++++-------- apache2/re_tfns.c | 57 +++++++++ apache2/re_variables.c | 150 +++++++++++++++++++++- apache2/utf8tables.h | 2 + 37 files changed, 612 insertions(+), 106 deletions(-) diff --git a/apache2/acmp.c b/apache2/acmp.c index a8fae4af..23502fb8 100644 --- a/apache2/acmp.c +++ b/apache2/acmp.c @@ -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++; diff --git a/apache2/acmp.h b/apache2/acmp.h index dcd473d9..13f4e367 100644 --- a/apache2/acmp.h +++ b/apache2/acmp.h @@ -16,6 +16,7 @@ * directly using the email address support@trustwave.com. * */ + #ifndef ACMP_H_ #define ACMP_H_ diff --git a/apache2/apache2.h b/apache2/apache2.h index 024ab4c1..a8791e91 100644 --- a/apache2/apache2.h +++ b/apache2/apache2.h @@ -16,6 +16,7 @@ * directly using the email address support@trustwave.com. * */ + #ifndef _APACHE2_H_ #define _APACHE2_H_ diff --git a/apache2/apache2_config.c b/apache2/apache2_config.c index 0d311cb0..8f38d16c 100644 --- a/apache2/apache2_config.c +++ b/apache2/apache2_config.c @@ -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 #include "modsecurity.h" diff --git a/apache2/apache2_io.c b/apache2/apache2_io.c index 8cb45c04..31ef4670 100644 --- a/apache2/apache2_io.c +++ b/apache2/apache2_io.c @@ -16,6 +16,7 @@ * directly using the email address support@trustwave.com. * */ + #include #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; diff --git a/apache2/apache2_util.c b/apache2/apache2_util.c index 0c89bc2e..645a24fa 100644 --- a/apache2/apache2_util.c +++ b/apache2/apache2_util.c @@ -16,6 +16,7 @@ * directly using the email address support@trustwave.com. * */ + #include "modsecurity.h" #include "apache2.h" #include "http_core.h" diff --git a/apache2/mod_security2.c b/apache2/mod_security2.c index e654a1a2..bb3246b4 100644 --- a/apache2/mod_security2.c +++ b/apache2/mod_security2.c @@ -16,6 +16,7 @@ * directly using the email address support@trustwave.com. * */ + #include #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" diff --git a/apache2/modsecurity.c b/apache2/modsecurity.c index 9d72ec43..956f2d85 100644 --- a/apache2/modsecurity.c +++ b/apache2/modsecurity.c @@ -16,6 +16,7 @@ * directly using the email address support@trustwave.com. * */ + #include #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) { diff --git a/apache2/modsecurity.h b/apache2/modsecurity.h index 352f1ec6..7bae4277 100644 --- a/apache2/modsecurity.h +++ b/apache2/modsecurity.h @@ -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; }; diff --git a/apache2/msc_geo.c b/apache2/msc_geo.c index b5761ae3..000c6a87 100644 --- a/apache2/msc_geo.c +++ b/apache2/msc_geo.c @@ -16,6 +16,7 @@ * directly using the email address support@trustwave.com. * */ + #include "msc_geo.h" diff --git a/apache2/msc_geo.h b/apache2/msc_geo.h index a056f5c7..5d181b94 100644 --- a/apache2/msc_geo.h +++ b/apache2/msc_geo.h @@ -16,6 +16,7 @@ * directly using the email address support@trustwave.com. * */ + #ifndef _MSC_GEO_H_ #define _MSC_GEO_H_ diff --git a/apache2/msc_gsb.h b/apache2/msc_gsb.h index 2b364a69..6c1aeb13 100644 --- a/apache2/msc_gsb.h +++ b/apache2/msc_gsb.h @@ -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 diff --git a/apache2/msc_logging.c b/apache2/msc_logging.c index 32fd643e..5000c806 100644 --- a/apache2/msc_logging.c +++ b/apache2/msc_logging.c @@ -17,8 +17,7 @@ * */ -#include "modsecurity_config.h" - +#include "modsecurity.h" #include #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 : "")); + 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 */ diff --git a/apache2/msc_logging.h b/apache2/msc_logging.h index f0abb091..3bd56605 100644 --- a/apache2/msc_logging.h +++ b/apache2/msc_logging.h @@ -16,6 +16,7 @@ * directly using the email address support@trustwave.com. * */ + #ifndef _MSC_LOGGING_H_ #define _MSC_LOGGING_H_ diff --git a/apache2/msc_lua.c b/apache2/msc_lua.c index 1a09c4e4..7d108952 100644 --- a/apache2/msc_lua.c +++ b/apache2/msc_lua.c @@ -16,6 +16,7 @@ * directly using the email address support@trustwave.com. * */ + #if defined(WITH_LUA) #include "msc_lua.h" diff --git a/apache2/msc_lua.h b/apache2/msc_lua.h index cd60e17a..f0a0486b 100644 --- a/apache2/msc_lua.h +++ b/apache2/msc_lua.h @@ -16,6 +16,7 @@ * directly using the email address support@trustwave.com. * */ + #if defined(WITH_LUA) #ifndef _MSC_LUA_H_ diff --git a/apache2/msc_multipart.c b/apache2/msc_multipart.c index 343dda5b..26c8238c 100644 --- a/apache2/msc_multipart.c +++ b/apache2/msc_multipart.c @@ -16,8 +16,8 @@ * directly using the email address support@trustwave.com. * */ -#include "modsecurity_config.h" +#include "modsecurity.h" #include #include diff --git a/apache2/msc_multipart.h b/apache2/msc_multipart.h index 9321acbc..3df23d13 100644 --- a/apache2/msc_multipart.h +++ b/apache2/msc_multipart.h @@ -16,6 +16,7 @@ * directly using the email address support@trustwave.com. * */ + #ifndef _MSC_MULTIPART_H_ #define _MSC_MULTIPART_H_ diff --git a/apache2/msc_parsers.c b/apache2/msc_parsers.c index 83736f62..7aad1b53 100644 --- a/apache2/msc_parsers.c +++ b/apache2/msc_parsers.c @@ -16,6 +16,7 @@ * directly using the email address support@trustwave.com. * */ + #include "msc_parsers.h" #include diff --git a/apache2/msc_parsers.h b/apache2/msc_parsers.h index 30ff6bca..886accec 100644 --- a/apache2/msc_parsers.h +++ b/apache2/msc_parsers.h @@ -16,6 +16,7 @@ * directly using the email address support@trustwave.com. * */ + #ifndef _MSC_PARSERS_H_ #define _MSC_PARSERS_H_ diff --git a/apache2/msc_pcre.c b/apache2/msc_pcre.c index 32cce44a..43869ab3 100644 --- a/apache2/msc_pcre.c +++ b/apache2/msc_pcre.c @@ -16,6 +16,7 @@ * directly using the email address support@trustwave.com. * */ + #include "msc_pcre.h" #include "apr_strings.h" diff --git a/apache2/msc_pcre.h b/apache2/msc_pcre.h index a8c2e18a..703dff18 100644 --- a/apache2/msc_pcre.h +++ b/apache2/msc_pcre.h @@ -16,6 +16,7 @@ * directly using the email address support@trustwave.com. * */ + #ifndef _MSC_PCRE_H_ #define _MSC_PCRE_H_ diff --git a/apache2/msc_release.h b/apache2/msc_release.h index a8dc772d..ea0b6236 100644 --- a/apache2/msc_release.h +++ b/apache2/msc_release.h @@ -16,6 +16,7 @@ * directly using the email address support@trustwave.com. * */ + #ifndef _MSC_RELEASE_H_ #define _MSC_RELEASE_H_ diff --git a/apache2/msc_reqbody.c b/apache2/msc_reqbody.c index ab5880df..67639f6f 100644 --- a/apache2/msc_reqbody.c +++ b/apache2/msc_reqbody.c @@ -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); diff --git a/apache2/msc_util.c b/apache2/msc_util.c index b2f3454f..e716214f 100644 --- a/apache2/msc_util.c +++ b/apache2/msc_util.c @@ -16,8 +16,8 @@ * directly using the email address support@trustwave.com. * */ -#include "modsecurity_config.h" +#include "modsecurity.h" #include #include #include diff --git a/apache2/msc_util.h b/apache2/msc_util.h index 32992b98..ad04bcc0 100644 --- a/apache2/msc_util.h +++ b/apache2/msc_util.h @@ -16,6 +16,7 @@ * directly using the email address support@trustwave.com. * */ + #ifndef _UTIL_H_ #define _UTIL_H_ diff --git a/apache2/msc_xml.c b/apache2/msc_xml.c index 7361f371..80eb724e 100644 --- a/apache2/msc_xml.c +++ b/apache2/msc_xml.c @@ -16,6 +16,7 @@ * directly using the email address support@trustwave.com. * */ + #include "msc_xml.h" diff --git a/apache2/msc_xml.h b/apache2/msc_xml.h index 9e27fe32..511bbcb3 100644 --- a/apache2/msc_xml.h +++ b/apache2/msc_xml.h @@ -16,6 +16,7 @@ * directly using the email address support@trustwave.com. * */ + #ifndef _MSC_XML_H_ #define _MSC_XML_H_ diff --git a/apache2/persist_dbm.c b/apache2/persist_dbm.c index 9fefa838..a446bf9b 100644 --- a/apache2/persist_dbm.c +++ b/apache2/persist_dbm.c @@ -16,6 +16,7 @@ * directly using the email address support@trustwave.com. * */ + #include "persist_dbm.h" #include "apr_sdbm.h" diff --git a/apache2/persist_dbm.h b/apache2/persist_dbm.h index b94b58da..1b7a340f 100644 --- a/apache2/persist_dbm.h +++ b/apache2/persist_dbm.h @@ -16,6 +16,7 @@ * directly using the email address support@trustwave.com. * */ + #ifndef _PERSIST_DBM_H_ #define _PERSIST_DBM_H_ diff --git a/apache2/re.c b/apache2/re.c index a364d7d2..e173ae59 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -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 #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)) { diff --git a/apache2/re.h b/apache2/re.h index ec4a94cb..aab13a32 100644 --- a/apache2/re.h +++ b/apache2/re.h @@ -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; }; diff --git a/apache2/re_actions.c b/apache2/re_actions.c index 364e8a6c..95c57d09 100644 --- a/apache2/re_actions.c +++ b/apache2/re_actions.c @@ -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 #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 */ diff --git a/apache2/re_operators.c b/apache2/re_operators.c index 3ae520cb..99888611 100644 --- a/apache2/re_operators.c +++ b/apache2/re_operators.c @@ -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 +#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 : "")); /* 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); diff --git a/apache2/re_tfns.c b/apache2/re_tfns.c index 3f1d4190..fb7f15c8 100644 --- a/apache2/re_tfns.c +++ b/apache2/re_tfns.c @@ -16,6 +16,7 @@ * directly using the email address support@trustwave.com. * */ + #include #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", diff --git a/apache2/re_variables.c b/apache2/re_variables.c index 9de7d779..6e520996 100644 --- a/apache2/re_variables.c +++ b/apache2/re_variables.c @@ -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", diff --git a/apache2/utf8tables.h b/apache2/utf8tables.h index d88809d8..e386a4f1 100644 --- a/apache2/utf8tables.h +++ b/apache2/utf8tables.h @@ -16,6 +16,8 @@ * directly using the email address support@trustwave.com. * */ + + #ifndef UTF8TABLES_H_ #define UTF8TABLES_H_