mirror of
https://github.com/owasp-modsecurity/ModSecurity.git
synced 2025-08-14 05:45:59 +03:00
Adds fuzzyHash operator
The fuzzyHash operator can be used to match files. In conjuntcion with FILES_TMP_CONTENT collection it can scan uploaded files and try to match it with a pre caculated list of know malicious content, more details on how it works can be found on ssdeep website: http://ssdeep.sourceforge.net/
This commit is contained in:
parent
873c628b1a
commit
96865a92d3
@ -2453,6 +2453,32 @@ not_enough_memory:
|
||||
return headers_length;
|
||||
}
|
||||
|
||||
int read_line(char *buf, int len, FILE *fp)
|
||||
{
|
||||
char *tmp;
|
||||
|
||||
if (buf == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(buf, '\0', len*sizeof(char));
|
||||
|
||||
if (fgets(buf, len, fp) == NULL)
|
||||
{
|
||||
*buf = '\0';
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((tmp = strrchr(buf, '\n')) != NULL)
|
||||
{
|
||||
*tmp = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int create_radix_tree(apr_pool_t *mp, TreeRoot **rtree, char **error_msg)
|
||||
{
|
||||
|
@ -159,4 +159,6 @@ int DSOLOCAL tree_contains_ip(apr_pool_t *mp, TreeRoot *rtree,
|
||||
int DSOLOCAL ip_tree_from_param(apr_pool_t *pool,
|
||||
char *param, TreeRoot **rtree, char **error_msg);
|
||||
|
||||
int read_line(char *buff, int size, FILE *fp);
|
||||
|
||||
#endif
|
||||
|
@ -409,4 +409,9 @@ struct msre_cache_rec {
|
||||
apr_size_t val_len;
|
||||
};
|
||||
|
||||
struct fuzzy_hash_param_data {
|
||||
const char *file;
|
||||
int threshold;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -27,6 +27,10 @@
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#ifdef WITH_SSDEEP
|
||||
#include "fuzzy.h"
|
||||
#endif
|
||||
|
||||
#include "libinjection/libinjection.h"
|
||||
|
||||
/**
|
||||
@ -3718,6 +3722,142 @@ static int msre_op_rbl_execute(modsec_rec *msr, msre_rule *rule, msre_var *var,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* fuzzyHash */
|
||||
static int msre_op_fuzzy_hash_init(msre_rule *rule, char **error_msg)
|
||||
{
|
||||
#ifdef WITH_SSDEEP
|
||||
struct fuzzy_hash_param_data *param_data;
|
||||
char *file;
|
||||
int param_len,threshold;
|
||||
|
||||
char *data = NULL;
|
||||
char *threshold_str = NULL;
|
||||
|
||||
param_data = apr_palloc(rule->ruleset->mp,
|
||||
sizeof(struct fuzzy_hash_param_data));
|
||||
|
||||
data = apr_pstrdup(rule->ruleset->mp, rule->op_param);
|
||||
threshold_str = data;
|
||||
#endif
|
||||
|
||||
if (error_msg == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
*error_msg = NULL;
|
||||
|
||||
#ifdef WITH_SSDEEP
|
||||
/* Sanity check */
|
||||
param_len = strlen(threshold_str);
|
||||
threshold_str = threshold_str + param_len;
|
||||
|
||||
if (param_len < 3)
|
||||
{
|
||||
goto invalid_parameters;
|
||||
}
|
||||
|
||||
while (param_len - 1 > 0 && *threshold_str != ' ')
|
||||
{
|
||||
param_len--;
|
||||
threshold_str--;
|
||||
}
|
||||
|
||||
*threshold_str = '\0';
|
||||
threshold_str++;
|
||||
file = data;
|
||||
threshold = atoi(threshold_str);
|
||||
|
||||
if ((file == NULL) || (is_empty_string(file)) || (threshold > 100) ||
|
||||
(threshold < 1))
|
||||
{
|
||||
goto invalid_parameters;
|
||||
}
|
||||
|
||||
file = resolve_relative_path(rule->ruleset->mp, rule->filename, file);
|
||||
|
||||
if (!fopen(file, "r"))
|
||||
{
|
||||
*error_msg = apr_psprintf(rule->ruleset->mp, "Not able to open file:" \
|
||||
" %s.", file);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
param_data->file = file;
|
||||
param_data->threshold = threshold;
|
||||
|
||||
rule->op_param_data = param_data;
|
||||
#else
|
||||
*error_msg = apr_psprintf(rule->ruleset->mp, "ModSecurity was not " \
|
||||
"compiled with ssdeep support.");
|
||||
|
||||
rule->op_param_data = NULL;
|
||||
|
||||
return -1;
|
||||
#endif
|
||||
return 1;
|
||||
|
||||
invalid_parameters:
|
||||
*error_msg = apr_psprintf(rule->ruleset->mp, "Operator @fuzzyHash " \
|
||||
"requires valid parameters. File and threshold.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int msre_op_fuzzy_hash_execute(modsec_rec *msr, msre_rule *rule,
|
||||
msre_var *var, char **error_msg)
|
||||
{
|
||||
|
||||
#ifdef WITH_SSDEEP
|
||||
char result[FUZZY_MAX_RESULT];
|
||||
struct fuzzy_hash_param_data *param = rule->op_param_data;
|
||||
char line[1024];
|
||||
#endif
|
||||
|
||||
if (error_msg == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
*error_msg = NULL;
|
||||
|
||||
#ifdef WITH_SSDEEP
|
||||
if (fuzzy_hash_buf(var->value, var->value_len, result))
|
||||
{
|
||||
*error_msg = apr_psprintf(rule->ruleset->mp, "Problems generating " \
|
||||
"fuzzy hash.");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
FILE *fp = fopen(param->file, "r");
|
||||
if (!fp)
|
||||
{
|
||||
*error_msg = apr_psprintf(rule->ruleset->mp, "Not able to open " \
|
||||
"fuzzy hash file: %s", param->file);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
while (read_line(line, sizeof(line), fp))
|
||||
{
|
||||
int i = fuzzy_compare(line, result);
|
||||
if (i >= param->threshold)
|
||||
{
|
||||
*error_msg = apr_psprintf(msr->mp, "Fuzzy hash of %s matched " \
|
||||
"with %s (from: %s). Socore: %d.", var->name, line,
|
||||
param->file, i);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
#endif
|
||||
|
||||
/* No match. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* inspectFile */
|
||||
|
||||
static int msre_op_inspectFile_init(msre_rule *rule, char **error_msg) {
|
||||
@ -4552,6 +4692,13 @@ void msre_engine_register_default_operators(msre_engine *engine) {
|
||||
msre_op_inspectFile_execute
|
||||
);
|
||||
|
||||
/* fuzzy_hash */
|
||||
msre_engine_op_register(engine,
|
||||
"fuzzyHash",
|
||||
msre_op_fuzzy_hash_init,
|
||||
msre_op_fuzzy_hash_execute
|
||||
);
|
||||
|
||||
/* validateByteRange */
|
||||
msre_engine_op_register(engine,
|
||||
"validateByteRange",
|
||||
|
Loading…
x
Reference in New Issue
Block a user