1 /*
2  * ModSecurity, http://www.modsecurity.org/
3  * Copyright (c) 2015 - 2021 Trustwave Holdings, Inc. (http://www.trustwave.com/)
4  *
5  * You may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * If any of the files related to licensing are missing or if you have any
11  * other questions related to licensing please contact Trustwave Holdings, Inc.
12  * directly using the email address security@modsecurity.org.
13  *
14  */
15 
16 #include "src/operators/fuzzy_hash.h"
17 
18 #include <string>
19 
20 #include "src/operators/operator.h"
21 #include "src/utils/system.h"
22 
23 namespace modsecurity {
24 namespace operators {
25 
init(const std::string & param2,std::string * error)26 bool FuzzyHash::init(const std::string &param2, std::string *error) {
27 #ifdef WITH_SSDEEP
28     std::string digit;
29     std::string file;
30     std::istream *iss;
31     struct fuzzy_hash_chunk *chunk, *t;
32     std::string err;
33 
34     auto pos = m_param.find_last_of(' ');
35     if (pos == std::string::npos) {
36         error->assign("Please use @fuzzyHash with filename and value");
37         return false;
38     }
39     digit.append(std::string(m_param, pos+1));
40     file.append(std::string(m_param, 0, pos));
41     try {
42         m_threshold = std::stoi(digit);
43     } catch (...) {
44         error->assign("Expecting a digit, got: " + digit);
45         return false;
46     }
47 
48     std::string resource = utils::find_resource(file, param2, &err);
49     iss = new std::ifstream(resource, std::ios::in);
50 
51     if (((std::ifstream *)iss)->is_open() == false) {
52         error->assign("Failed to open file: " + m_param + ". " + err);
53         delete iss;
54         return false;
55     }
56 
57     for (std::string line; std::getline(*iss, line); ) {
58        chunk = (struct fuzzy_hash_chunk *)calloc(1,
59             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;
78     return true;
79 #else
80     error->assign("@fuzzyHash: SSDEEP support was not enabled " \
81         "during the compilation.");
82     return false;
83 #endif
84 }
85 
~FuzzyHash()86 FuzzyHash::~FuzzyHash() {
87     struct fuzzy_hash_chunk *c = m_head;
88     while (c) {
89         struct fuzzy_hash_chunk *t = c;
90         free(c->data);
91         c->data = NULL;
92         c = c->next;
93         free(t);
94     }
95     m_head = NULL;
96 }
97 
98 
evaluate(Transaction * t,const std::string & str)99 bool FuzzyHash::evaluate(Transaction *t, const std::string &str) {
100 #ifdef WITH_SSDEEP
101     char result[FUZZY_MAX_RESULT];
102     struct fuzzy_hash_chunk *chunk = m_head;
103 
104     if (fuzzy_hash_buf((const unsigned char*)str.c_str(),
105         str.size(), result)) {
106         ms_dbg_a(t, 4, "Problems generating fuzzy hash");
107         return false;
108     }
109 
110     while (chunk != NULL) {
111         int i = fuzzy_compare(chunk->data, result);
112         if (i >= m_threshold) {
113             ms_dbg_a(t, 4, "Fuzzy hash: matched " \
114                 "with score: " + std::to_string(i) + ".");
115             return true;
116         }
117         chunk = chunk->next;
118     }
119 #endif
120     /* No match. */
121     return false;
122 }
123 
124 }  // namespace operators
125 }  // namespace modsecurity
126