Skip to content

Commit d287029

Browse files
author
Felipe Zimmerle
committed
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/
1 parent 42adb2e commit d287029

File tree

4 files changed

+180
-0
lines changed

4 files changed

+180
-0
lines changed

apache2/msc_util.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2453,6 +2453,32 @@ int msc_headers_to_buffer(const apr_array_header_t *arr, char *buffer,
24532453
return headers_length;
24542454
}
24552455

2456+
int read_line(char *buf, int len, FILE *fp)
2457+
{
2458+
char *tmp;
2459+
2460+
if (buf == NULL)
2461+
{
2462+
return -1;
2463+
}
2464+
2465+
memset(buf, '\0', len*sizeof(char));
2466+
2467+
if (fgets(buf, len, fp) == NULL)
2468+
{
2469+
*buf = '\0';
2470+
return 0;
2471+
}
2472+
else
2473+
{
2474+
if ((tmp = strrchr(buf, '\n')) != NULL)
2475+
{
2476+
*tmp = '\0';
2477+
}
2478+
}
2479+
2480+
return 1;
2481+
}
24562482

24572483
int create_radix_tree(apr_pool_t *mp, TreeRoot **rtree, char **error_msg)
24582484
{

apache2/msc_util.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,4 +159,6 @@ int DSOLOCAL tree_contains_ip(apr_pool_t *mp, TreeRoot *rtree,
159159
int DSOLOCAL ip_tree_from_param(apr_pool_t *pool,
160160
char *param, TreeRoot **rtree, char **error_msg);
161161

162+
int read_line(char *buff, int size, FILE *fp);
163+
162164
#endif

apache2/re.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,4 +409,9 @@ struct msre_cache_rec {
409409
apr_size_t val_len;
410410
};
411411

412+
struct fuzzy_hash_param_data {
413+
const char *file;
414+
int threshold;
415+
};
416+
412417
#endif

apache2/re_operators.c

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@
2727
#include <arpa/inet.h>
2828
#endif
2929

30+
#ifdef WITH_SSDEEP
31+
#include "fuzzy.h"
32+
#endif
33+
3034
#include "libinjection/libinjection.h"
3135

3236
/**
@@ -3718,6 +3722,142 @@ static int msre_op_rbl_execute(modsec_rec *msr, msre_rule *rule, msre_var *var,
37183722
return 0;
37193723
}
37203724

3725+
/* fuzzyHash */
3726+
static int msre_op_fuzzy_hash_init(msre_rule *rule, char **error_msg)
3727+
{
3728+
#ifdef WITH_SSDEEP
3729+
struct fuzzy_hash_param_data *param_data;
3730+
char *file;
3731+
int param_len,threshold;
3732+
3733+
char *data = NULL;
3734+
char *threshold_str = NULL;
3735+
3736+
param_data = apr_palloc(rule->ruleset->mp,
3737+
sizeof(struct fuzzy_hash_param_data));
3738+
3739+
data = apr_pstrdup(rule->ruleset->mp, rule->op_param);
3740+
threshold_str = data;
3741+
#endif
3742+
3743+
if (error_msg == NULL)
3744+
{
3745+
return -1;
3746+
}
3747+
3748+
*error_msg = NULL;
3749+
3750+
#ifdef WITH_SSDEEP
3751+
/* Sanity check */
3752+
param_len = strlen(threshold_str);
3753+
threshold_str = threshold_str + param_len;
3754+
3755+
if (param_len < 3)
3756+
{
3757+
goto invalid_parameters;
3758+
}
3759+
3760+
while (param_len - 1 > 0 && *threshold_str != ' ')
3761+
{
3762+
param_len--;
3763+
threshold_str--;
3764+
}
3765+
3766+
*threshold_str = '\0';
3767+
threshold_str++;
3768+
file = data;
3769+
threshold = atoi(threshold_str);
3770+
3771+
if ((file == NULL) || (is_empty_string(file)) || (threshold > 100) ||
3772+
(threshold < 1))
3773+
{
3774+
goto invalid_parameters;
3775+
}
3776+
3777+
file = resolve_relative_path(rule->ruleset->mp, rule->filename, file);
3778+
3779+
if (!fopen(file, "r"))
3780+
{
3781+
*error_msg = apr_psprintf(rule->ruleset->mp, "Not able to open file:" \
3782+
" %s.", file);
3783+
return -1;
3784+
}
3785+
3786+
3787+
param_data->file = file;
3788+
param_data->threshold = threshold;
3789+
3790+
rule->op_param_data = param_data;
3791+
#else
3792+
*error_msg = apr_psprintf(rule->ruleset->mp, "ModSecurity was not " \
3793+
"compiled with ssdeep support.");
3794+
3795+
rule->op_param_data = NULL;
3796+
3797+
return -1;
3798+
#endif
3799+
return 1;
3800+
3801+
invalid_parameters:
3802+
*error_msg = apr_psprintf(rule->ruleset->mp, "Operator @fuzzyHash " \
3803+
"requires valid parameters. File and threshold.");
3804+
return -1;
3805+
}
3806+
3807+
static int msre_op_fuzzy_hash_execute(modsec_rec *msr, msre_rule *rule,
3808+
msre_var *var, char **error_msg)
3809+
{
3810+
3811+
#ifdef WITH_SSDEEP
3812+
char result[FUZZY_MAX_RESULT];
3813+
struct fuzzy_hash_param_data *param = rule->op_param_data;
3814+
char line[1024];
3815+
#endif
3816+
3817+
if (error_msg == NULL)
3818+
{
3819+
return -1;
3820+
}
3821+
3822+
*error_msg = NULL;
3823+
3824+
#ifdef WITH_SSDEEP
3825+
if (fuzzy_hash_buf(var->value, var->value_len, result))
3826+
{
3827+
*error_msg = apr_psprintf(rule->ruleset->mp, "Problems generating " \
3828+
"fuzzy hash.");
3829+
3830+
return -1;
3831+
}
3832+
3833+
FILE *fp = fopen(param->file, "r");
3834+
if (!fp)
3835+
{
3836+
*error_msg = apr_psprintf(rule->ruleset->mp, "Not able to open " \
3837+
"fuzzy hash file: %s", param->file);
3838+
3839+
return 1;
3840+
}
3841+
3842+
while (read_line(line, sizeof(line), fp))
3843+
{
3844+
int i = fuzzy_compare(line, result);
3845+
if (i >= param->threshold)
3846+
{
3847+
*error_msg = apr_psprintf(msr->mp, "Fuzzy hash of %s matched " \
3848+
"with %s (from: %s). Socore: %d.", var->name, line,
3849+
param->file, i);
3850+
return 1;
3851+
}
3852+
}
3853+
3854+
fclose(fp);
3855+
#endif
3856+
3857+
/* No match. */
3858+
return 0;
3859+
}
3860+
37213861
/* inspectFile */
37223862

37233863
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) {
45524692
msre_op_inspectFile_execute
45534693
);
45544694

4695+
/* fuzzy_hash */
4696+
msre_engine_op_register(engine,
4697+
"fuzzyHash",
4698+
msre_op_fuzzy_hash_init,
4699+
msre_op_fuzzy_hash_execute
4700+
);
4701+
45554702
/* validateByteRange */
45564703
msre_engine_op_register(engine,
45574704
"validateByteRange",

0 commit comments

Comments
 (0)