/src/suricata7/src/detect-engine-file.c
Line | Count | Source |
1 | | /* Copyright (C) 2007-2021 Open Information Security Foundation |
2 | | * |
3 | | * You can copy, redistribute or modify this Program under the terms of |
4 | | * the GNU General Public License version 2 as published by the Free |
5 | | * Software Foundation. |
6 | | * |
7 | | * This program is distributed in the hope that it will be useful, |
8 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
9 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
10 | | * GNU General Public License for more details. |
11 | | * |
12 | | * You should have received a copy of the GNU General Public License |
13 | | * version 2 along with this program; if not, write to the Free Software |
14 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
15 | | * 02110-1301, USA. |
16 | | */ |
17 | | |
18 | | /** |
19 | | * \file |
20 | | * |
21 | | * \author Victor Julien <victor@inliniac.net> |
22 | | */ |
23 | | |
24 | | #include "suricata-common.h" |
25 | | |
26 | | #include "decode.h" |
27 | | |
28 | | #include "detect.h" |
29 | | #include "detect-engine.h" |
30 | | #include "detect-parse.h" |
31 | | #include "detect-engine-state.h" |
32 | | |
33 | | #include "detect-filestore.h" |
34 | | |
35 | | #include "detect-engine-dcepayload.h" |
36 | | #include "detect-engine-file.h" |
37 | | |
38 | | #include "stream-tcp.h" |
39 | | #include "stream-tcp-private.h" |
40 | | #include "stream-tcp-reassemble.h" |
41 | | |
42 | | #include "app-layer-parser.h" |
43 | | #include "app-layer-protos.h" |
44 | | #include "app-layer-htp.h" |
45 | | #include "app-layer-smtp.h" |
46 | | |
47 | | #include "util-unittest.h" |
48 | | #include "util-unittest-helper.h" |
49 | | #include "util-profiling.h" |
50 | | #include "util-validate.h" |
51 | | |
52 | | /** |
53 | | * \brief Inspect the file inspecting keywords. |
54 | | * |
55 | | * \param tv thread vars |
56 | | * \param det_ctx detection engine thread ctx |
57 | | * \param f flow |
58 | | * \param s signature to inspect |
59 | | * |
60 | | * \retval 0 no match |
61 | | * \retval 1 match |
62 | | * \retval 2 can't match |
63 | | * \retval 3 can't match filestore signature |
64 | | */ |
65 | | static uint8_t DetectFileInspect(DetectEngineThreadCtx *det_ctx, Flow *f, const Signature *s, |
66 | | const SigMatchData *smd, uint8_t flags, FileContainer *ffc) |
67 | 23.1k | { |
68 | 23.1k | uint8_t r = 0; |
69 | 23.1k | int match = 0; |
70 | 23.1k | int store_r = 0; |
71 | | |
72 | 23.1k | SCLogDebug("file inspection... %p", ffc); |
73 | | |
74 | 46.2k | for (File *file = ffc->head; file != NULL; file = file->next) { |
75 | 23.1k | SCLogDebug("file"); |
76 | | |
77 | 23.1k | if (file->state == FILE_STATE_NONE) { |
78 | 0 | SCLogDebug("file state FILE_STATE_NONE"); |
79 | 0 | continue; |
80 | 0 | } |
81 | | |
82 | 23.1k | if ((s->file_flags & FILE_SIG_NEED_FILENAME) && file->name == NULL) { |
83 | 0 | SCLogDebug("sig needs filename, but we don't have any"); |
84 | 0 | r = DETECT_ENGINE_INSPECT_SIG_NO_MATCH; |
85 | 0 | continue; |
86 | 0 | } |
87 | | |
88 | 23.1k | uint64_t file_size = FileDataSize(file); |
89 | 23.1k | if ((s->file_flags & FILE_SIG_NEED_MAGIC) && file_size == 0) { |
90 | 0 | SCLogDebug("sig needs file content, but we don't have any"); |
91 | 0 | r = DETECT_ENGINE_INSPECT_SIG_NO_MATCH; |
92 | 0 | continue; |
93 | 0 | } |
94 | | |
95 | 23.1k | if ((s->file_flags & FILE_SIG_NEED_FILECONTENT) && file_size == 0) { |
96 | 0 | SCLogDebug("sig needs file content, but we don't have any"); |
97 | 0 | r = DETECT_ENGINE_INSPECT_SIG_NO_MATCH; |
98 | 0 | continue; |
99 | 0 | } |
100 | | |
101 | 23.1k | if ((s->file_flags & FILE_SIG_NEED_MD5) && (!(file->flags & FILE_MD5))) { |
102 | 0 | SCLogDebug("sig needs file md5, but we don't have any"); |
103 | 0 | r = DETECT_ENGINE_INSPECT_SIG_NO_MATCH; |
104 | 0 | continue; |
105 | 0 | } |
106 | | |
107 | 23.1k | if ((s->file_flags & FILE_SIG_NEED_SHA1) && (!(file->flags & FILE_SHA1))) { |
108 | 0 | SCLogDebug("sig needs file sha1, but we don't have any"); |
109 | 0 | r = DETECT_ENGINE_INSPECT_SIG_NO_MATCH; |
110 | 0 | continue; |
111 | 0 | } |
112 | | |
113 | 23.1k | if ((s->file_flags & FILE_SIG_NEED_SHA256) && (!(file->flags & FILE_SHA256))) { |
114 | 0 | SCLogDebug("sig needs file sha256, but we don't have any"); |
115 | 0 | r = DETECT_ENGINE_INSPECT_SIG_NO_MATCH; |
116 | 0 | continue; |
117 | 0 | } |
118 | | |
119 | 23.1k | if ((s->file_flags & FILE_SIG_NEED_SIZE) && file->state < FILE_STATE_CLOSED) { |
120 | 89 | SCLogDebug("sig needs filesize, but state < FILE_STATE_CLOSED"); |
121 | 89 | r = DETECT_ENGINE_INSPECT_SIG_NO_MATCH; |
122 | 89 | continue; |
123 | 89 | } |
124 | | |
125 | | /* run the file match functions. */ |
126 | 23.0k | while (1) { |
127 | 23.0k | SCLogDebug("smd %p", smd); |
128 | | |
129 | 23.0k | if (sigmatch_table[smd->type].FileMatch != NULL) { |
130 | 23.0k | KEYWORD_PROFILING_START; |
131 | 23.0k | match = sigmatch_table[smd->type].FileMatch(det_ctx, f, flags, file, s, smd->ctx); |
132 | 23.0k | KEYWORD_PROFILING_END(det_ctx, smd->type, (match > 0)); |
133 | 23.0k | if (match == 0) { |
134 | 70 | r = DETECT_ENGINE_INSPECT_SIG_CANT_MATCH_FILES; |
135 | 70 | break; |
136 | 23.0k | } else if (smd->is_last) { |
137 | 22.9k | r = DETECT_ENGINE_INSPECT_SIG_MATCH; |
138 | 22.9k | break; |
139 | 22.9k | } |
140 | 23.0k | } |
141 | 15 | if (smd->is_last) |
142 | 0 | break; |
143 | 15 | smd++; |
144 | 15 | } |
145 | | |
146 | | /* continue inspection for other files as we may want to store |
147 | | * those as well. We'll return 1 (match) regardless of their |
148 | | * results though */ |
149 | 23.0k | if (r == DETECT_ENGINE_INSPECT_SIG_MATCH) |
150 | 22.9k | store_r = DETECT_ENGINE_INSPECT_SIG_MATCH; |
151 | | |
152 | | /* continue, this file may (or may not) be unable to match |
153 | | * maybe we have more that can :) */ |
154 | 23.0k | } |
155 | | |
156 | 23.1k | if (r == DETECT_ENGINE_INSPECT_SIG_NO_MATCH && store_r == DETECT_ENGINE_INSPECT_SIG_MATCH) { |
157 | 0 | SCLogDebug("stored MATCH, current file NOMATCH"); |
158 | 0 | SCReturnInt(DETECT_ENGINE_INSPECT_SIG_MATCH_MORE_FILES); |
159 | 0 | } |
160 | | |
161 | 23.1k | if (store_r == DETECT_ENGINE_INSPECT_SIG_MATCH) |
162 | 22.9k | r = DETECT_ENGINE_INSPECT_SIG_MATCH; |
163 | 23.1k | SCReturnInt(r); |
164 | 23.1k | } |
165 | | |
166 | | /** |
167 | | * \brief Inspect the file inspecting keywords against the state |
168 | | * |
169 | | * \param det_ctx detection engine thread ctx |
170 | | * \param f flow |
171 | | * \param s signature to inspect |
172 | | * \param alstate state |
173 | | * \param flags direction flag |
174 | | * |
175 | | * \retval 0 no match |
176 | | * \retval 1 match |
177 | | * \retval 2 can't match |
178 | | * \retval 3 can't match filestore signature |
179 | | * |
180 | | * \note flow is not locked at this time |
181 | | */ |
182 | | uint8_t DetectFileInspectGeneric(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, |
183 | | const struct DetectEngineAppInspectionEngine_ *engine, const Signature *s, Flow *f, |
184 | | uint8_t flags, void *alstate, void *tx, uint64_t tx_id) |
185 | 52.5k | { |
186 | 52.5k | SCEnter(); |
187 | 52.5k | DEBUG_VALIDATE_BUG_ON(f->alstate != alstate); |
188 | | |
189 | 52.5k | const uint8_t direction = flags & (STREAM_TOSERVER|STREAM_TOCLIENT); |
190 | 52.5k | AppLayerGetFileState files = AppLayerParserGetTxFiles(f, alstate, tx, direction); |
191 | 52.5k | FileContainer *ffc = files.fc; |
192 | 52.5k | SCLogDebug("tx %p tx_id %" PRIu64 " ffc %p ffc->head %p sid %u", tx, tx_id, ffc, |
193 | 52.5k | ffc ? ffc->head : NULL, s->id); |
194 | 52.5k | if (ffc == NULL) { |
195 | 21.0k | SCReturnInt(DETECT_ENGINE_INSPECT_SIG_CANT_MATCH_FILES); |
196 | 31.5k | } else if (ffc->head == NULL) { |
197 | 8.35k | SCReturnInt(DETECT_ENGINE_INSPECT_SIG_NO_MATCH); |
198 | 8.35k | } |
199 | | |
200 | 23.1k | uint8_t r = DETECT_ENGINE_INSPECT_SIG_NO_MATCH; |
201 | 23.1k | uint8_t match = DetectFileInspect(det_ctx, f, s, engine->smd, flags, ffc); |
202 | 23.1k | if (match == DETECT_ENGINE_INSPECT_SIG_MATCH) { |
203 | 22.9k | r = DETECT_ENGINE_INSPECT_SIG_MATCH; |
204 | 22.9k | } else if (match == DETECT_ENGINE_INSPECT_SIG_CANT_MATCH) { |
205 | 0 | SCLogDebug("sid %u can't match on this transaction", s->id); |
206 | 0 | r = DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; |
207 | 159 | } else if (match == DETECT_ENGINE_INSPECT_SIG_CANT_MATCH_FILES) { |
208 | 70 | SCLogDebug("sid %u can't match on this transaction (file sig)", s->id); |
209 | 70 | r = DETECT_ENGINE_INSPECT_SIG_CANT_MATCH_FILES; |
210 | 89 | } else if (match == DETECT_ENGINE_INSPECT_SIG_MATCH_MORE_FILES) { |
211 | 0 | SCLogDebug("match with more files ahead"); |
212 | 0 | r = match; |
213 | 0 | } |
214 | | |
215 | 23.1k | SCReturnInt(r); |
216 | 52.5k | } |