MODSEC-178

This commit is contained in:
brenosilva 2011-03-28 18:47:58 +00:00
parent a5ddb8189c
commit 1a2d377e34
5 changed files with 220 additions and 90 deletions

View File

@ -167,18 +167,40 @@ static void copy_rules_phase(apr_pool_t *mp,
char *my_error_msg = NULL;
int rc = msc_regexec(exceptions[j]->param_data,
rule->actionset->msg, strlen(rule->actionset->msg),
&my_error_msg);
rule->actionset->msg, strlen(rule->actionset->msg),
&my_error_msg);
if (rc >= 0) copy--;
}
break;
case RULE_EXCEPTION_REMOVE_TAG :
if ((rule->actionset != NULL)&&(apr_is_empty_table(rule->actionset->actions) == 0)) {
char *my_error_msg = NULL;
const apr_array_header_t *tarr = NULL;
const apr_table_entry_t *telts = NULL;
int i;
tarr = apr_table_elts(rule->actionset->actions);
telts = (const apr_table_entry_t*)tarr->elts;
for (i = 0; i < tarr->nelts; i++) {
msre_action *action = (msre_action *)telts[i].val;
if(strcmp("tag", action->metadata->name) == 0) {
int rc = msc_regexec(exceptions[j]->param_data,
action->param, strlen(action->param),
&my_error_msg);
if (rc >= 0) copy--;
}
}
}
break;
}
}
if (copy > 0) {
#ifdef DEBUG_CONF
#ifdef DEBUG_CONF
ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Copy rule %pp [id \"%s\"]", rule, rule->actionset->id);
#endif
#endif
/* Copy the rule. */
*(msre_rule **)apr_array_push(child_phase_arr) = rule;
@ -188,9 +210,9 @@ static void copy_rules_phase(apr_pool_t *mp,
}
} else {
if (mode == 2) {
#ifdef DEBUG_CONF
#ifdef DEBUG_CONF
ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Copy chain %pp for rule %pp [id \"%s\"]", rule, rule->chain_starter, rule->chain_starter->actionset->id);
#endif
#endif
/* Copy the rule (it belongs to the chain we want to include. */
*(msre_rule **)apr_array_push(child_phase_arr) = rule;
@ -1859,6 +1881,31 @@ static const char *cmd_rule_remove_by_id(cmd_parms *cmd, void *_dcfg,
return NULL;
}
static const char *cmd_rule_remove_by_tag(cmd_parms *cmd, void *_dcfg,
const char *p1)
{
directory_config *dcfg = (directory_config *)_dcfg;
rule_exception *re = apr_pcalloc(cmd->pool, sizeof(rule_exception));
if (dcfg == NULL) return NULL;
re->type = RULE_EXCEPTION_REMOVE_TAG;
re->param = p1;
re->param_data = msc_pregcomp(cmd->pool, p1, 0, NULL, NULL);
if (re->param_data == NULL) {
return apr_psprintf(cmd->pool, "ModSecurity: Invalid regular expression: %s", p1);
}
*(rule_exception **)apr_array_push(dcfg->rule_exceptions) = re;
/* Remove the corresponding rules from the context straight away. */
msre_ruleset_rule_remove_with_exception(dcfg->ruleset, re);
#ifdef DEBUG_CONF
ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, "Added exception %pp (%d %s) to dcfg %pp.", re, re->type, re->param, dcfg);
#endif
return NULL;
}
static const char *cmd_rule_remove_by_msg(cmd_parms *cmd, void *_dcfg,
const char *p1)
{
@ -2559,6 +2606,14 @@ const command_rec module_directives[] = {
"rule ID for removal"
),
AP_INIT_ITERATE (
"SecRuleRemoveByTag",
cmd_rule_remove_by_tag,
NULL,
CMD_SCOPE_ANY,
"rule tag for removal"
),
AP_INIT_ITERATE (
"SecRuleRemoveByMsg",
cmd_rule_remove_by_msg,

View File

@ -419,6 +419,9 @@ apr_status_t modsecurity_tx_init(modsec_rec *msr) {
msr->removed_rules = apr_array_make(msr->mp, 16, sizeof(char *));
if (msr->removed_rules == NULL) return -1;
msr->removed_rules_tag = apr_array_make(msr->mp, 16, sizeof(char *));
if (msr->removed_rules_tag == NULL) return -1;
return 1;
}

View File

@ -187,6 +187,7 @@ extern DSOLOCAL unsigned long int conn_read_state_limit;
#define RULE_EXCEPTION_IMPORT_MSG 2
#define RULE_EXCEPTION_REMOVE_ID 3
#define RULE_EXCEPTION_REMOVE_MSG 4
#define RULE_EXCEPTION_REMOVE_TAG 5
#define NBSP 160
@ -378,6 +379,7 @@ struct modsec_rec {
/* removed rules */
apr_array_header_t *removed_rules;
apr_array_header_t *removed_rules_tag;
/* When "allow" is executed the variable below is
* updated to contain the scope of the allow action. Set

View File

@ -929,9 +929,9 @@ apr_status_t msre_ruleset_process_phase(msre_ruleset *ruleset, modsec_rec *msr)
rules = (msre_rule **)arr->elts;
for (i = 0; i < arr->nelts; i++) {
msre_rule *rule = rules[i];
#if defined(PERFORMANCE_MEASUREMENT)
#if defined(PERFORMANCE_MEASUREMENT)
apr_time_t time1 = 0;
#endif
#endif
/* Reset the rule interception flag */
msr->rule_was_intercepted = 0;
@ -1025,13 +1025,17 @@ apr_status_t msre_ruleset_process_phase(msre_ruleset *ruleset, modsec_rec *msr)
}
/* Check if this rule was removed at runtime */
if ((rule->actionset->id !=NULL) && (! apr_is_empty_array(msr->removed_rules))) {
int j;
int do_process = 1;
const char *range;
if (((rule->actionset->id !=NULL) && !apr_is_empty_array(msr->removed_rules)) || (apr_is_empty_array(msr->removed_rules_tag)==0)) {
int j, act;
int do_process = 1;
const char *range;
const apr_array_header_t *tag_tarr = NULL;
const apr_table_entry_t *tag_telts = NULL;
for(j = 0; j < msr->removed_rules->nelts; j++) {
range = ((const char**)msr->removed_rules->elts)[j];
for(j = 0; j < msr->removed_rules->nelts; j++) {
range = ((const char**)msr->removed_rules->elts)[j];
if(rule->actionset->id !=NULL) {
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "Checking removal of rule id=\"%s\" against: %s", rule->actionset->id, range);
@ -1042,25 +1046,53 @@ apr_status_t msre_ruleset_process_phase(msre_ruleset *ruleset, modsec_rec *msr)
break;
}
}
}
/* Go to the next rule if this one has been removed. */
if (do_process == 0) {
if (msr->txcfg->debuglog_level >= 5) {
msr_log(msr, 5, "Not processing %srule id=\"%s\": "
"removed by ctl action",
rule->actionset->is_chained ? "chained " : "",
rule->actionset->id);
tag_tarr = apr_table_elts(rule->actionset->actions);
tag_telts = (const apr_table_entry_t*)tag_tarr->elts;
for (act = 0; act < tag_tarr->nelts; act++) {
msre_action *action = (msre_action *)tag_telts[act].val;
if((action != NULL) && (action->metadata != NULL ) && strcmp("tag", action->metadata->name) == 0) {
for(j = 0; j < msr->removed_rules_tag->nelts; j++) {
range = ((const char**)msr->removed_rules_tag->elts)[j];
if(action->param != NULL) {
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "Checking removal of rule tag=\"%s\" against: %s", (char *)action->param, range);
}
if (strncasecmp(action->param, range, strlen(range)) == 0) {
do_process = 0;
break;
}
}
}
/* Skip the whole chain, if this is a chained rule */
if (rule->actionset->is_chained) {
mode = NEXT_CHAIN;
}
skipped = 0;
saw_starter = 0;
continue;
}
}
/* Go to the next rule if this one has been removed. */
if (do_process == 0) {
if (msr->txcfg->debuglog_level >= 5) {
msr_log(msr, 5, "Not processing %srule id=\"%s\": "
"removed by ctl action",
rule->actionset->is_chained ? "chained " : "",
rule->actionset->id);
}
/* Skip the whole chain, if this is a chained rule */
if (rule->actionset->is_chained) {
mode = NEXT_CHAIN;
}
skipped = 0;
saw_starter = 0;
continue;
}
}
if (msr->txcfg->debuglog_level >= 4) {
@ -1086,15 +1118,15 @@ apr_status_t msre_ruleset_process_phase(msre_ruleset *ruleset, modsec_rec *msr)
msr_log(msr, 5, "Rule %pp: %s", rule, rule->unparsed);
}
#if defined(PERFORMANCE_MEASUREMENT)
#if defined(PERFORMANCE_MEASUREMENT)
time1 = apr_time_now();
#endif
#endif
rc = msre_rule_process(rule, msr);
#if defined(PERFORMANCE_MEASUREMENT)
#if defined(PERFORMANCE_MEASUREMENT)
rule->execution_time += (apr_time_now() - time1);
#endif
#endif
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "Rule returned %d.", rc);
@ -1310,7 +1342,7 @@ int msre_ruleset_rule_add(msre_ruleset *ruleset, msre_rule *rule, int phase) {
}
static msre_rule * msre_ruleset_fetch_phase_rule(const msre_ruleset *ruleset, const char *id,
const apr_array_header_t *phase_arr)
const apr_array_header_t *phase_arr)
{
msre_rule **rules = (msre_rule **)phase_arr->elts;
int i;
@ -1320,9 +1352,9 @@ static msre_rule * msre_ruleset_fetch_phase_rule(const msre_ruleset *ruleset, co
/* Rule with an action, not a sub-rule (chain) and a matching id */
if ( (rule->actionset != NULL)
&& (!rule->actionset->is_chained || !rule->chain_starter)
&& (rule->actionset->id != NULL)
&& (strcmp(rule->actionset->id, id) == 0))
&& (!rule->actionset->is_chained || !rule->chain_starter)
&& (rule->actionset->id != NULL)
&& (strcmp(rule->actionset->id, id) == 0))
{
/* Return rule that matched unless it is a placeholder */
return (rule->placeholder == RULE_PH_NONE) ? rule : NULL;
@ -1358,7 +1390,7 @@ msre_rule * msre_ruleset_fetch_rule(msre_ruleset *ruleset, const char *id) {
}
static int msre_ruleset_phase_rule_remove_with_exception(msre_ruleset *ruleset, rule_exception *re,
apr_array_header_t *phase_arr)
apr_array_header_t *phase_arr)
{
msre_rule **rules;
int i, j, mode, removed_count;
@ -1392,13 +1424,38 @@ static int msre_ruleset_phase_rule_remove_with_exception(msre_ruleset *ruleset,
char *my_error_msg = NULL;
int rc = msc_regexec(re->param_data,
rule->actionset->msg, strlen(rule->actionset->msg),
&my_error_msg);
rule->actionset->msg, strlen(rule->actionset->msg),
&my_error_msg);
if (rc >= 0) {
remove_rule = 1;
}
}
break;
case RULE_EXCEPTION_REMOVE_TAG :
if ((rule->actionset != NULL)&&(apr_is_empty_table(rule->actionset->actions) == 0)) {
char *my_error_msg = NULL;
const apr_array_header_t *tarr = NULL;
const apr_table_entry_t *telts = NULL;
int act;
tarr = apr_table_elts(rule->actionset->actions);
telts = (const apr_table_entry_t*)tarr->elts;
for (act = 0; act < tarr->nelts; act++) {
msre_action *action = (msre_action *)telts[act].val;
if((action != NULL) && (action->metadata != NULL) && (strcmp("tag", action->metadata->name) == 0)) {
int rc = msc_regexec(re->param_data,
action->param, strlen(action->param),
&my_error_msg);
if (rc >= 0) {
remove_rule = 1;
}
}
}
}
break;
}
}
@ -1480,15 +1537,15 @@ char *msre_format_metadata(modsec_rec *msr, msre_actionset *actionset) {
if ((actionset->rule != NULL) && (actionset->rule->filename != NULL)) {
fn = apr_psprintf(msr->mp, " [file \"%s\"] [line \"%d\"]",
actionset->rule->filename, actionset->rule->line_num);
actionset->rule->filename, actionset->rule->line_num);
}
if (actionset->id != NULL) {
id = apr_psprintf(msr->mp, " [id \"%s\"]",
log_escape(msr->mp, actionset->id));
log_escape(msr->mp, actionset->id));
}
if (actionset->rev != NULL) {
rev = apr_psprintf(msr->mp, " [rev \"%s\"]",
log_escape(msr->mp, actionset->rev));
log_escape(msr->mp, actionset->rev));
}
if (actionset->msg != NULL) {
/* Expand variables in the message string. */
@ -1498,7 +1555,7 @@ char *msre_format_metadata(modsec_rec *msr, msre_actionset *actionset) {
expand_macros(msr, var, NULL, msr->mp);
msg = apr_psprintf(msr->mp, " [msg \"%s\"]",
log_escape_ex(msr->mp, var->value, var->value_len));
log_escape_ex(msr->mp, var->value, var->value_len));
}
if (actionset->logdata != NULL) {
/* Expand variables in the message string. */
@ -1508,7 +1565,7 @@ char *msre_format_metadata(modsec_rec *msr, msre_actionset *actionset) {
expand_macros(msr, var, NULL, msr->mp);
logdata = apr_psprintf(msr->mp, " [data \"%s\"]",
log_escape_hex(msr->mp, (unsigned char *)var->value, var->value_len));
log_escape_hex(msr->mp, (unsigned char *)var->value, var->value_len));
/* If it is > 512 bytes, then truncate at 512 with ellipsis.
* NOTE: 512 actual data + 9 bytes of label = 521
@ -1524,7 +1581,7 @@ char *msre_format_metadata(modsec_rec *msr, msre_actionset *actionset) {
}
if ((actionset->severity >= 0)&&(actionset->severity <= 7)) {
severity = apr_psprintf(msr->mp, " [severity \"%s\"]",
msre_format_severity(actionset->severity));
msre_format_severity(actionset->severity));
}
/* Extract rule tags from the action list. */
@ -1535,7 +1592,7 @@ char *msre_format_metadata(modsec_rec *msr, msre_actionset *actionset) {
msre_action *action = (msre_action *)telts[k].val;
if (strcmp(telts[k].key, "tag") == 0) {
tags = apr_psprintf(msr->mp, "%s [tag \"%s\"]", tags,
log_escape(msr->mp, action->param));
log_escape(msr->mp, action->param));
}
}
@ -1543,7 +1600,7 @@ char *msre_format_metadata(modsec_rec *msr, msre_actionset *actionset) {
}
char * msre_rule_generate_unparsed(apr_pool_t *pool, const msre_rule *rule, const char *targets,
const char *args, const char *actions)
const char *args, const char *actions)
{
char *unparsed = NULL;
const char *r_targets = targets;
@ -1561,36 +1618,36 @@ char * msre_rule_generate_unparsed(apr_pool_t *pool, const msre_rule *rule, con
}
switch (rule->type) {
case RULE_TYPE_NORMAL:
if (r_actions == NULL) {
unparsed = apr_psprintf(pool, "SecRule \"%s\" \"%s\"",
log_escape(pool, r_targets), log_escape(pool, r_args));
}
else {
unparsed = apr_psprintf(pool, "SecRule \"%s\" \"%s\" \"%s\"",
log_escape(pool, r_targets), log_escape(pool, r_args),
log_escape(pool, r_actions));
}
break;
case RULE_TYPE_ACTION:
unparsed = apr_psprintf(pool, "SecAction \"%s\"",
log_escape(pool, r_actions));
break;
case RULE_TYPE_MARKER:
unparsed = apr_psprintf(pool, "SecMarker \"%s\"", rule->actionset->id);
break;
#if defined(WITH_LUA)
case RULE_TYPE_LUA:
/* SecRuleScript */
if (r_actions == NULL) {
unparsed = apr_psprintf(pool, "SecRuleScript \"%s\"", r_args);
}
else {
unparsed = apr_psprintf(pool, "SecRuleScript \"%s\" \"%s\"",
r_args, log_escape(pool, r_actions));
}
break;
#endif
case RULE_TYPE_NORMAL:
if (r_actions == NULL) {
unparsed = apr_psprintf(pool, "SecRule \"%s\" \"%s\"",
log_escape(pool, r_targets), log_escape(pool, r_args));
}
else {
unparsed = apr_psprintf(pool, "SecRule \"%s\" \"%s\" \"%s\"",
log_escape(pool, r_targets), log_escape(pool, r_args),
log_escape(pool, r_actions));
}
break;
case RULE_TYPE_ACTION:
unparsed = apr_psprintf(pool, "SecAction \"%s\"",
log_escape(pool, r_actions));
break;
case RULE_TYPE_MARKER:
unparsed = apr_psprintf(pool, "SecMarker \"%s\"", rule->actionset->id);
break;
#if defined(WITH_LUA)
case RULE_TYPE_LUA:
/* SecRuleScript */
if (r_actions == NULL) {
unparsed = apr_psprintf(pool, "SecRuleScript \"%s\"", r_args);
}
else {
unparsed = apr_psprintf(pool, "SecRuleScript \"%s\" \"%s\"",
r_args, log_escape(pool, r_actions));
}
break;
#endif
}
return unparsed;
@ -1601,8 +1658,8 @@ char * msre_rule_generate_unparsed(apr_pool_t *pool, const msre_rule *rule, con
* of targets (variables), arguments, and actions.
*/
msre_rule *msre_rule_create(msre_ruleset *ruleset, int type,
const char *fn, int line, const char *targets,
const char *args, const char *actions, char **error_msg)
const char *fn, int line, const char *targets,
const char *args, const char *actions, char **error_msg)
{
msre_rule *rule;
char *my_error_msg;
@ -1657,7 +1714,7 @@ msre_rule *msre_rule_create(msre_ruleset *ruleset, int type,
rule->op_metadata = msre_engine_op_resolve(ruleset->engine, rule->op_name);
if (rule->op_metadata == NULL) {
*error_msg = apr_psprintf(ruleset->mp,
"Error creating rule: Failed to resolve operator: %s", rule->op_name);
"Error creating rule: Failed to resolve operator: %s", rule->op_name);
return NULL;
}
@ -1690,8 +1747,8 @@ msre_rule *msre_rule_create(msre_ruleset *ruleset, int type,
*
*/
msre_rule *msre_rule_lua_create(msre_ruleset *ruleset,
const char *fn, int line, const char *script_filename,
const char *actions, char **error_msg)
const char *fn, int line, const char *script_filename,
const char *actions, char **error_msg)
{
msre_rule *rule;
char *my_error_msg;
@ -1734,7 +1791,7 @@ msre_rule *msre_rule_lua_create(msre_ruleset *ruleset,
* Perform non-disruptive actions associated with the provided actionset.
*/
static void msre_perform_nondisruptive_actions(modsec_rec *msr, msre_rule *rule,
msre_actionset *actionset, apr_pool_t *mptmp)
msre_actionset *actionset, apr_pool_t *mptmp)
{
const apr_array_header_t *tarr;
const apr_table_entry_t *telts;
@ -1756,7 +1813,7 @@ static void msre_perform_nondisruptive_actions(modsec_rec *msr, msre_rule *rule,
* Perform the disruptive actions associated with the given actionset.
*/
static void msre_perform_disruptive_actions(modsec_rec *msr, msre_rule *rule,
msre_actionset *actionset, apr_pool_t *mptmp, const char *message)
msre_actionset *actionset, apr_pool_t *mptmp, const char *message)
{
const apr_array_header_t *tarr;
const apr_table_entry_t *telts;
@ -1787,9 +1844,9 @@ static void msre_perform_disruptive_actions(modsec_rec *msr, msre_rule *rule,
* cases we only emit warnings.
*/
if ((msr->phase == PHASE_LOGGING)
|| (msr->txcfg->is_enabled == MODSEC_DETECTION_ONLY)
|| (msr->modsecurity->processing_mode == MODSEC_OFFLINE)
|| (actionset->intercept_action == ACTION_NONE))
|| (msr->txcfg->is_enabled == MODSEC_DETECTION_ONLY)
|| (msr->modsecurity->processing_mode == MODSEC_OFFLINE)
|| (actionset->intercept_action == ACTION_NONE))
{
int log_level;

View File

@ -764,6 +764,10 @@ static char *msre_action_ctl_validate(msre_engine *engine, msre_action *action)
/* ENH nothing yet */
return NULL;
} else
if (strcasecmp(name, "ruleRemoveByTag") == 0) {
/* ENH nothing yet */
return NULL;
} else
if (strcasecmp(name, "requestBodyAccess") == 0) {
if (parse_boolean(value) == -1) {
return apr_psprintf(engine->mp, "Invalid setting for ctl name "
@ -906,7 +910,16 @@ static apr_status_t msre_action_ctl_execute(modsec_rec *msr, apr_pool_t *mptmp,
*(const char **)apr_array_push(msr->removed_rules) = (const char *)apr_pstrdup(msr->mp, value);
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "Ctl: Removed rule %s.", value);
msr_log(msr, 4, "Ctl: Removed rule by id : %s.", value);
}
return 1;
} else
if (strcasecmp(name, "ruleRemoveByTag") == 0) {
*(const char **)apr_array_push(msr->removed_rules_tag) = (const char *)apr_pstrdup(msr->mp, value);
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "Ctl: Removed rule by tag : %s.", value);
}
return 1;