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:
Felipe Zimmerle 2013-12-06 09:24:42 -08:00
parent 873c628b1a
commit 96865a92d3
4 changed files with 180 additions and 0 deletions

View File

@ -2453,6 +2453,32 @@ not_enough_memory:
return headers_length; 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) int create_radix_tree(apr_pool_t *mp, TreeRoot **rtree, char **error_msg)
{ {

View File

@ -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, int DSOLOCAL ip_tree_from_param(apr_pool_t *pool,
char *param, TreeRoot **rtree, char **error_msg); char *param, TreeRoot **rtree, char **error_msg);
int read_line(char *buff, int size, FILE *fp);
#endif #endif

View File

@ -409,4 +409,9 @@ struct msre_cache_rec {
apr_size_t val_len; apr_size_t val_len;
}; };
struct fuzzy_hash_param_data {
const char *file;
int threshold;
};
#endif #endif

View File

@ -27,6 +27,10 @@
#include <arpa/inet.h> #include <arpa/inet.h>
#endif #endif
#ifdef WITH_SSDEEP
#include "fuzzy.h"
#endif
#include "libinjection/libinjection.h" #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; 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 */ /* inspectFile */
static int msre_op_inspectFile_init(msre_rule *rule, char **error_msg) { 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 msre_op_inspectFile_execute
); );
/* fuzzy_hash */
msre_engine_op_register(engine,
"fuzzyHash",
msre_op_fuzzy_hash_init,
msre_op_fuzzy_hash_execute
);
/* validateByteRange */ /* validateByteRange */
msre_engine_op_register(engine, msre_engine_op_register(engine,
"validateByteRange", "validateByteRange",