Skip to content

Commit 7622866

Browse files
author
Felipe Zimmerle
committed
Adds support for @fuzzyHash
Issue #997
1 parent 4ecfed3 commit 7622866

File tree

20 files changed

+1224
-709
lines changed

20 files changed

+1224
-709
lines changed

CHANGES

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
v3.0.????? - ?
33
---------------------------
44

5+
- Adds support for @fuzzyHash operator.
6+
[Issue #997 - @zimmerle]
57
- Fix build on non x86 arch build
68
[Issue #1598 - @athmane]
79
- Fix memory issue while changing rule target dynamic

Makefile.am

+1
Original file line numberDiff line numberDiff line change
@@ -284,4 +284,5 @@ TESTS+=test/test-cases/regression/offset-variable.json
284284
TESTS+=test/test-cases/regression/config-update-target-by-tag.json
285285
TESTS+=test/test-cases/regression/config-update-target-by-id.json
286286
TESTS+=test/test-cases/regression/misc-variable-under-quotes.json
287+
TESTS+=test/test-cases/regression/operator-fuzzyhash.json
287288

build/ssdeep.m4

+153
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
dnl Check for SSDEEP Libraries
2+
dnl CHECK_SSDEEP(ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND])
3+
4+
5+
AC_DEFUN([CHECK_SSDEEP],
6+
[dnl
7+
8+
# Possible names for the ssdeep library/package (pkg-config)
9+
SSDEEP_POSSIBLE_LIB_NAMES="fuzzy"
10+
11+
# Possible extensions for the library
12+
SSDEEP_POSSIBLE_EXTENSIONS="so so0 la sl dll dylib so.0.0.0"
13+
14+
# Possible paths (if pkg-config was not found, proceed with the file lookup)
15+
SSDEEP_POSSIBLE_PATHS="/usr/lib /usr/local/lib /usr/local/fuzzy /usr/local/libfuzzy /usr/local /opt /usr /usr/lib64 /opt/local"
16+
17+
# Variables to be set by this very own script.
18+
SSDEEP_CFLAGS=""
19+
SSDEEP_LDFLAGS=""
20+
SSDEEP_LDADD=""
21+
SSDEEP_DISPLAY=""
22+
23+
AC_ARG_WITH(
24+
ssdeep,
25+
AC_HELP_STRING(
26+
[--with-ssdeep=PATH],
27+
[Path to ssdeep prefix]
28+
)
29+
)
30+
31+
32+
if test "x${with_ssdeep}" == "xno"; then
33+
AC_DEFINE(HAVE_SSDEEP, 0, [Support for SSDEEP was disabled by the utilization of --without-ssdeep or --with-ssdeep=no])
34+
AC_MSG_NOTICE([Support for SSDEEP was disabled by the utilization of --without-ssdeep or --with-ssdeep=no])
35+
SSDEEP_DISABLED=yes
36+
else
37+
if test "x${with_ssdeep}" == "xyes"; then
38+
SSDEEP_MANDATORY=yes
39+
AC_MSG_NOTICE([SSDEEP support was marked as mandatory by the utilization of --with-ssdeep=yes])
40+
else
41+
SSDEEP_MANDATORY=no
42+
fi
43+
for x in ${SSDEEP_POSSIBLE_PATHS}; do
44+
CHECK_FOR_SSDEEP_AT(${x})
45+
if test -n "${SSDEEP_CFLAGS}"; then
46+
break
47+
fi
48+
done
49+
fi
50+
51+
52+
if test -z "${SSDEEP_CFLAGS}"; then
53+
if test -z "${SSDEEP_MANDATORY}"; then
54+
if test -z "${SSDEEP_DISABLED}"; then
55+
AC_MSG_NOTICE([SSDEEP library was not found])
56+
SSDEEP_FOUND=0
57+
else
58+
SSDEEP_FOUND=2
59+
fi
60+
else
61+
AC_MSG_ERROR([SSDEEP was explicitly referenced but it was not found])
62+
SSDEEP_FOUND=-1
63+
fi
64+
else
65+
66+
if test -z "${SSDEEP_MANDATORY}"; then
67+
SSDEEP_FOUND=2
68+
AC_MSG_NOTICE([SSDEEP is disabled by default.])
69+
else
70+
SSDEEP_FOUND=1
71+
AC_MSG_NOTICE([using SSDEEP v${SSDEEP_VERSION}])
72+
SSDEEP_CFLAGS="-DWITH_SSDEEP ${SSDEEP_CFLAGS}"
73+
SSDEEP_DISPLAY="${SSDEEP_LDADD} ${SSDEEP_LDFLAGS}, ${SSDEEP_CFLAGS}"
74+
AC_SUBST(SSDEEP_LDFLAGS)
75+
AC_SUBST(SSDEEP_LDADD)
76+
AC_SUBST(SSDEEP_CFLAGS)
77+
AC_SUBST(SSDEEP_DISPLAY)
78+
fi
79+
fi
80+
81+
82+
AC_SUBST(SSDEEP_FOUND)
83+
84+
]) # AC_DEFUN [CHECK_SSDEEP]
85+
86+
87+
AC_DEFUN([CHECK_FOR_SSDEEP_AT], [
88+
path=$1
89+
echo "*** LOOKING AT PATH: " ${path}
90+
for y in ${SSDEEP_POSSIBLE_EXTENSIONS}; do
91+
for z in ${SSDEEP_POSSIBLE_LIB_NAMES}; do
92+
if test -e "${path}/${z}.${y}"; then
93+
ssdeep_lib_path="${path}/"
94+
ssdeep_lib_name="${z}"
95+
ssdeep_lib_file="${ssdeep_lib_path}/${z}.${y}"
96+
break
97+
fi
98+
if test -e "${path}/lib${z}.${y}"; then
99+
ssdeep_lib_path="${path}/"
100+
ssdeep_lib_name="${z}"
101+
ssdeep_lib_file="${ssdeep_lib_path}/lib${z}.${y}"
102+
break
103+
fi
104+
if test -e "${path}/lib/lib${z}.${y}"; then
105+
ssdeep_lib_path="${path}/lib/"
106+
ssdeep_lib_name="${z}"
107+
ssdeep_lib_file="${ssdeep_lib_path}/lib${z}.${y}"
108+
break
109+
fi
110+
if test -e "${path}/lib/x86_64-linux-gnu/lib${z}.${y}"; then
111+
ssdeep_lib_path="${path}/lib/x86_64-linux-gnu/"
112+
ssdeep_lib_name="${z}"
113+
ssdeep_lib_file="${ssdeep_lib_path}/lib${z}.${y}"
114+
break
115+
fi
116+
if test -e "${path}/lib/i386-linux-gnu/lib${z}.${y}"; then
117+
ssdeep_lib_path="${path}/lib/i386-linux-gnu/"
118+
ssdeep_lib_name="${z}"
119+
ssdeep_lib_file="${ssdeep_lib_path}/lib${z}.${y}"
120+
break
121+
fi
122+
done
123+
if test -n "$ssdeep_lib_path"; then
124+
break
125+
fi
126+
done
127+
if test -e "${path}/include/fuzzy.h"; then
128+
ssdeep_inc_path="${path}/include"
129+
elif test -e "${path}/fuzzy.h"; then
130+
ssdeep_inc_path="${path}"
131+
elif test -e "${path}/include/fuzzy/fuzzy.h"; then
132+
ssdeep_inc_path="${path}/include"
133+
fi
134+
135+
if test -n "${ssdeep_lib_path}"; then
136+
AC_MSG_NOTICE([SSDEEP library found at: ${ssdeep_lib_file}])
137+
fi
138+
139+
if test -n "${ssdeep_inc_path}"; then
140+
AC_MSG_NOTICE([SSDEEP headers found at: ${ssdeep_inc_path}])
141+
fi
142+
143+
if test -n "${ssdeep_lib_path}" -a -n "${ssdeep_inc_path}"; then
144+
# TODO: Compile a piece of code to check the version.
145+
SSDEEP_CFLAGS="-I${ssdeep_inc_path}"
146+
SSDEEP_LDADD="-l${ssdeep_lib_name}"
147+
SSDEEP_LDFLAGS="-L${ssdeep_lib_path}"
148+
SSDEEP_DISPLAY="${ssdeep_lib_file}, ${ssdeep_inc_path}"
149+
fi
150+
]) # AC_DEFUN [CHECK_FOR_SSDEEP_AT]
151+
152+
153+

configure.ac

+22
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,10 @@ AM_CONDITIONAL([GEOIP_CFLAGS], [test "GEOIP_CFLAGS" != ""])
8686
PROG_LMDB
8787
AM_CONDITIONAL([LMDB_CFLAGS], [test "LMDB_CFLAGS" != ""])
8888

89+
# Check for SSDEEP
90+
CHECK_SSDEEP
91+
AM_CONDITIONAL([SSDEEP_CFLAGS], [test "SSDEEP_CFLAGS" != ""])
92+
8993
#
9094
# Check for curl
9195
#
@@ -483,6 +487,24 @@ if test "x$LIBXML2_FOUND" = "x2"; then
483487
fi
484488

485489

490+
## SSDEEP
491+
if test "x$SSDEEP_FOUND" = "x0"; then
492+
echo " + SSDEEP ....not found"
493+
fi
494+
if test "x$SSDEEP_FOUND" = "x1"; then
495+
echo -n " + SSDEEP ....found "
496+
if ! test "x$SSDEEP_VERSION" = "x"; then
497+
echo "v${SSDEEP_VERSION}"
498+
else
499+
echo ""
500+
fi
501+
echo " ${SSDEEP_DISPLAY}"
502+
fi
503+
if test "x$SSDEEP_FOUND" = "x2"; then
504+
echo " + SSDEEP ....disabled"
505+
fi
506+
507+
486508
echo " "
487509
echo " Other Options"
488510
if test $buildTestUtilities = true; then

examples/multiprocess_c/Makefile.am

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ multi_LDADD = \
1111
-lpthread \
1212
$(YAJL_LDFLAGS) \
1313
$(GEOIP_LDFLAGS) \
14+
$(SSDEEP_LDFLAGS) $(SSDEEP_LDADD) \
1415
$(GLOBAL_LDADD)
1516

1617
multi_CFLAGS = \

examples/reading_logs_via_rule_message/Makefile.am

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ simple_request_LDADD = \
1313
$(PCRE_LDADD) \
1414
$(YAJL_LDFLAGS) $(YAJL_LDADD) \
1515
$(LMDB_LDFLAGS) $(LMDB_LDADD) \
16+
$(SSDEEP_LDFLAGS) $(SSDEEP_LDADD) \
1617
$(LIBXML2_LDADD) \
1718
$(GLOBAL_LDADD)
1819

examples/reading_logs_with_offset/Makefile.am

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ read_LDADD = \
1212
$(PCRE_LDADD) \
1313
$(YAJL_LDFLAGS) $(YAJL_LDADD) \
1414
$(LMDB_LDFLAGS) $(LMDB_LDADD) \
15+
$(SSDEEP_LDFLAGS) $(SSDEEP_LDADD) \
1516
$(LIBXML2_LDADD) \
1617
$(GLOBAL_LDADD)
1718

examples/simple_example_using_c/Makefile.am

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ test_LDADD = \
1010
-lmodsecurity \
1111
$(YAJL_LDFLAGS) \
1212
$(GEOIP_LDFLAGS) \
13+
$(SSDEEP_LDFLAGS) $(SSDEEP_LDADD) \
1314
$(GLOBAL_LDADD)
1415

1516
test_CFLAGS = \

examples/using_bodies_in_chunks/Makefile.am

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ simple_request_LDADD = \
1313
$(PCRE_LDADD) \
1414
$(YAJL_LDFLAGS) $(YAJL_LDADD) \
1515
$(LMDB_LDFLAGS) $(LMDB_LDADD) \
16+
$(SSDEEP_LDFLAGS) $(SSDEEP_LDADD) \
1617
$(LIBXML2_LDADD) \
1718
$(GLOBAL_LDADD)
1819

src/Makefile.am

+2
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,7 @@ libmodsecurity_la_CPPFLAGS = \
297297
$(YAJL_CFLAGS) \
298298
$(LMDB_CFLAGS) \
299299
$(PCRE_CFLAGS) \
300+
$(SSDEEP_CFLAGS) \
300301
$(LIBXML2_CFLAGS)
301302

302303
libmodsecurity_la_LIBADD = \
@@ -306,6 +307,7 @@ libmodsecurity_la_LIBADD = \
306307
$(PCRE_LDADD) \
307308
$(YAJL_LDFLAGS) $(YAJL_LDADD) \
308309
$(LMDB_LDFLAGS) $(LMDB_LDADD) \
310+
$(SSDEEP_LDFLAGS) $(SSDEEP_LDADD) \
309311
$(LIBXML2_LDADD) \
310312
../others/libinjection.la \
311313
../others/libmbedtls.la

src/operators/fuzzy_hash.cc

+85-5
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,96 @@
1919

2020
#include "src/operators/operator.h"
2121
#include "src/macro_expansion.h"
22+
#include "src/utils/system.h"
2223

2324
namespace modsecurity {
2425
namespace operators {
2526

26-
bool FuzzyHash::evaluate(Transaction *transaction, const std::string &str) {
27-
/**
28-
* @todo Implement the operator FuzzyHash.
29-
* Reference: https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual#fuzzyhash
30-
*/
27+
bool FuzzyHash::init(const std::string &param2, std::string *error) {
28+
#ifdef WITH_SSDEEP
29+
std::string digit;
30+
std::string file;
31+
std::istream *iss;
32+
struct fuzzy_hash_chunk *chunk, *t;
33+
std::string err;
34+
35+
auto pos = m_param.find_last_of(' ');
36+
if (pos == std::string::npos) {
37+
error->assign("Please use @fuzzyHash with filename and value");
38+
return false;
39+
}
40+
digit.append(std::string(m_param, pos+1));
41+
file.append(std::string(m_param, 0, pos));
42+
try {
43+
m_threshold = std::stoi(digit);
44+
} catch (...) {
45+
error->assign("Expecting a digit, got: " + digit);
46+
return false;
47+
}
48+
49+
std::string resource = utils::find_resource(file, param2, &err);
50+
iss = new std::ifstream(resource, std::ios::in);
51+
52+
if (((std::ifstream *)iss)->is_open() == false) {
53+
error->assign("Failed to open file: " + m_param + ". " + err);
54+
delete iss;
55+
return false;
56+
}
57+
58+
for (std::string line; std::getline(*iss, line); ) {
59+
chunk = (struct fuzzy_hash_chunk *)calloc(1, sizeof(struct fuzzy_hash_chunk));
60+
61+
chunk->data = strdup(line.c_str());
62+
chunk->next = NULL;
63+
64+
if (m_head == NULL) {
65+
m_head = chunk;
66+
} else {
67+
t = m_head;
68+
69+
while (t->next) {
70+
t = t->next;
71+
}
72+
73+
t->next = chunk;
74+
}
75+
}
76+
77+
delete iss;
3178
return true;
79+
#else
80+
error->assign("@fuzzyHash: SSDEEP support was not enabled during the compilation.");
81+
return false;
82+
#endif
83+
}
84+
85+
86+
87+
bool FuzzyHash::evaluate(Transaction *t, const std::string &str) {
88+
#ifdef WITH_SSDEEP
89+
char result[FUZZY_MAX_RESULT];
90+
struct fuzzy_hash_chunk *chunk = m_head;
91+
92+
if (fuzzy_hash_buf((const unsigned char*)str.c_str(), str.size(), result))
93+
{
94+
t->debug(4, "Problems generating fuzzy hash");
95+
return false;
96+
}
97+
98+
while (chunk != NULL)
99+
{
100+
int i = fuzzy_compare(chunk->data, result);
101+
if (i >= m_threshold)
102+
{
103+
t->debug(4, "Fuzzy hash: matched " \
104+
"with score: " + std::to_string(i) + ".");
105+
return true;
106+
}
107+
chunk = chunk->next;
108+
}
109+
#endif
110+
/* No match. */
111+
return false;
32112
}
33113

34114
} // namespace operators

0 commit comments

Comments
 (0)