/src/suricata7/src/detect-http-uri.c
Line | Count | Source |
1 | | /* Copyright (C) 2007-2018 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 | | * \ingroup httplayer |
20 | | * |
21 | | * @{ |
22 | | */ |
23 | | |
24 | | |
25 | | /** |
26 | | * \file |
27 | | * |
28 | | * \author Gerardo Iglesias <iglesiasg@gmail.com> |
29 | | * \author Victor Julien <victor@inliniac.net> |
30 | | */ |
31 | | |
32 | | #include "suricata-common.h" |
33 | | #include "threads.h" |
34 | | #include "decode.h" |
35 | | #include "detect.h" |
36 | | |
37 | | #include "detect-parse.h" |
38 | | #include "detect-engine.h" |
39 | | #include "detect-engine-mpm.h" |
40 | | #include "detect-engine-prefilter.h" |
41 | | #include "detect-content.h" |
42 | | #include "detect-pcre.h" |
43 | | #include "detect-urilen.h" |
44 | | |
45 | | #include "flow.h" |
46 | | #include "flow-var.h" |
47 | | |
48 | | #include "util-debug.h" |
49 | | #include "util-unittest.h" |
50 | | #include "util-spm.h" |
51 | | #include "util-print.h" |
52 | | |
53 | | #include "app-layer.h" |
54 | | |
55 | | #include "app-layer-htp.h" |
56 | | #include "detect-http-uri.h" |
57 | | #include "stream-tcp.h" |
58 | | |
59 | | #ifdef UNITTESTS |
60 | | static void DetectHttpUriRegisterTests(void); |
61 | | #endif |
62 | | static void DetectHttpUriSetupCallback(const DetectEngineCtx *de_ctx, |
63 | | Signature *s); |
64 | | static bool DetectHttpUriValidateCallback(const Signature *s, const char **sigerror); |
65 | | static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, |
66 | | const DetectEngineTransforms *transforms, |
67 | | Flow *_f, const uint8_t _flow_flags, |
68 | | void *txv, const int list_id); |
69 | | static InspectionBuffer *GetData2(DetectEngineThreadCtx *det_ctx, |
70 | | const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, |
71 | | const int list_id); |
72 | | static int DetectHttpUriSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str); |
73 | | static int DetectHttpRawUriSetup(DetectEngineCtx *, Signature *, const char *); |
74 | | static void DetectHttpRawUriSetupCallback(const DetectEngineCtx *de_ctx, |
75 | | Signature *s); |
76 | | static bool DetectHttpRawUriValidateCallback(const Signature *s, const char **); |
77 | | static InspectionBuffer *GetRawData(DetectEngineThreadCtx *det_ctx, |
78 | | const DetectEngineTransforms *transforms, |
79 | | Flow *_f, const uint8_t _flow_flags, |
80 | | void *txv, const int list_id); |
81 | | static int DetectHttpRawUriSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str); |
82 | | |
83 | | static int g_http_raw_uri_buffer_id = 0; |
84 | | static int g_http_uri_buffer_id = 0; |
85 | | |
86 | | /** |
87 | | * \brief Registration function for keywords: http_uri and http.uri |
88 | | */ |
89 | | void DetectHttpUriRegister (void) |
90 | 75 | { |
91 | | /* http_uri content modifier */ |
92 | 75 | sigmatch_table[DETECT_AL_HTTP_URI].name = "http_uri"; |
93 | 75 | sigmatch_table[DETECT_AL_HTTP_URI].desc = "content modifier to match specifically and only on the HTTP uri-buffer"; |
94 | 75 | sigmatch_table[DETECT_AL_HTTP_URI].url = "/rules/http-keywords.html#http-uri-and-http-uri-raw"; |
95 | 75 | sigmatch_table[DETECT_AL_HTTP_URI].Setup = DetectHttpUriSetup; |
96 | | #ifdef UNITTESTS |
97 | | sigmatch_table[DETECT_AL_HTTP_URI].RegisterTests = DetectHttpUriRegisterTests; |
98 | | #endif |
99 | 75 | sigmatch_table[DETECT_AL_HTTP_URI].flags |= SIGMATCH_NOOPT|SIGMATCH_INFO_CONTENT_MODIFIER; |
100 | 75 | sigmatch_table[DETECT_AL_HTTP_URI].alternative = DETECT_HTTP_URI; |
101 | | |
102 | | /* http.uri sticky buffer */ |
103 | 75 | sigmatch_table[DETECT_HTTP_URI].name = "http.uri"; |
104 | 75 | sigmatch_table[DETECT_HTTP_URI].alias = "http.uri.normalized"; |
105 | 75 | sigmatch_table[DETECT_HTTP_URI].desc = "sticky buffer to match specifically and only on the normalized HTTP URI buffer"; |
106 | 75 | sigmatch_table[DETECT_HTTP_URI].url = "/rules/http-keywords.html#http-uri-and-http-uri-raw"; |
107 | 75 | sigmatch_table[DETECT_HTTP_URI].Setup = DetectHttpUriSetupSticky; |
108 | 75 | sigmatch_table[DETECT_HTTP_URI].flags |= SIGMATCH_NOOPT|SIGMATCH_INFO_STICKY_BUFFER; |
109 | | |
110 | 75 | DetectAppLayerInspectEngineRegister2("http_uri", ALPROTO_HTTP1, SIG_FLAG_TOSERVER, |
111 | 75 | HTP_REQUEST_LINE, DetectEngineInspectBufferGeneric, GetData); |
112 | | |
113 | 75 | DetectAppLayerMpmRegister2("http_uri", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, |
114 | 75 | GetData, ALPROTO_HTTP1, HTP_REQUEST_LINE); |
115 | | |
116 | 75 | DetectAppLayerInspectEngineRegister2("http_uri", ALPROTO_HTTP2, SIG_FLAG_TOSERVER, |
117 | 75 | HTTP2StateOpen, DetectEngineInspectBufferGeneric, GetData2); |
118 | | |
119 | 75 | DetectAppLayerMpmRegister2("http_uri", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, |
120 | 75 | GetData2, ALPROTO_HTTP2, HTTP2StateOpen); |
121 | | |
122 | 75 | DetectBufferTypeSetDescriptionByName("http_uri", |
123 | 75 | "http request uri"); |
124 | | |
125 | 75 | DetectBufferTypeRegisterSetupCallback("http_uri", |
126 | 75 | DetectHttpUriSetupCallback); |
127 | | |
128 | 75 | DetectBufferTypeRegisterValidateCallback("http_uri", |
129 | 75 | DetectHttpUriValidateCallback); |
130 | | |
131 | 75 | g_http_uri_buffer_id = DetectBufferTypeGetByName("http_uri"); |
132 | | |
133 | | /* http_raw_uri content modifier */ |
134 | 75 | sigmatch_table[DETECT_AL_HTTP_RAW_URI].name = "http_raw_uri"; |
135 | 75 | sigmatch_table[DETECT_AL_HTTP_RAW_URI].desc = "content modifier to match on the raw HTTP uri"; |
136 | 75 | sigmatch_table[DETECT_AL_HTTP_RAW_URI].url = "/rules/http-keywords.html#http_uri-and-http_raw-uri"; |
137 | 75 | sigmatch_table[DETECT_AL_HTTP_RAW_URI].Setup = DetectHttpRawUriSetup; |
138 | 75 | sigmatch_table[DETECT_AL_HTTP_RAW_URI].flags |= SIGMATCH_NOOPT|SIGMATCH_INFO_CONTENT_MODIFIER; |
139 | 75 | sigmatch_table[DETECT_AL_HTTP_RAW_URI].alternative = DETECT_HTTP_URI_RAW; |
140 | | |
141 | | /* http.uri.raw sticky buffer */ |
142 | 75 | sigmatch_table[DETECT_HTTP_URI_RAW].name = "http.uri.raw"; |
143 | 75 | sigmatch_table[DETECT_HTTP_URI_RAW].desc = "sticky buffer to match specifically and only on the raw HTTP URI buffer"; |
144 | 75 | sigmatch_table[DETECT_HTTP_URI_RAW].url = "/rules/http-keywords.html#http-uri-and-http-raw-uri"; |
145 | 75 | sigmatch_table[DETECT_HTTP_URI_RAW].Setup = DetectHttpRawUriSetupSticky; |
146 | 75 | sigmatch_table[DETECT_HTTP_URI_RAW].flags |= SIGMATCH_NOOPT|SIGMATCH_INFO_STICKY_BUFFER; |
147 | | |
148 | 75 | DetectAppLayerInspectEngineRegister2("http_raw_uri", ALPROTO_HTTP1, SIG_FLAG_TOSERVER, |
149 | 75 | HTP_REQUEST_LINE, DetectEngineInspectBufferGeneric, GetRawData); |
150 | | |
151 | 75 | DetectAppLayerMpmRegister2("http_raw_uri", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, |
152 | 75 | GetRawData, ALPROTO_HTTP1, HTP_REQUEST_LINE); |
153 | | |
154 | | // no difference between raw and decoded uri for HTTP2 |
155 | 75 | DetectAppLayerInspectEngineRegister2("http_raw_uri", ALPROTO_HTTP2, SIG_FLAG_TOSERVER, |
156 | 75 | HTTP2StateOpen, DetectEngineInspectBufferGeneric, GetData2); |
157 | | |
158 | 75 | DetectAppLayerMpmRegister2("http_raw_uri", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, |
159 | 75 | GetData2, ALPROTO_HTTP2, HTTP2StateOpen); |
160 | | |
161 | 75 | DetectBufferTypeSetDescriptionByName("http_raw_uri", |
162 | 75 | "raw http uri"); |
163 | | |
164 | 75 | DetectBufferTypeRegisterSetupCallback("http_raw_uri", |
165 | 75 | DetectHttpRawUriSetupCallback); |
166 | | |
167 | 75 | DetectBufferTypeRegisterValidateCallback("http_raw_uri", |
168 | 75 | DetectHttpRawUriValidateCallback); |
169 | | |
170 | 75 | g_http_raw_uri_buffer_id = DetectBufferTypeGetByName("http_raw_uri"); |
171 | 75 | } |
172 | | |
173 | | /** |
174 | | * \brief this function setups the http_uri modifier keyword used in the rule |
175 | | * |
176 | | * \param de_ctx Pointer to the Detection Engine Context |
177 | | * \param s Pointer to the Signature to which the current keyword belongs |
178 | | * \param str Should hold an empty string always |
179 | | * |
180 | | * \retval 0 On success |
181 | | * \retval -1 On failure |
182 | | */ |
183 | | |
184 | | int DetectHttpUriSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) |
185 | 36.3k | { |
186 | 36.3k | return DetectEngineContentModifierBufferSetup( |
187 | 36.3k | de_ctx, s, str, DETECT_AL_HTTP_URI, g_http_uri_buffer_id, ALPROTO_HTTP1); |
188 | 36.3k | } |
189 | | |
190 | | static bool DetectHttpUriValidateCallback(const Signature *s, const char **sigerror) |
191 | 45.7k | { |
192 | 45.7k | return DetectUrilenValidateContent(s, g_http_uri_buffer_id, sigerror); |
193 | 45.7k | } |
194 | | |
195 | | static void DetectHttpUriSetupCallback(const DetectEngineCtx *de_ctx, |
196 | | Signature *s) |
197 | 82.1k | { |
198 | 82.1k | SCLogDebug("callback invoked by %u", s->id); |
199 | 82.1k | DetectUrilenApplyToContent(s, g_http_uri_buffer_id); |
200 | 82.1k | } |
201 | | |
202 | | /** |
203 | | * \brief this function setup the http.uri keyword used in the rule |
204 | | * |
205 | | * \param de_ctx Pointer to the Detection Engine Context |
206 | | * \param s Pointer to the Signature to which the current keyword belongs |
207 | | * \param str Should hold an empty string always |
208 | | * |
209 | | * \retval 0 On success |
210 | | */ |
211 | | static int DetectHttpUriSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str) |
212 | 63.5k | { |
213 | 63.5k | if (DetectBufferSetActiveList(de_ctx, s, g_http_uri_buffer_id) < 0) |
214 | 603 | return -1; |
215 | 62.9k | if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) < 0) |
216 | 4.66k | return -1; |
217 | 58.2k | return 0; |
218 | 62.9k | } |
219 | | |
220 | | static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, |
221 | | const DetectEngineTransforms *transforms, Flow *_f, |
222 | | const uint8_t _flow_flags, void *txv, const int list_id) |
223 | 2.13k | { |
224 | 2.13k | SCEnter(); |
225 | | |
226 | 2.13k | InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); |
227 | 2.13k | if (!buffer->initialized) { |
228 | 1.95k | htp_tx_t *tx = (htp_tx_t *)txv; |
229 | 1.95k | HtpTxUserData *tx_ud = htp_tx_get_user_data(tx); |
230 | | |
231 | 1.95k | if (tx_ud == NULL || tx_ud->request_uri_normalized == NULL) { |
232 | 849 | SCLogDebug("no tx_id or uri"); |
233 | 849 | return NULL; |
234 | 849 | } |
235 | | |
236 | 1.10k | const uint32_t data_len = bstr_len(tx_ud->request_uri_normalized); |
237 | 1.10k | const uint8_t *data = bstr_ptr(tx_ud->request_uri_normalized); |
238 | | |
239 | 1.10k | InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); |
240 | 1.10k | InspectionBufferApplyTransforms(buffer, transforms); |
241 | 1.10k | } |
242 | | |
243 | 1.28k | return buffer; |
244 | 2.13k | } |
245 | | |
246 | | static InspectionBuffer *GetData2(DetectEngineThreadCtx *det_ctx, |
247 | | const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, |
248 | | const int list_id) |
249 | 2.63k | { |
250 | 2.63k | SCEnter(); |
251 | | |
252 | 2.63k | InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); |
253 | 2.63k | if (!buffer->initialized) { |
254 | 2.38k | uint32_t b_len = 0; |
255 | 2.38k | const uint8_t *b = NULL; |
256 | | |
257 | 2.38k | if (rs_http2_tx_get_uri(txv, &b, &b_len) != 1) |
258 | 1.56k | return NULL; |
259 | 821 | if (b == NULL || b_len == 0) |
260 | 1 | return NULL; |
261 | | |
262 | 820 | InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); |
263 | 820 | InspectionBufferApplyTransforms(buffer, transforms); |
264 | 820 | } |
265 | | |
266 | 1.07k | return buffer; |
267 | 2.63k | } |
268 | | |
269 | | /** |
270 | | * \brief Sets up the http_raw_uri modifier keyword. |
271 | | * |
272 | | * \param de_ctx Pointer to the Detection Engine Context. |
273 | | * \param s Pointer to the Signature to which the current keyword belongs. |
274 | | * \param arg Should hold an empty string always. |
275 | | * |
276 | | * \retval 0 On success. |
277 | | * \retval -1 On failure. |
278 | | */ |
279 | | static int DetectHttpRawUriSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) |
280 | 651 | { |
281 | 651 | return DetectEngineContentModifierBufferSetup( |
282 | 651 | de_ctx, s, arg, DETECT_AL_HTTP_RAW_URI, g_http_raw_uri_buffer_id, ALPROTO_HTTP1); |
283 | 651 | } |
284 | | |
285 | | static bool DetectHttpRawUriValidateCallback(const Signature *s, const char **sigerror) |
286 | 441 | { |
287 | 441 | return DetectUrilenValidateContent(s, g_http_raw_uri_buffer_id, sigerror); |
288 | 441 | } |
289 | | |
290 | | static void DetectHttpRawUriSetupCallback(const DetectEngineCtx *de_ctx, |
291 | | Signature *s) |
292 | 2.16k | { |
293 | 2.16k | SCLogDebug("callback invoked by %u", s->id); |
294 | 2.16k | DetectUrilenApplyToContent(s, g_http_raw_uri_buffer_id); |
295 | 2.16k | } |
296 | | |
297 | | /** |
298 | | * \brief this function setup the http.uri.raw keyword used in the rule |
299 | | * |
300 | | * \param de_ctx Pointer to the Detection Engine Context |
301 | | * \param s Pointer to the Signature to which the current keyword belongs |
302 | | * \param str Should hold an empty string always |
303 | | * |
304 | | * \retval 0 On success |
305 | | */ |
306 | | static int DetectHttpRawUriSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str) |
307 | 2.28k | { |
308 | 2.28k | if (DetectBufferSetActiveList(de_ctx, s, g_http_raw_uri_buffer_id) < 0) |
309 | 3 | return -1; |
310 | 2.28k | if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) < 0) |
311 | 4 | return -1; |
312 | 2.27k | return 0; |
313 | 2.28k | } |
314 | | |
315 | | static InspectionBuffer *GetRawData(DetectEngineThreadCtx *det_ctx, |
316 | | const DetectEngineTransforms *transforms, Flow *_f, |
317 | | const uint8_t _flow_flags, void *txv, const int list_id) |
318 | 12.7k | { |
319 | 12.7k | SCEnter(); |
320 | | |
321 | 12.7k | InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); |
322 | 12.7k | if (!buffer->initialized) { |
323 | 10.0k | htp_tx_t *tx = (htp_tx_t *)txv; |
324 | 10.0k | if (unlikely(tx->request_uri == NULL)) { |
325 | 1.94k | return NULL; |
326 | 1.94k | } |
327 | 8.08k | const uint32_t data_len = bstr_len(tx->request_uri); |
328 | 8.08k | const uint8_t *data = bstr_ptr(tx->request_uri); |
329 | | |
330 | 8.08k | InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); |
331 | 8.08k | InspectionBufferApplyTransforms(buffer, transforms); |
332 | 8.08k | } |
333 | | |
334 | 10.8k | return buffer; |
335 | 12.7k | } |
336 | | |
337 | | #ifdef UNITTESTS /* UNITTESTS */ |
338 | | #include "tests/detect-http-uri.c" |
339 | | #endif /* UNITTESTS */ |
340 | | |
341 | | /** |
342 | | * @} |
343 | | */ |