Include data edition, sanitizematched and few fixes

This commit is contained in:
brenosilva 2011-02-14 12:49:55 +00:00
parent 37e8cba181
commit 7f52d86e4b
13 changed files with 762 additions and 75 deletions

View File

@ -104,6 +104,10 @@ void *create_directory_config(apr_pool_t *mp, char *path)
/* Content injection. */ /* Content injection. */
dcfg->content_injection_enabled = NOT_SET; dcfg->content_injection_enabled = NOT_SET;
/* Stream inspection */
dcfg->stream_inbody_inspection = NOT_SET;
dcfg->stream_outbody_inspection = NOT_SET;
/* Geo Lookups */ /* Geo Lookups */
dcfg->geo = NOT_SET_P; dcfg->geo = NOT_SET_P;
@ -445,6 +449,12 @@ void *merge_directory_configs(apr_pool_t *mp, void *_parent, void *_child)
merged->content_injection_enabled = (child->content_injection_enabled == NOT_SET merged->content_injection_enabled = (child->content_injection_enabled == NOT_SET
? parent->content_injection_enabled : child->content_injection_enabled); ? parent->content_injection_enabled : child->content_injection_enabled);
/* Stream inspection */
merged->stream_inbody_inspection = (child->stream_inbody_inspection == NOT_SET
? parent->stream_inbody_inspection : child->stream_inbody_inspection);
merged->stream_outbody_inspection = (child->stream_outbody_inspection == NOT_SET
? parent->stream_outbody_inspection : child->stream_outbody_inspection);
/* Geo Lookup */ /* Geo Lookup */
merged->geo = (child->geo == NOT_SET_P merged->geo = (child->geo == NOT_SET_P
? parent->geo : child->geo); ? parent->geo : child->geo);
@ -543,6 +553,10 @@ void init_directory_config(directory_config *dcfg)
/* Content injection. */ /* Content injection. */
if (dcfg->content_injection_enabled == NOT_SET) dcfg->content_injection_enabled = 0; if (dcfg->content_injection_enabled == NOT_SET) dcfg->content_injection_enabled = 0;
/* Stream inspection */
if (dcfg->stream_inbody_inspection == NOT_SET) dcfg->stream_inbody_inspection = 0;
if (dcfg->stream_outbody_inspection == NOT_SET) dcfg->stream_outbody_inspection = 0;
/* Geo Lookup */ /* Geo Lookup */
if (dcfg->geo == NOT_SET_P) dcfg->geo = NULL; if (dcfg->geo == NOT_SET_P) dcfg->geo = NULL;
@ -1334,6 +1348,72 @@ static const char *cmd_guardian_log(cmd_parms *cmd, void *_dcfg,
return NULL; return NULL;
} }
/*
* \brief Add StreamInBodyInspection configuration option
*
* \param cmd Pointer to configuration data
* \param _dcfg Pointer to directory configuration
* \param p1 Pointer to configuration option
*
* \retval NULL On failure
* \retval apr_psprintf On Success
*/
static const char *cmd_stream_inbody_inspection(cmd_parms *cmd, void *_dcfg, int flag)
{
directory_config *dcfg = (directory_config *)_dcfg;
if (dcfg == NULL) return NULL;
dcfg->stream_inbody_inspection = flag;
return NULL;
}
/*
* \brief Add StreamOutBodyInspection configuration option
*
* \param cmd Pointer to configuration data
* \param _dcfg Pointer to directory configuration
* \param p1 Pointer to configuration option
*
* \retval NULL On failure
* \retval apr_psprintf On Success
*/
static const char *cmd_stream_outbody_inspection(cmd_parms *cmd, void *_dcfg, int flag)
{
directory_config *dcfg = (directory_config *)_dcfg;
if (dcfg == NULL) return NULL;
dcfg->stream_outbody_inspection = flag;
return NULL;
}
/*
* \brief Add SecReadStateLimit configuration option
*
* \param cmd Pointer to configuration data
* \param _dcfg Pointer to directory configuration
* \param p1 Pointer to configuration option
*
* \retval NULL On failure
* \retval apr_psprintf On Success
*/
static const char *cmd_conn_read_state_limit(cmd_parms *cmd, void *_dcfg,
const char *p1)
{
directory_config *dcfg = (directory_config *)_dcfg;
long int limit;
if (dcfg == NULL) return NULL;
limit = strtol(p1, NULL, 10);
if ((limit == LONG_MAX)||(limit == LONG_MIN)||(limit <= 0)) {
return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecReadStateLimit: %s", p1);
}
conn_read_state_limit = limit;
return NULL;
}
static const char *cmd_request_body_inmemory_limit(cmd_parms *cmd, void *_dcfg, static const char *cmd_request_body_inmemory_limit(cmd_parms *cmd, void *_dcfg,
const char *p1) const char *p1)
{ {
@ -2029,6 +2109,22 @@ const command_rec module_directives[] = {
"On or Off" "On or Off"
), ),
AP_INIT_FLAG (
"StreamOutBodyInspection",
cmd_stream_outbody_inspection,
NULL,
CMD_SCOPE_ANY,
"On or Off"
),
AP_INIT_FLAG (
"StreamInBodyInspection",
cmd_stream_inbody_inspection,
NULL,
CMD_SCOPE_ANY,
"On or Off"
),
AP_INIT_TAKE1 ( AP_INIT_TAKE1 (
"SecCookieFormat", "SecCookieFormat",
cmd_cookie_format, cmd_cookie_format,
@ -2134,6 +2230,14 @@ const command_rec module_directives[] = {
"On or Off" "On or Off"
), ),
AP_INIT_TAKE1 (
"SecReadStateLimit",
cmd_conn_read_state_limit,
NULL,
CMD_SCOPE_ANY,
"maximum number of threads in READ_BUSY state per ip address"
),
AP_INIT_TAKE1 ( AP_INIT_TAKE1 (
"SecRequestBodyInMemoryLimit", "SecRequestBodyInMemoryLimit",
cmd_request_body_inmemory_limit, cmd_request_body_inmemory_limit,

View File

@ -21,7 +21,6 @@
#include "modsecurity.h" #include "modsecurity.h"
#include "apache2.h" #include "apache2.h"
/* -- Input filter -- */ /* -- Input filter -- */
#if 0 #if 0
@ -89,7 +88,7 @@ apr_status_t input_filter(ap_filter_t *f, apr_bucket_brigade *bb_out,
return APR_EGENERAL; return APR_EGENERAL;
} }
if (chunk) { if (chunk && !msr->txcfg->stream_inbody_inspection) {
/* Copy the data we received in the chunk */ /* Copy the data we received in the chunk */
bucket = apr_bucket_heap_create(chunk->data, chunk->length, NULL, bucket = apr_bucket_heap_create(chunk->data, chunk->length, NULL,
f->r->connection->bucket_alloc); f->r->connection->bucket_alloc);
@ -117,6 +116,22 @@ apr_status_t input_filter(ap_filter_t *f, apr_bucket_brigade *bb_out,
if (msr->txcfg->debuglog_level >= 4) { if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "Input filter: Forwarded %" APR_SIZE_T_FMT " bytes.", chunk->length); msr_log(msr, 4, "Input filter: Forwarded %" APR_SIZE_T_FMT " bytes.", chunk->length);
} }
} else if (msr->stream_input_data != NULL) {
bucket = apr_bucket_heap_create(msr->stream_input_data, msr->stream_input_length, NULL,
f->r->connection->bucket_alloc);
if (bucket == NULL) return APR_EGENERAL;
APR_BRIGADE_INSERT_TAIL(bb_out, bucket);
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "Input stream filter: Forwarded %" APR_SIZE_T_FMT " bytes.", msr->msc_reqbody_disk_chunk->length);
}
}
if(msr->txcfg->stream_inbody_inspection && msr->stream_input_data != NULL) {
free(msr->stream_input_data);
msr->stream_input_data = NULL;
} }
if (rc == 0) { if (rc == 0) {
@ -259,7 +274,7 @@ apr_status_t read_request_body(modsec_rec *msr, char **error_msg) {
if (msr->txcfg->debuglog_level >= 4) { if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "Input filter: Completed receiving request body (length %" APR_SIZE_T_FMT ").", msr_log(msr, 4, "Input filter: Completed receiving request body (length %" APR_SIZE_T_FMT ").",
msr->reqbody_length); msr->reqbody_length);
} }
msr->if_status = IF_STATUS_WANTS_TO_RUN; msr->if_status = IF_STATUS_WANTS_TO_RUN;
@ -409,9 +424,9 @@ static apr_status_t send_of_brigade(modsec_rec *msr, ap_filter_t *f) {
rc = ap_pass_brigade(f->next, msr->of_brigade); rc = ap_pass_brigade(f->next, msr->of_brigade);
if (rc != APR_SUCCESS) { if (rc != APR_SUCCESS) {
/* TODO: These need to move to flags in 2.6. For now log them /* TODO: These need to move to flags in 2.6. For now log them
* at level 3 so that they are not confusing users. * at level 4 so that they are not confusing users.
*/ */
int log_level = 3; int log_level = 4;
if (msr->txcfg->debuglog_level >= log_level) { if (msr->txcfg->debuglog_level >= log_level) {
switch(rc) { switch(rc) {
@ -438,6 +453,34 @@ static apr_status_t send_of_brigade(modsec_rec *msr, ap_filter_t *f) {
return APR_SUCCESS; return APR_SUCCESS;
} }
static void inject_content_to_of_brigade(modsec_rec *msr, ap_filter_t *f) {
apr_bucket *b;
if (msr->txcfg->content_injection_enabled && msr->stream_output_data != NULL) {
apr_bucket *bucket_ci = NULL;
apr_bucket *bucket_eos = NULL;
bucket_ci = apr_bucket_heap_create(msr->stream_output_data,
msr->stream_output_length, NULL, f->r->connection->bucket_alloc);
for (b = APR_BRIGADE_FIRST(msr->of_brigade); b != APR_BRIGADE_SENTINEL(msr->of_brigade); b = APR_BUCKET_NEXT(b)) {
if(!APR_BUCKET_IS_METADATA(b))
apr_bucket_delete(b);
}
APR_BRIGADE_INSERT_HEAD(msr->of_brigade, bucket_ci);
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "Content Injection: Data reinjected bytes [%d]",msr->stream_output_length);
}
}
if(msr->stream_output_data != NULL) {
free(msr->stream_output_data);
msr->stream_output_data = NULL;
}
}
/** /**
* *
*/ */
@ -486,6 +529,19 @@ static int flatten_response_body(modsec_rec *msr) {
msr->resbody_data[msr->resbody_length] = '\0'; msr->resbody_data[msr->resbody_length] = '\0';
msr->resbody_status = RESBODY_STATUS_READ; 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;
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);
}
return 1; return 1;
} }
@ -801,6 +857,7 @@ apr_status_t output_filter(ap_filter_t *f, apr_bucket_brigade *bb_in) {
* (full-buffering only). * (full-buffering only).
*/ */
if ((msr->of_skipping == 0)&&(!msr->of_partial)) { if ((msr->of_skipping == 0)&&(!msr->of_partial)) {
inject_content_to_of_brigade(msr,f);
prepend_content_to_of_brigade(msr, f); prepend_content_to_of_brigade(msr, f);
/* Inject content into response (append & buffering). */ /* Inject content into response (append & buffering). */

View File

@ -575,7 +575,6 @@ static int hook_post_config(apr_pool_t *mp, apr_pool_t *mp_log, apr_pool_t *mp_t
ap_log_error(APLOG_MARK, APLOG_NOTICE | APLOG_NOERRNO, 0, s, ap_log_error(APLOG_MARK, APLOG_NOTICE | APLOG_NOERRNO, 0, s,
"%s configured.", MODSEC_MODULE_NAME_FULL); "%s configured.", MODSEC_MODULE_NAME_FULL);
/* show libraries informations */
version(mp); version(mp);
/* If we've changed the server signature make note of the original. */ /* If we've changed the server signature make note of the original. */
@ -802,6 +801,13 @@ static int hook_request_late(request_rec *r) {
rc = perform_interception(msr); rc = perform_interception(msr);
} }
if(msr->txcfg->stream_inbody_inspection && msr->msc_reqbody_read) {
const char *clen = NULL;
clen = apr_psprintf(msr->mp,"%d",msr->stream_input_length);
if(clen)
apr_table_setn(r->headers_in, "Content-Length",clen);
}
/* Remove the compression ability indications the client set, /* Remove the compression ability indications the client set,
* but only if we need to disable backend compression. * but only if we need to disable backend compression.
*/ */
@ -1250,8 +1256,6 @@ static void register_hooks(apr_pool_t *mp) {
NULL NULL
}; };
/* Add the MODSEC_2.x compatibility defines */ /* Add the MODSEC_2.x compatibility defines */
*(char **)apr_array_push(ap_server_config_defines) = apr_pstrdup(mp, "MODSEC_2.5"); *(char **)apr_array_push(ap_server_config_defines) = apr_pstrdup(mp, "MODSEC_2.5");
@ -1311,8 +1315,10 @@ static void register_hooks(apr_pool_t *mp) {
* mod_deflate = -1 * mod_deflate = -1
* mod_headers = 0 * mod_headers = 0
*/ */
ap_register_output_filter("MODSECURITY_OUT", output_filter, ap_register_output_filter("MODSECURITY_OUT", output_filter,
NULL, AP_FTYPE_CONTENT_SET - 3); NULL, AP_FTYPE_CONTENT_SET - 3);
} }
/* Defined in apache2_config.c */ /* Defined in apache2_config.c */

View File

@ -355,6 +355,8 @@ apr_status_t modsecurity_tx_init(modsec_rec *msr) {
if (msr->request_headers_to_sanitize == NULL) return -1; if (msr->request_headers_to_sanitize == NULL) return -1;
msr->response_headers_to_sanitize = apr_table_make(msr->mp, 16); msr->response_headers_to_sanitize = apr_table_make(msr->mp, 16);
if (msr->response_headers_to_sanitize == NULL) return -1; if (msr->response_headers_to_sanitize == NULL) return -1;
msr->pattern_to_sanitize = apr_table_make(msr->mp, 32);
if (msr->pattern_to_sanitize == NULL) return -1;
/* Initialise cookies */ /* Initialise cookies */
msr->request_cookies = apr_table_make(msr->mp, 16); msr->request_cookies = apr_table_make(msr->mp, 16);
@ -543,6 +545,7 @@ static apr_status_t modsecurity_process_phase_response_body(modsec_rec *msr) {
msr->time_phase4 = apr_time_now() - time_before; msr->time_phase4 = apr_time_now() - time_before;
return rc; return rc;
} }

View File

@ -32,6 +32,7 @@ typedef struct msc_engine msc_engine;
typedef struct msc_data_chunk msc_data_chunk; typedef struct msc_data_chunk msc_data_chunk;
typedef struct msc_arg msc_arg; typedef struct msc_arg msc_arg;
typedef struct msc_string msc_string; typedef struct msc_string msc_string;
typedef struct msc_parm msc_parm;
#include "msc_release.h" #include "msc_release.h"
#include "msc_logging.h" #include "msc_logging.h"
@ -229,6 +230,11 @@ struct modsec_rec {
char *resbody_data; char *resbody_data;
unsigned int resbody_contains_html; unsigned int resbody_contains_html;
apr_size_t stream_input_length;
char *stream_input_data;
apr_size_t stream_output_length;
char *stream_output_data;
apr_array_header_t *error_messages; apr_array_header_t *error_messages;
apr_array_header_t *alerts; apr_array_header_t *alerts;
@ -267,6 +273,7 @@ struct modsec_rec {
apr_table_t *request_headers_to_sanitize; apr_table_t *request_headers_to_sanitize;
apr_table_t *response_headers_to_sanitize; apr_table_t *response_headers_to_sanitize;
apr_table_t *request_cookies; apr_table_t *request_cookies;
apr_table_t *pattern_to_sanitize;
unsigned int urlencoded_error; unsigned int urlencoded_error;
unsigned int inbound_error; unsigned int inbound_error;
@ -473,6 +480,10 @@ struct directory_config {
/* Content injection. */ /* Content injection. */
int content_injection_enabled; int content_injection_enabled;
/* Stream Inspection */
int stream_inbody_inspection;
int stream_outbody_inspection;
/* Geo Lookup */ /* Geo Lookup */
geo_db *geo; geo_db *geo;
@ -535,6 +546,11 @@ struct msc_string {
unsigned int value_len; unsigned int value_len;
}; };
struct msc_parm {
char *value;
unsigned int pad_1;
unsigned int pad_2;
};
/* Engine functions */ /* Engine functions */

View File

@ -343,15 +343,41 @@ int geo_lookup(modsec_rec *msr, geo_rec *georec, const char *target, char **erro
/* NOTE: This is hard-coded for size 3 records */ /* NOTE: This is hard-coded for size 3 records */
/* Left */ /* Left */
if ((ipnum & (1 << level)) == 0) { if ((ipnum & (1 << level)) == 0) {
//rec_val = buf[0] +
// (buf[1] << 8) +
// (buf[2] << 16);
rec_val = (buf[3*0 + 0] << (0*8)) + rec_val = (buf[3*0 + 0] << (0*8)) +
(buf[3*0 + 1] << (1*8)) + (buf[3*0 + 1] << (1*8)) +
(buf[3*0 + 2] << (2*8)); (buf[3*0 + 2] << (2*8));
/*j = 3;
p = &buf[2*j];
x = 0;
do {
x <<= 8;
x += *(--p);
} while ( --j );
rec_val = x;
*/
} }
/* Right */ /* Right */
else { else {
//rec_val = buf[3] +
// (buf[4] << 8) +
// (buf[5] << 16);
rec_val = (buf[3*1 + 0] << (0*8)) + rec_val = (buf[3*1 + 0] << (0*8)) +
(buf[3*1 + 1] << (1*8)) + (buf[3*1 + 1] << (1*8)) +
(buf[3*1 + 2] << (2*8)); (buf[3*1 + 2] << (2*8));
/*j = 3;
p = &buf[1*j];
x = 0;
do {
x <<= 8;
x += *(--p);
} while ( --j );
rec_val = x;
*/
} }
/* If we are past the country offset, then we are done */ /* If we are past the country offset, then we are done */

View File

@ -326,10 +326,16 @@ static char *create_auditlog_boundary(request_rec *r) {
* that have been marked as sensitive. * that have been marked as sensitive.
*/ */
static void sanitize_request_line(modsec_rec *msr) { static void sanitize_request_line(modsec_rec *msr) {
const apr_array_header_t *tarr; const apr_array_header_t *tarr = NULL;
const apr_table_entry_t *telts; const apr_table_entry_t *telts = NULL;
int i; const apr_array_header_t *tarr_pattern = NULL;
const apr_table_entry_t *telts_pattern = NULL;
msc_parm *mparm = NULL;
int i, k;
char *qspos; char *qspos;
char *buf = NULL;
int sanitized_partial = 0;
int sanitize_matched = 0;
/* Locate the query string. */ /* Locate the query string. */
qspos = strstr(msr->request_line, "?"); qspos = strstr(msr->request_line, "?");
@ -343,8 +349,9 @@ static void sanitize_request_line(modsec_rec *msr) {
msc_arg *arg = (msc_arg *)telts[i].val; msc_arg *arg = (msc_arg *)telts[i].val;
/* Only look at the parameters that appeared in the query string. */ /* Only look at the parameters that appeared in the query string. */
if (strcmp(arg->origin, "QUERY_STRING") == 0) { if (strcmp(arg->origin, "QUERY_STRING") == 0) {
char *pat = NULL;
char *p; char *p;
int j; int j, arg_min, arg_max;
/* Go to the beginning of the parameter. */ /* Go to the beginning of the parameter. */
p = qspos; p = qspos;
@ -352,23 +359,65 @@ static void sanitize_request_line(modsec_rec *msr) {
while((*p != '\0')&&(j--)) p++; while((*p != '\0')&&(j--)) p++;
if (*p == '\0') { if (*p == '\0') {
msr_log(msr, 1, "Unable to sanitize variable \"%s\" at offset %u of QUERY_STRING" msr_log(msr, 1, "Unable to sanitize variable \"%s\" at offset %u of QUERY_STRING"
"because the request line is too short.", "because the request line is too short.",
log_escape_ex(msr->mp, arg->name, arg->name_len), log_escape_ex(msr->mp, arg->name, arg->name_len),
arg->value_origin_offset); arg->value_origin_offset);
continue; continue;
} }
/* Write over the value. */ tarr_pattern = apr_table_elts(msr->pattern_to_sanitize);
j = arg->value_origin_len; telts_pattern = (const apr_table_entry_t*)tarr_pattern->elts;
while((*p != '\0')&&(j--)) {
*p++ = '*'; sanitized_partial = 0;
sanitize_matched = 0;
buf = apr_psprintf(msr->mp, "%s",p);
for ( k = 0; k < tarr_pattern->nelts; k++) {
if(strncmp(telts_pattern[k].key,arg->name,strlen(arg->name)) ==0 ) {
mparm = (msc_parm *)telts_pattern[k].val;
pat = strstr(buf,mparm->value);
if(mparm->pad_1 == -1)
sanitize_matched = 1;
if (pat != NULL) {
j = strlen(mparm->value);
arg_min = j;
arg_max = 1;
while((*pat != '\0')&&(j--)) {
if(arg_max > mparm->pad_2) {
int off = (strlen(mparm->value) - arg_max);
int pos = (mparm->pad_1-1);
if(off > pos) {
*pat = '*';
}
}
arg_max++;
arg_min--;
*pat++;
}
}
sanitized_partial = 1;
}
} }
if (*p == '\0') {
msr_log(msr, 1, "Unable to sanitize variable \"%s\" at offset %u (size %d) " if(sanitized_partial == 1 && sanitize_matched == 0) {
"of QUERY_STRING because the request line is too short.", while(*buf != '\0') {
log_escape_ex(msr->mp, arg->name, arg->name_len), *p++ = *buf++;
arg->value_origin_offset, arg->value_origin_len); }
continue; continue;
} else {
/* Write over the value. */
j = arg->value_origin_len;
while((*p != '\0')&&(j--)) {
*p++ = '*';
}
if (*p == '\0') {
msr_log(msr, 1, "Unable to sanitize variable \"%s\" at offset %u (size %d) "
"of QUERY_STRING because the request line is too short.",
log_escape_ex(msr->mp, arg->name, arg->name_len),
arg->value_origin_offset, arg->value_origin_len);
continue;
}
} }
} }
} }
@ -451,7 +500,7 @@ msre_rule *return_chained_rule(const msre_rule *current, modsec_rec *msr) {
for (i = 0; i < arr->nelts; i++) { for (i = 0; i < arr->nelts; i++) {
rule = rules[i]; rule = rules[i];
if (rule != NULL) { if (rule != NULL) {
if (strcmp(current->unparsed,rule->unparsed) == 0) { if (strncmp(current->unparsed,rule->unparsed,strlen(rule->unparsed)) == 0) {
if (i < arr->nelts -1) { if (i < arr->nelts -1) {
next_rule = rules[i+1]; next_rule = rules[i+1];
} else { } else {
@ -482,7 +531,7 @@ int chained_is_matched(modsec_rec *msr, const msre_rule *next_rule) {
for (i = 0; i < msr->matched_rules->nelts; i++) { for (i = 0; i < msr->matched_rules->nelts; i++) {
rule = ((msre_rule **)msr->matched_rules->elts)[i]; rule = ((msre_rule **)msr->matched_rules->elts)[i];
if (rule != NULL && (strcmp(rule->unparsed,next_rule->unparsed) == 0)) if (rule != NULL && (strncmp(rule->unparsed,next_rule->unparsed,strlen(next_rule->unparsed)) == 0))
return 1; return 1;
} }
@ -495,6 +544,8 @@ int chained_is_matched(modsec_rec *msr, const msre_rule *next_rule) {
void sec_audit_logger(modsec_rec *msr) { void sec_audit_logger(modsec_rec *msr) {
const apr_array_header_t *arr = NULL; const apr_array_header_t *arr = NULL;
apr_table_entry_t *te = NULL; apr_table_entry_t *te = NULL;
const apr_array_header_t *tarr_pattern = NULL;
const apr_table_entry_t *telts_pattern = NULL;
char *str1 = NULL, *str2 = NULL, *text = NULL; char *str1 = NULL, *str2 = NULL, *text = NULL;
const msre_rule *rule = NULL, *next_rule = NULL; const msre_rule *rule = NULL, *next_rule = NULL;
apr_size_t nbytes, nbytes_written; apr_size_t nbytes, nbytes_written;
@ -504,7 +555,10 @@ void sec_audit_logger(modsec_rec *msr) {
int wrote_response_body = 0; int wrote_response_body = 0;
char *entry_filename, *entry_basename; char *entry_filename, *entry_basename;
apr_status_t rc; apr_status_t rc;
int i, limit; int i, limit, k, sanitized_partial, j;
char *buf = NULL, *pat = NULL;
msc_parm *mparm = NULL;
int arg_min, arg_max, sanitize_matched;
/* the boundary is used by both audit log types */ /* the boundary is used by both audit log types */
msr->new_auditlog_boundary = create_auditlog_boundary(msr->r); msr->new_auditlog_boundary = create_auditlog_boundary(msr->r);
@ -621,12 +675,49 @@ void sec_audit_logger(modsec_rec *msr) {
arr = apr_table_elts(msr->request_headers); arr = apr_table_elts(msr->request_headers);
te = (apr_table_entry_t *)arr->elts; te = (apr_table_entry_t *)arr->elts;
tarr_pattern = apr_table_elts(msr->pattern_to_sanitize);
telts_pattern = (const apr_table_entry_t*)tarr_pattern->elts;
for (i = 0; i < arr->nelts; i++) { for (i = 0; i < arr->nelts; i++) {
sanitized_partial = 0;
sanitize_matched = 0;
text = apr_psprintf(msr->mp, "%s: %s\n", te[i].key, te[i].val); text = apr_psprintf(msr->mp, "%s: %s\n", te[i].key, te[i].val);
/* Do we need to sanitize this request header? */
if (apr_table_get(msr->request_headers_to_sanitize, te[i].key) != NULL) { if (apr_table_get(msr->request_headers_to_sanitize, te[i].key) != NULL) {
/* Yes, sanitize it. */ buf = apr_psprintf(msr->mp, "%s",text+strlen(te[i].key)+2);
memset(text + strlen(te[i].key) + 2, '*', strlen(te[i].val));
for ( k = 0; k < tarr_pattern->nelts; k++) {
if(strncmp(telts_pattern[k].key,te[i].key,strlen(te[i].key)) ==0 ) {
mparm = (msc_parm *)telts_pattern[k].val;
if(mparm->pad_1 == -1)
sanitize_matched = 1;
pat = strstr(buf,mparm->value);
if (pat != NULL) {
j = strlen(mparm->value);
arg_min = j;
arg_max = 1;
while((*pat != '\0')&&(j--)) {
if(arg_max > mparm->pad_2) {
int off = strlen(mparm->value) - arg_max;
int pos = mparm->pad_1-1;
if(off > pos) {
*pat = '*';
}
}
arg_max++;
arg_min--;
*pat++;
}
sanitized_partial = 1;
}
}
}
if(sanitized_partial == 1 && sanitize_matched == 0) {
text = apr_psprintf(msr->mp, "%s: %s\n", te[i].key, buf);
} else {
memset(text + strlen(te[i].key) + 2, '*', strlen(te[i].val));
}
} }
sec_auditlog_write(msr, text, strlen(text)); sec_auditlog_write(msr, text, strlen(text));
} }
@ -820,10 +911,10 @@ void sec_audit_logger(modsec_rec *msr) {
if (msr->response_headers_sent) { if (msr->response_headers_sent) {
if (msr->status_line != NULL) { if (msr->status_line != NULL) {
text = apr_psprintf(msr->mp, "%s %s\n", msr->response_protocol, text = apr_psprintf(msr->mp, "%s %s\n", msr->response_protocol,
msr->status_line); msr->status_line);
} else { } else {
text = apr_psprintf(msr->mp, "%s %u\n", msr->response_protocol, text = apr_psprintf(msr->mp, "%s %u\n", msr->response_protocol,
msr->response_status); msr->response_status);
} }
sec_auditlog_write(msr, text, strlen(text)); sec_auditlog_write(msr, text, strlen(text));
@ -831,18 +922,57 @@ void sec_audit_logger(modsec_rec *msr) {
arr = apr_table_elts(msr->response_headers); arr = apr_table_elts(msr->response_headers);
te = (apr_table_entry_t *)arr->elts; te = (apr_table_entry_t *)arr->elts;
tarr_pattern = apr_table_elts(msr->pattern_to_sanitize);
telts_pattern = (const apr_table_entry_t*)tarr_pattern->elts;
for (i = 0; i < arr->nelts; i++) { for (i = 0; i < arr->nelts; i++) {
sanitized_partial = 0;
sanitize_matched = 0;
text = apr_psprintf(msr->mp, "%s: %s\n", te[i].key, te[i].val); text = apr_psprintf(msr->mp, "%s: %s\n", te[i].key, te[i].val);
/* Do we need to sanitize this response header? */
if (apr_table_get(msr->response_headers_to_sanitize, te[i].key) != NULL) { if (apr_table_get(msr->response_headers_to_sanitize, te[i].key) != NULL) {
/* Yes, sanitize it. */ buf = apr_psprintf(msr->mp, "%s",text+strlen(te[i].key)+2);
memset(text + strlen(te[i].key) + 2, '*', strlen(te[i].val));
for ( k = 0; k < tarr_pattern->nelts; k++) {
if(strncmp(telts_pattern[k].key,te[i].key,strlen(te[i].key)) ==0 ) {
mparm = (msc_parm *)telts_pattern[k].val;
if(mparm->pad_1 == -1)
sanitize_matched = 1;
pat = strstr(buf,mparm->value);
if (pat != NULL) {
j = strlen(mparm->value);
arg_min = j;
arg_max = 1;
while((*pat != '\0')&&(j--)) {
if(arg_max > mparm->pad_2) {
int off = strlen(mparm->value) - arg_max;
int pos = mparm->pad_1-1;
if(off > pos) {
*pat = '*';
}
}
arg_max++;
arg_min--;
*pat++;
}
sanitized_partial = 1;
}
}
}
if(sanitized_partial == 1 && sanitize_matched == 0) {
text = apr_psprintf(msr->mp, "%s: %s\n", te[i].key, buf);
} else {
memset(text + strlen(te[i].key) + 2, '*', strlen(te[i].val));
}
} }
sec_auditlog_write(msr, text, strlen(text)); sec_auditlog_write(msr, text, strlen(text));
} }
} }
} }
apr_table_clear(msr->pattern_to_sanitize);
/* AUDITLOG_PART_RESPONSE_BODY */ /* AUDITLOG_PART_RESPONSE_BODY */
if (strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_RESPONSE_BODY) != NULL) { if (strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_RESPONSE_BODY) != NULL) {

View File

@ -308,7 +308,6 @@ apr_status_t modsecurity_request_body_store(modsec_rec *msr,
msre_reqbody_processor_metadata *metadata = msre_reqbody_processor_metadata *metadata =
(msre_reqbody_processor_metadata *)apr_table_get(msr->modsecurity->msre->reqbody_processors, msr->msc_reqbody_processor); (msre_reqbody_processor_metadata *)apr_table_get(msr->modsecurity->msre->reqbody_processors, msr->msc_reqbody_processor);
if (metadata != NULL) { if (metadata != NULL) {
if ( (metadata->process != NULL) if ( (metadata->process != NULL)
&& (metadata->process(msr, data, length, &my_error_msg) < 0)) && (metadata->process(msr, data, length, &my_error_msg) < 0))
@ -384,6 +383,51 @@ apr_status_t modsecurity_request_body_store(modsec_rec *msr,
return -1; return -1;
} }
static apr_status_t modsecurity_request_body_to_stream(modsec_rec *msr, char **error_msg) {
msc_data_chunk **chunks;
char *d;
int i, sofar;
*error_msg = NULL;
/* Allocate a buffer large enough to hold the request body. */
if (msr->msc_reqbody_length + 1 == 0) {
*error_msg = apr_psprintf(msr->mp, "Internal error, request body length will overflow the stream buffer: %u",
msr->msc_reqbody_length);
return -1;
}
msr->stream_input_length = msr->msc_reqbody_length;
msr->stream_input_data = malloc(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);
return -1;
}
msr->stream_input_data[msr->stream_input_length] = '\0';
/* Copy the data we keep in chunks into the new buffer. */
sofar = 0;
d = msr->stream_input_data;
chunks = (msc_data_chunk **)msr->msc_reqbody_chunks->elts;
for(i = 0; i < msr->msc_reqbody_chunks->nelts; i++) {
if (sofar + chunks[i]->length <= msr->stream_input_length) {
memcpy(d, chunks[i]->data, chunks[i]->length);
d += chunks[i]->length;
sofar += chunks[i]->length;
} else {
*error_msg = apr_psprintf(msr->mp, "Internal error, request body buffer overflow.");
return -1;
}
}
return 1;
}
/** /**
* Replace a bunch of chunks holding a request body with a single large chunk. * Replace a bunch of chunks holding a request body with a single large chunk.
*/ */
@ -498,13 +542,15 @@ apr_status_t modsecurity_request_body_end(modsec_rec *msr, char **error_msg) {
/* Note that we've read the body. */ /* Note that we've read the body. */
msr->msc_reqbody_read = 1; msr->msc_reqbody_read = 1;
if (msr->txcfg->stream_inbody_inspection)
modsecurity_request_body_to_stream(msr, error_msg);
/* Finalise body processing. */ /* Finalise body processing. */
if ((msr->msc_reqbody_processor != NULL) && (msr->msc_reqbody_error == 0)) { if ((msr->msc_reqbody_processor != NULL) && (msr->msc_reqbody_error == 0)) {
char *my_error_msg = NULL; char *my_error_msg = NULL;
msre_reqbody_processor_metadata *metadata = msre_reqbody_processor_metadata *metadata =
(msre_reqbody_processor_metadata *)apr_table_get(msr->modsecurity->msre->reqbody_processors, msr->msc_reqbody_processor); (msre_reqbody_processor_metadata *)apr_table_get(msr->modsecurity->msre->reqbody_processors, msr->msc_reqbody_processor);
if (metadata != NULL) { if (metadata != NULL) {
if ( (metadata->complete != NULL) if ( (metadata->complete != NULL)
&& (metadata->complete(msr, &my_error_msg) < 0)) && (metadata->complete(msr, &my_error_msg) < 0))

View File

@ -580,6 +580,8 @@ msre_actionset *msre_actionset_create(msre_engine *engine, const char *text,
actionset->phase = NOT_SET; actionset->phase = NOT_SET;
actionset->severity = -1; actionset->severity = -1;
actionset->rule = NOT_SET_P; actionset->rule = NOT_SET_P;
actionset->arg_max = -1;
actionset->arg_min = -1;
/* Flow */ /* Flow */
actionset->is_chained = NOT_SET; actionset->is_chained = NOT_SET;
@ -660,6 +662,8 @@ msre_actionset *msre_actionset_merge(msre_engine *engine, msre_actionset *parent
if (child->severity != NOT_SET) merged->severity = child->severity; if (child->severity != NOT_SET) merged->severity = child->severity;
if (child->phase != NOT_SET) merged->phase = child->phase; if (child->phase != NOT_SET) merged->phase = child->phase;
if (child->rule != NOT_SET_P) merged->rule = child->rule; if (child->rule != NOT_SET_P) merged->rule = child->rule;
if (child->arg_min != NOT_SET) merged->arg_min = child->arg_min;
if (child->arg_max != NOT_SET) merged->arg_max = child->arg_max;
/* Flow */ /* Flow */
merged->is_chained = child->is_chained; merged->is_chained = child->is_chained;
@ -714,6 +718,8 @@ void msre_actionset_set_defaults(msre_actionset *actionset) {
if (actionset->phase == NOT_SET) actionset->phase = 2; if (actionset->phase == NOT_SET) actionset->phase = 2;
if (actionset->severity == -1) {} /* leave at -1 */ if (actionset->severity == -1) {} /* leave at -1 */
if (actionset->rule == NOT_SET_P) actionset->rule = NULL; if (actionset->rule == NOT_SET_P) actionset->rule = NULL;
if (actionset->arg_max == NOT_SET) actionset->arg_max = -1;
if (actionset->arg_min == NOT_SET) actionset->arg_min = -1;
/* Flow */ /* Flow */
if (actionset->is_chained == NOT_SET) actionset->is_chained = 0; if (actionset->is_chained == NOT_SET) actionset->is_chained = 0;

View File

@ -16,6 +16,7 @@
* directly using the email address support@trustwave.com. * directly using the email address support@trustwave.com.
* *
*/ */
#ifndef _MSC_RE_H_ #ifndef _MSC_RE_H_
#define _MSC_RE_H_ #define _MSC_RE_H_
@ -174,6 +175,9 @@ struct msre_rule {
/* Compiled Lua script. */ /* Compiled Lua script. */
msc_script *script; msc_script *script;
#endif #endif
ap_regex_t *sub_regex;
char *sub_str;
}; };
char DSOLOCAL *msre_rule_generate_unparsed(apr_pool_t *pool, const msre_rule *rule, const char *targets, const char *args, const char *actions); char DSOLOCAL *msre_rule_generate_unparsed(apr_pool_t *pool, const msre_rule *rule, const char *targets, const char *args, const char *actions);
@ -284,6 +288,8 @@ struct msre_actionset {
int severity; int severity;
int phase; int phase;
msre_rule *rule; msre_rule *rule;
int arg_min;
int arg_max;
/* Flow */ /* Flow */
int is_chained; int is_chained;

View File

@ -18,6 +18,9 @@
*/ */
#include "re.h" #include "re.h"
#include <ctype.h> #include <ctype.h>
#include "apr_lib.h"
#include "apr_strmatch.h"
/** /**
* Register action with the engine. * Register action with the engine.
@ -344,7 +347,6 @@ apr_status_t collection_original_setvar(modsec_rec *msr, const char *col_name, c
msr_log(msr, 9, "Original collection variable: %s.%s = \"%s\"", col_name, var_name, msr_log(msr, 9, "Original collection variable: %s.%s = \"%s\"", col_name, var_name,
log_escape_ex(msr->mp, orig_var->value, orig_var->value_len)); log_escape_ex(msr->mp, orig_var->value, orig_var->value_len));
} }
return 1; return 1;
} }
} }
@ -406,6 +408,34 @@ static apr_status_t msre_action_logdata_init(msre_engine *engine, msre_actionset
return 1; return 1;
} }
/* SanitizeMatchedBytes init */
static apr_status_t msre_action_sanitizeMatchedBytes_init(msre_engine *engine,
msre_actionset *actionset, msre_action *action)
{
char *parse_parm = NULL;
char *ac_param = NULL;
char *savedptr = NULL;
int arg_min = 0;
int arg_max = 0;
if (action->param != NULL && strlen(action->param) == 3) {
ac_param = apr_pstrdup(engine->mp, action->param);
parse_parm = apr_strtok(ac_param,"/",&savedptr);
if(apr_isdigit(*parse_parm) && apr_isdigit(*savedptr)) {
arg_max = atoi(parse_parm);
arg_min = atoi(savedptr);
}
}
actionset->arg_min = arg_min;
actionset->arg_max = arg_max;
return 1;
}
/* severity */ /* severity */
static apr_status_t msre_action_severity_init(msre_engine *engine, static apr_status_t msre_action_severity_init(msre_engine *engine,
@ -1053,7 +1083,9 @@ static apr_status_t msre_action_sanitizeMatched_execute(modsec_rec *msr, apr_poo
const char *sargname = NULL; const char *sargname = NULL;
const apr_array_header_t *tarr; const apr_array_header_t *tarr;
const apr_table_entry_t *telts; const apr_table_entry_t *telts;
int i, type = 0; const apr_array_header_t *tarr_pattern;
const apr_table_entry_t *telts_pattern;
int i, type = 0, k;
msc_string *mvar = msr->matched_var; msc_string *mvar = msr->matched_var;
if (mvar->name_len == 0) return 0; if (mvar->name_len == 0) return 0;
@ -1090,7 +1122,6 @@ static apr_status_t msre_action_sanitizeMatched_execute(modsec_rec *msr, apr_poo
msr_log(msr, 3, "sanitizeMatched: Don't know how to handle variable: %s", msr_log(msr, 3, "sanitizeMatched: Don't know how to handle variable: %s",
mvar->name); mvar->name);
} }
return 0; return 0;
} }
@ -2294,6 +2325,19 @@ void msre_engine_register_default_actions(msre_engine *engine) {
msre_action_sanitizeArg_execute msre_action_sanitizeArg_execute
); );
/* sanitiseMatchedBytes */
msre_engine_action_register(engine,
"sanitizeMatchedBytes",
ACTION_NON_DISRUPTIVE,
0, 1,
NO_PLUS_MINUS,
ACTION_CARDINALITY_MANY,
ACTION_CGROUP_NONE,
NULL,
msre_action_sanitizeMatchedBytes_init,
msre_action_sanitizeMatched_execute
);
/* sanitizeArg */ /* sanitizeArg */
msre_engine_action_register(engine, msre_engine_action_register(engine,
"sanitizeArg", "sanitizeArg",

View File

@ -22,6 +22,7 @@
#include "apr_lib.h" #include "apr_lib.h"
#include "apr_strmatch.h" #include "apr_strmatch.h"
#include "acmp.h" #include "acmp.h"
#include <regex.h>
/** /**
* *
@ -72,6 +73,162 @@ static int msre_op_nomatch_execute(modsec_rec *msr, msre_rule *rule,
return 0; return 0;
} }
/* rsub */
static int msre_op_rsub_param_init(msre_rule *rule, char **error_msg) {
const char *errptr = NULL;
int erroffset;
ap_regex_t *regex;
const char *pattern = NULL;
const char *line = NULL;
char *reg_pattern = NULL;
char *replace = NULL;
char *flags = NULL;
char *data;
char delim;
int ignore_case = 0;
line = rule->op_param;
if (apr_tolower(*line) != 's') {
*error_msg = apr_psprintf(rule->ruleset->mp, "Error rsub operator format, must be s/// pattern",
erroffset, errptr);
return 0;
}
data = apr_pstrdup(rule->ruleset->mp, line);
delim = *++data;
if (delim)
reg_pattern = ++data;
if (reg_pattern) {
if (*data != delim) {
while (*++data && *data != delim);
}
if (*data) {
*data = '\0';
replace = ++data;
}
}
if (replace) {
if (*data != delim) {
while (*++data && *data != delim);
}
if (*data) {
*data = '\0';
flags = ++data;
}
}
if (!delim || !reg_pattern || !*reg_pattern || !replace) {
*error_msg = apr_psprintf(rule->ruleset->mp, "Error rsub operator format - must be s/regex/str/[flags]",
erroffset, errptr);
return 0;
}
if (flags) {
while (*flags) {
delim = apr_tolower(*flags);
if (delim == 'i')
ignore_case = 1;
else
*error_msg = apr_psprintf(rule->ruleset->mp, "Regex flag not supported",
erroffset, errptr);
flags++;
}
}
if (error_msg == NULL) return -1;
*error_msg = NULL;
pattern = apr_pstrdup(rule->ruleset->mp, reg_pattern);
rule->sub_str = apr_pstrdup(rule->ruleset->mp, replace);
regex = ap_pregcomp(rule->ruleset->mp, pattern, AP_REG_EXTENDED |
(ignore_case ? AP_REG_ICASE : 0));
rule->sub_regex = regex;
return 1; /* OK */
}
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;
char *offset = NULL;
int sub = 0, so = 0, p_len = 0;
char *replace = NULL;
char *data = NULL;
int size = var->value_len;
int output_body = 0, input_body = 0, count = 0;
ap_regmatch_t pmatch[AP_MAX_REG_MATCH];
if(strcmp(var->name,"STREAM_OUTPUT_BODY") == 0 ) {
output_body = 1;
} else if(strcmp(var->name,"STREAM_INPUT_BODY") == 0 ) {
input_body = 1;
} else {
msr_log(msr,9,"Operator rsub only works with STREAM_* variables");
return -1;
}
replace = apr_pstrdup(rule->ruleset->mp, rule->sub_str);;
data = apr_pcalloc(msr->mp, var->value_len+(AP_MAX_REG_MATCH*strlen(replace))+1);
if(replace == NULL || data == NULL)
return 0;
memcpy(data,var->value,var->value_len);
size += (AP_MAX_REG_MATCH*strlen(replace)+2);
if (ap_regexec(rule->sub_regex, data ,AP_MAX_REG_MATCH, pmatch, 0)) return 0;
for (offset = replace; *offset; offset++)
if (*offset == '\\' && *(offset + 1) > '0' && *(offset + 1) <= '9') {
so = pmatch [*(offset + 1) - 48].rm_so;
p_len = pmatch [*(offset + 1) - 48].rm_eo - so;
if (so < 0 || strlen (replace) + p_len - 1 > size) return 0;
memmove (offset + p_len, offset + 2, strlen (offset) - 1);
memmove (offset, data + so, p_len);
offset = offset + p_len - 2;
}
sub = pmatch [1].rm_so;
for (offset = data; !ap_regexec(rule->sub_regex, offset, 1, pmatch, 0); ) {
p_len = pmatch [0].rm_eo - pmatch [0].rm_so;
count++;
offset += pmatch [0].rm_so;
if (var->value_len - p_len + strlen(replace) + 1 > size) return 0;
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)));
if(msr->stream_output_data != NULL && output_body == 1) {
msr->stream_output_data = (char *)realloc(msr->stream_output_data,size);
msr->stream_output_length = size;
if (msr->stream_output_data != NULL) {
memset(msr->stream_output_data,0,size);
memcpy(msr->stream_output_data,data,size);
msr->stream_output_data[msr->stream_output_length] = '\0';
}
}
if(msr->stream_input_data != NULL && input_body == 1) {
msr->stream_input_data = (char *)realloc(msr->stream_input_data,size);
msr->stream_input_length = size;
if (msr->stream_input_data != NULL) {
memset(msr->stream_input_data,0,size);
memcpy(msr->stream_input_data,data,size);
msr->stream_input_data[msr->stream_input_length] = '\0';
}
}
return 1;
}
/* rx */ /* rx */
static int msre_op_rx_param_init(msre_rule *rule, char **error_msg) { static int msre_op_rx_param_init(msre_rule *rule, char **error_msg) {
@ -103,7 +260,12 @@ static int msre_op_rx_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, c
char *my_error_msg = NULL; char *my_error_msg = NULL;
int ovector[33]; int ovector[33];
int capture = 0; int capture = 0;
int matched_bytes = 0;
int matched = 0;
int rc; int rc;
char *qspos = NULL;
const char *parm = NULL;
msc_parm *mparm = NULL;
if (error_msg == NULL) return -1; if (error_msg == NULL) return -1;
*error_msg = NULL; *error_msg = NULL;
@ -127,6 +289,8 @@ static int msre_op_rx_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, c
/* Are we supposed to capture subexpressions? */ /* Are we supposed to capture subexpressions? */
capture = apr_table_get(rule->actionset->actions, "capture") ? 1 : 0; capture = apr_table_get(rule->actionset->actions, "capture") ? 1 : 0;
matched_bytes = apr_table_get(rule->actionset->actions, "sanitizeMatchedBytes") ? 1 : 0;
matched = apr_table_get(rule->actionset->actions, "sanitizeMatched") ? 1 : 0;
/* Show when the regex captures but "capture" is not set */ /* Show when the regex captures but "capture" is not set */
if (msr->txcfg->debuglog_level >= 6) { if (msr->txcfg->debuglog_level >= 6) {
@ -192,16 +356,39 @@ static int msre_op_rx_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, c
for(i = 0; i < rc; i++) { for(i = 0; i < rc; i++) {
msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
if (s == NULL) return -1; if (s == NULL) return -1;
s->name = apr_psprintf(msr->mp, "%d", i); s->name = apr_psprintf(msr->mp, "%d", i);
s->name_len = strlen(s->name); s->name_len = strlen(s->name);
s->value = apr_pstrmemdup(msr->mp, s->value = apr_pstrmemdup(msr->mp,
target + ovector[2 * i], ovector[2 * i + 1] - ovector[2 * i]); target + ovector[2 * i], ovector[2 * i + 1] - ovector[2 * i]);
s->value_len = (ovector[2 * i + 1] - ovector[2 * i]); s->value_len = (ovector[2 * i + 1] - ovector[2 * i]);
if ((s->name == NULL)||(s->value == NULL)) return -1; if ((s->name == NULL)||(s->value == NULL)) return -1;
apr_table_addn(msr->tx_vars, s->name, (void *)s); apr_table_addn(msr->tx_vars, s->name, (void *)s);
if(((matched == 1) || (matched_bytes == 1)) && (var != NULL) && (var->name != NULL)) {
qspos = apr_psprintf(msr->mp, "%s", var->name);
parm = strstr(qspos, ":");
if (parm != NULL) {
parm++;
mparm = apr_palloc(msr->mp, sizeof(msc_parm));
if (mparm == NULL)
continue;
mparm->value = apr_pstrmemdup(msr->mp,s->value,s->value_len);
mparm->pad_1 = rule->actionset->arg_min;
mparm->pad_2 = rule->actionset->arg_max;
apr_table_addn(msr->pattern_to_sanitize, parm, (void *)mparm);
} else {
mparm = apr_palloc(msr->mp, sizeof(msc_parm));
if (mparm == NULL)
continue;
mparm->value = apr_pstrmemdup(msr->mp,s->value,s->value_len);
apr_table_addn(msr->pattern_to_sanitize, qspos, (void *)mparm);
}
}
if (msr->txcfg->debuglog_level >= 9) { if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "Added regex subexpression to TX.%d: %s", i, msr_log(msr, 9, "Added regex subexpression to TX.%d: %s", i,
log_escape_nq_ex(msr->mp, s->value, s->value_len)); log_escape_nq_ex(msr->mp, s->value, s->value_len));
@ -2290,6 +2477,13 @@ void msre_engine_register_default_operators(msre_engine *engine) {
msre_op_nomatch_execute msre_op_nomatch_execute
); );
/* rsub */
msre_engine_op_register(engine,
"rsub",
msre_op_rsub_param_init,
msre_op_rsub_execute
);
/* rx */ /* rx */
msre_engine_op_register(engine, msre_engine_op_register(engine,
"rx", "rx",

View File

@ -2149,6 +2149,32 @@ static int var_path_info_generate(modsec_rec *msr, msre_var *var, msre_rule *rul
return var_simple_generate(var, vartab, mptmp, value); return var_simple_generate(var, vartab, mptmp, value);
} }
/* STREAM_OUTPUT_BODY */
static int var_stream_output_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
apr_table_t *vartab, apr_pool_t *mptmp)
{
if (msr->stream_output_data != NULL) {
return var_simple_generate_ex(var, vartab, mptmp,
msr->stream_output_data, msr->stream_output_length);
}
return 0;
}
/* STREAM_INPUT_BODY */
static int var_stream_input_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
apr_table_t *vartab, apr_pool_t *mptmp)
{
if (msr->stream_input_data != NULL) {
return var_simple_generate_ex(var, vartab, mptmp,
msr->stream_input_data, msr->stream_input_length);
}
return 0;
}
/* RESPONSE_BODY */ /* RESPONSE_BODY */
static int var_response_body_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, static int var_response_body_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
@ -3012,6 +3038,29 @@ void msre_engine_register_default_variables(msre_engine *engine) {
PHASE_REQUEST_HEADERS PHASE_REQUEST_HEADERS
); );
/* STREAM_OUTPUT_BODY */
msre_engine_variable_register(engine,
"STREAM_OUTPUT_BODY",
VAR_SIMPLE,
0, 0,
NULL,
var_stream_output_generate,
VAR_CACHE,
PHASE_RESPONSE_BODY
);
/* STREAM_INPUT_BODY */
msre_engine_variable_register(engine,
"STREAM_INPUT_BODY",
VAR_SIMPLE,
0, 0,
NULL,
var_stream_input_generate,
VAR_CACHE,
PHASE_FIRST
);
/* RESPONSE_BODY */ /* RESPONSE_BODY */
msre_engine_variable_register(engine, msre_engine_variable_register(engine,
"RESPONSE_BODY", "RESPONSE_BODY",