/src/suricata8/src/detect-bytejump.c
Line | Count | Source |
1 | | /* Copyright (C) 2007-2020 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 Brian Rectanus <brectanu@gmail.com> |
22 | | * |
23 | | * Implements byte_jump keyword. |
24 | | */ |
25 | | |
26 | | #include "suricata-common.h" |
27 | | #include "decode.h" |
28 | | #include "detect.h" |
29 | | #include "detect-parse.h" |
30 | | #include "detect-engine.h" |
31 | | #include "detect-engine-buffer.h" |
32 | | #include "app-layer.h" |
33 | | |
34 | | #include "detect-byte.h" |
35 | | #include "detect-byte-extract.h" |
36 | | #include "detect-bytejump.h" |
37 | | #include "detect-content.h" |
38 | | #include "detect-uricontent.h" |
39 | | |
40 | | #include "util-byte.h" |
41 | | #include "util-unittest.h" |
42 | | #include "util-debug.h" |
43 | | #include "util-validate.h" |
44 | | #include "detect-pcre.h" |
45 | | #include "detect-engine-build.h" |
46 | | |
47 | | /** |
48 | | * \brief Regex for parsing our options |
49 | | */ |
50 | 12 | #define PARSE_REGEX "^\\s*" \ |
51 | 12 | "([^\\s,]+\\s*,\\s*[^\\s,]+)" \ |
52 | 12 | "(?:\\s*,\\s*((?:multiplier|post_offset)\\s+[^\\s,]+|[^\\s,]+))?" \ |
53 | 12 | "(?:\\s*,\\s*((?:multiplier|post_offset)\\s+[^\\s,]+|[^\\s,]+))?" \ |
54 | 12 | "(?:\\s*,\\s*((?:multiplier|post_offset)\\s+[^\\s,]+|[^\\s,]+))?" \ |
55 | 12 | "(?:\\s*,\\s*((?:multiplier|post_offset)\\s+[^\\s,]+|[^\\s,]+))?" \ |
56 | 12 | "(?:\\s*,\\s*((?:multiplier|post_offset)\\s+[^\\s,]+|[^\\s,]+))?" \ |
57 | 12 | "(?:\\s*,\\s*((?:multiplier|post_offset)\\s+[^\\s,]+|[^\\s,]+))?" \ |
58 | 12 | "(?:\\s*,\\s*((?:multiplier|post_offset)\\s+[^\\s,]+|[^\\s,]+))?" \ |
59 | 12 | "(?:\\s*,\\s*((?:multiplier|post_offset)\\s+[^\\s,]+|[^\\s,]+))?" \ |
60 | 12 | "(?:\\s*,\\s*((?:multiplier|post_offset)\\s+[^\\s,]+|[^\\s,]+))?" \ |
61 | 12 | "\\s*$" |
62 | | |
63 | | static DetectParseRegex parse_regex; |
64 | | |
65 | | static DetectBytejumpData *DetectBytejumpParse( |
66 | | DetectEngineCtx *de_ctx, const char *optstr, char **nbytes, char **offset); |
67 | | static int DetectBytejumpSetup(DetectEngineCtx *de_ctx, Signature *s, const char *optstr); |
68 | | static void DetectBytejumpFree(DetectEngineCtx*, void *ptr); |
69 | | #ifdef UNITTESTS |
70 | | static void DetectBytejumpRegisterTests(void); |
71 | | #endif |
72 | | |
73 | | void DetectBytejumpRegister (void) |
74 | 12 | { |
75 | 12 | sigmatch_table[DETECT_BYTEJUMP].name = "byte_jump"; |
76 | 12 | sigmatch_table[DETECT_BYTEJUMP].desc = "allow the ability to select a <num of bytes> from an <offset> and move the detection pointer to that position"; |
77 | 12 | sigmatch_table[DETECT_BYTEJUMP].url = "/rules/payload-keywords.html#byte-jump"; |
78 | 12 | sigmatch_table[DETECT_BYTEJUMP].Match = NULL; |
79 | 12 | sigmatch_table[DETECT_BYTEJUMP].Setup = DetectBytejumpSetup; |
80 | 12 | sigmatch_table[DETECT_BYTEJUMP].Free = DetectBytejumpFree; |
81 | | #ifdef UNITTESTS |
82 | | sigmatch_table[DETECT_BYTEJUMP].RegisterTests = DetectBytejumpRegisterTests; |
83 | | #endif |
84 | 12 | DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); |
85 | 12 | } |
86 | | |
87 | | /* 23 - This is the largest string (octal, with a zero prefix) that |
88 | | * will not overflow uint64_t. The only way this length |
89 | | * could be over 23 and still not overflow is if it were zero |
90 | | * prefixed and we only support 1 byte of zero prefix for octal. |
91 | | * |
92 | | * "01777777777777777777777" = 0xffffffffffffffff |
93 | | * |
94 | | * 8 - Without string, the maximum byte extract count is 8. |
95 | | */ |
96 | | static inline bool DetectBytejumpValidateNbytesOnly(const DetectBytejumpData *data, int32_t nbytes) |
97 | 65.0k | { |
98 | 65.0k | return nbytes >= 0 && ((data->flags & DETECT_BYTEJUMP_STRING && nbytes <= 23) || (nbytes <= 8)); |
99 | 65.0k | } |
100 | | |
101 | | static bool DetectBytejumpValidateNbytes(const DetectBytejumpData *data, int32_t nbytes) |
102 | 30.7k | { |
103 | 30.7k | if (!DetectBytejumpValidateNbytesOnly(data, nbytes)) { |
104 | 128 | if (data->flags & DETECT_BYTEJUMP_STRING) { |
105 | | /* 23 - This is the largest string (octal, with a zero prefix) that |
106 | | * will not overflow uint64_t. The only way this length |
107 | | * could be over 23 and still not overflow is if it were zero |
108 | | * prefixed and we only support 1 byte of zero prefix for octal. |
109 | | * |
110 | | * "01777777777777777777777" = 0xffffffffffffffff |
111 | | */ |
112 | 20 | if (nbytes > 23) { |
113 | 19 | SCLogError("Cannot test more than 23 bytes " |
114 | 19 | "with \"string\""); |
115 | 19 | } |
116 | 108 | } else { |
117 | 108 | if (nbytes > 8) { |
118 | 104 | SCLogError("Cannot test more than 8 bytes " |
119 | 104 | "without \"string\""); |
120 | 104 | } |
121 | 108 | } |
122 | 128 | return false; |
123 | 128 | } |
124 | | |
125 | 30.6k | return true; |
126 | 30.7k | } |
127 | | |
128 | | /** \brief Byte jump match function |
129 | | * \param det_ctx thread detect engine ctx |
130 | | * \param s signature |
131 | | * \param m byte jump sigmatch |
132 | | * \param payload ptr to the payload |
133 | | * \param payload_len length of the payload |
134 | | * \retval true match |
135 | | * \retval false no match |
136 | | */ |
137 | | bool DetectBytejumpDoMatch(DetectEngineThreadCtx *det_ctx, const Signature *s, |
138 | | const SigMatchCtx *ctx, const uint8_t *payload, uint32_t payload_len, uint16_t flags, |
139 | | int32_t nbytes, int32_t offset) |
140 | 1.08k | { |
141 | 1.08k | SCEnter(); |
142 | | |
143 | 1.08k | const DetectBytejumpData *data = (const DetectBytejumpData *)ctx; |
144 | 1.08k | const uint8_t *ptr = NULL; |
145 | 1.08k | int32_t len = 0; |
146 | 1.08k | uint64_t val = 0; |
147 | 1.08k | int extbytes; |
148 | | |
149 | 1.08k | if (payload_len == 0) { |
150 | 44 | SCReturnBool(false); |
151 | 44 | } |
152 | | |
153 | | /* Validate the number of bytes we are testing |
154 | | * If the validation is successful, we know that |
155 | | * it contains a value <= 23. Thus, we can |
156 | | * safely cast it when extracting bytes |
157 | | */ |
158 | 1.04k | if (data->flags & DETECT_BYTEJUMP_NBYTES_VAR) { |
159 | 644 | if (!DetectBytejumpValidateNbytesOnly(data, nbytes)) { |
160 | 278 | SCLogDebug("Invalid byte_jump nbytes " |
161 | 278 | "seen in byte_jump - %d", |
162 | 278 | nbytes); |
163 | 278 | SCReturnBool(false); |
164 | 278 | } |
165 | 644 | } |
166 | | |
167 | | /* Calculate the ptr value for the bytejump and length remaining in |
168 | | * the packet from that point. |
169 | | */ |
170 | 765 | ptr = payload + offset; |
171 | 765 | len = payload_len - offset; |
172 | 765 | if (flags & DETECT_BYTEJUMP_RELATIVE) { |
173 | 366 | ptr += det_ctx->buffer_offset; |
174 | 366 | len -= det_ctx->buffer_offset; |
175 | | |
176 | 366 | SCLogDebug("[relative] after: ptr %p [len %d]", ptr, len); |
177 | | |
178 | | /* No match if there is no relative base */ |
179 | 366 | if (ptr == NULL || (nbytes && len <= 0)) { |
180 | 3 | SCReturnBool(false); |
181 | 3 | } |
182 | 366 | } |
183 | | |
184 | | /* Verify the to-be-extracted data is within the packet */ |
185 | 762 | if (ptr < payload || nbytes > len) { |
186 | 141 | SCLogDebug("Data not within payload " |
187 | 141 | "pkt=%p, ptr=%p, len=%" PRIi32 ", nbytes=%" PRIi32, |
188 | 141 | payload, ptr, len, nbytes); |
189 | 141 | SCReturnBool(false); |
190 | 141 | } |
191 | | |
192 | | /* Extract the byte data */ |
193 | 621 | if (flags & DETECT_BYTEJUMP_STRING) { |
194 | 258 | extbytes = ByteExtractStringUint64(&val, data->base, nbytes, (const char *)ptr); |
195 | 258 | if(extbytes <= 0) { |
196 | 165 | SCLogDebug("error extracting %d bytes of string data: %d", nbytes, extbytes); |
197 | 165 | SCReturnBool(false); |
198 | 165 | } |
199 | 258 | } |
200 | 363 | else { |
201 | 363 | int endianness = (flags & DETECT_BYTEJUMP_LITTLE) ? BYTE_LITTLE_ENDIAN : BYTE_BIG_ENDIAN; |
202 | 363 | extbytes = ByteExtractUint64(&val, endianness, (uint16_t)nbytes, ptr); |
203 | 363 | if (extbytes != nbytes) { |
204 | 0 | SCLogDebug("error extracting %d bytes of numeric data: %d", nbytes, extbytes); |
205 | 0 | SCReturnBool(false); |
206 | 0 | } |
207 | 363 | } |
208 | | |
209 | 456 | SCLogDebug("VAL: (%" PRIu64 " x %" PRIu32 ") + %" PRIi32 " + %" PRId32, val, data->multiplier, |
210 | 456 | extbytes, data->post_offset); |
211 | | |
212 | | /* Adjust the jump value based on flags */ |
213 | 456 | val *= data->multiplier; |
214 | 456 | if (flags & DETECT_BYTEJUMP_ALIGN) { |
215 | 0 | if ((val % 4) != 0) { |
216 | 0 | val += 4 - (val % 4); |
217 | 0 | } |
218 | 0 | } |
219 | 456 | val += data->post_offset; |
220 | 456 | SCLogDebug("val: %" PRIi64 " post_offset: %" PRIi32, val, data->post_offset); |
221 | | |
222 | 456 | const uint8_t *jumpptr; |
223 | | /* Calculate the jump location */ |
224 | 456 | if (flags & DETECT_BYTEJUMP_BEGIN) { |
225 | 0 | jumpptr = payload + (int64_t)val; |
226 | 0 | SCLogDebug("NEWVAL: payload %p + %" PRIi64 " = %p", payload, (int64_t)val, jumpptr + val); |
227 | 456 | } else if (flags & DETECT_BYTEJUMP_END) { |
228 | 0 | jumpptr = payload + payload_len + (int64_t)val; |
229 | 0 | SCLogDebug( |
230 | 0 | "NEWVAL: payload %p + %" PRIu32 " + %" PRIi64, payload, payload_len, (int64_t)val); |
231 | 456 | } else { |
232 | 456 | jumpptr = ptr + (int64_t)val + extbytes; |
233 | 456 | SCLogDebug("NEWVAL: ptr %p + %" PRIi64 " = %p", ptr, val, jumpptr); |
234 | 456 | } |
235 | | |
236 | | /* Validate that the jump location is still in the packet |
237 | | * \todo Should this validate it is still in the *payload*? |
238 | | */ |
239 | 456 | if (jumpptr < payload) { |
240 | 0 | jumpptr = payload; |
241 | 0 | SCLogDebug("jump location is before buffer start; resetting to buffer start"); |
242 | 456 | } else if (jumpptr > (payload + payload_len)) { |
243 | 20 | SCLogDebug("Jump location (%" PRIu64 ") is not within payload (%" PRIu32 ")", |
244 | 20 | payload_len + val, payload_len); |
245 | 20 | SCReturnBool(false); |
246 | 20 | } |
247 | | |
248 | | #ifdef DEBUG |
249 | | if (SCLogDebugEnabled()) { |
250 | | const uint8_t *sptr = (flags & DETECT_BYTEJUMP_BEGIN) ? payload : ptr; |
251 | | SCLogDebug("jumping %" PRId64 " bytes from %p (%08x)", val, sptr, (int)(sptr - payload)); |
252 | | } |
253 | | #endif /* DEBUG */ |
254 | | |
255 | | /* Adjust the detection context to the jump location. */ |
256 | 436 | DEBUG_VALIDATE_BUG_ON(jumpptr < payload); |
257 | 436 | det_ctx->buffer_offset = (uint32_t)(jumpptr - payload); |
258 | | |
259 | 436 | SCReturnBool(true); |
260 | 436 | } |
261 | | |
262 | | static DetectBytejumpData *DetectBytejumpParse( |
263 | | DetectEngineCtx *de_ctx, const char *optstr, char **nbytes_str, char **offset) |
264 | 13.4k | { |
265 | 13.4k | DetectBytejumpData *data = NULL; |
266 | 13.4k | char args[10][64]; |
267 | 13.4k | int res = 0; |
268 | 13.4k | size_t pcre2len; |
269 | 13.4k | int numargs = 0; |
270 | 13.4k | int i = 0; |
271 | 13.4k | uint32_t nbytes = 0; |
272 | 13.4k | char *str_ptr; |
273 | 13.4k | char *end_ptr; |
274 | 13.4k | pcre2_match_data *match = NULL; |
275 | | |
276 | 13.4k | memset(args, 0x00, sizeof(args)); |
277 | | |
278 | | /* Execute the regex and populate args with captures. */ |
279 | 13.4k | int ret = DetectParsePcreExec(&parse_regex, &match, optstr, 0, 0); |
280 | 13.4k | if (ret < 2 || ret > 10) { |
281 | 771 | SCLogError("parse error, ret %" PRId32 ", string \"%s\"", ret, optstr); |
282 | 771 | goto error; |
283 | 771 | } |
284 | | |
285 | | /* The first two arguments are stashed in the first PCRE substring. |
286 | | * This is because byte_jump can take 10 arguments, but PCRE only |
287 | | * supports 9 substrings, sigh. |
288 | | */ |
289 | 12.6k | char str[512] = ""; |
290 | 12.6k | pcre2len = sizeof(str); |
291 | 12.6k | res = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)str, &pcre2len); |
292 | 12.6k | if (res < 0) { |
293 | 20 | SCLogError("pcre2_substring_copy_bynumber failed " |
294 | 20 | "for arg 1"); |
295 | 20 | goto error; |
296 | 20 | } |
297 | | |
298 | | /* Break up first substring into two parameters |
299 | | * |
300 | | * NOTE: Because of this, we cannot free args[1] as it is part of args[0], |
301 | | * and *yes* this *is* ugly. |
302 | | */ |
303 | 12.6k | end_ptr = str; |
304 | 30.8k | while (!(isspace((unsigned char)*end_ptr) || (*end_ptr == ','))) end_ptr++; |
305 | 12.6k | *(end_ptr++) = '\0'; |
306 | 12.6k | strlcpy(args[0], str, sizeof(args[0])); |
307 | 12.6k | numargs++; |
308 | | |
309 | 12.6k | str_ptr = end_ptr; |
310 | 13.5k | while (isspace((unsigned char)*str_ptr) || (*str_ptr == ',')) str_ptr++; |
311 | 12.6k | end_ptr = str_ptr; |
312 | 35.1k | while (!(isspace((unsigned char)*end_ptr) || (*end_ptr == ',')) && (*end_ptr != '\0')) |
313 | 22.4k | end_ptr++; |
314 | 12.6k | *(end_ptr++) = '\0'; |
315 | 12.6k | strlcpy(args[1], str_ptr, sizeof(args[1])); |
316 | 12.6k | numargs++; |
317 | | |
318 | | /* The remaining args are directly from PCRE substrings */ |
319 | 38.1k | for (i = 1; i < (ret - 1); i++) { |
320 | 25.6k | pcre2len = sizeof(args[0]); |
321 | 25.6k | res = pcre2_substring_copy_bynumber(match, i + 1, (PCRE2_UCHAR8 *)args[i + 1], &pcre2len); |
322 | 25.6k | if (res < 0) { |
323 | 126 | SCLogError("pcre2_substring_copy_bynumber failed for arg %d", i + 1); |
324 | 126 | goto error; |
325 | 126 | } |
326 | 25.4k | numargs++; |
327 | 25.4k | } |
328 | | |
329 | | /* Initialize the data */ |
330 | 12.5k | data = SCMalloc(sizeof(DetectBytejumpData)); |
331 | 12.5k | if (unlikely(data == NULL)) |
332 | 0 | goto error; |
333 | 12.5k | data->base = DETECT_BYTEJUMP_BASE_UNSET; |
334 | 12.5k | data->flags = 0; |
335 | 12.5k | data->multiplier = 1; |
336 | 12.5k | data->post_offset = 0; |
337 | | |
338 | | /* |
339 | | * The first two options are required and positional. The |
340 | | * remaining arguments are flags and are not positional. |
341 | | */ |
342 | | |
343 | | /* Number of bytes */ |
344 | 12.5k | if (args[0][0] != '-' && isalpha((unsigned char)args[0][0])) { |
345 | 430 | if (nbytes_str == NULL) { |
346 | 0 | SCLogError("byte_jump supplied with " |
347 | 0 | "var name for nbytes. \"value\" argument supplied to " |
348 | 0 | "this function has to be non-NULL"); |
349 | 0 | goto error; |
350 | 0 | } |
351 | 430 | *nbytes_str = SCStrdup(args[0]); |
352 | 430 | if (*nbytes_str == NULL) |
353 | 0 | goto error; |
354 | 430 | data->flags |= DETECT_BYTEJUMP_NBYTES_VAR; |
355 | 12.1k | } else { |
356 | 12.1k | if (StringParseUint32(&nbytes, 10, (uint16_t)strlen(args[0]), args[0]) <= 0) { |
357 | 264 | SCLogError("Malformed number of bytes: %s", optstr); |
358 | 264 | goto error; |
359 | 264 | } |
360 | 12.1k | } |
361 | | |
362 | | /* Offset */ |
363 | 12.2k | if (args[1][0] != '-' && isalpha((unsigned char)args[1][0])) { |
364 | 381 | if (offset == NULL) { |
365 | 0 | SCLogError("byte_jump supplied with " |
366 | 0 | "var name for offset. \"value\" argument supplied to " |
367 | 0 | "this function has to be non-NULL"); |
368 | 0 | goto error; |
369 | 0 | } |
370 | 381 | *offset = SCStrdup(args[1]); |
371 | 381 | if (*offset == NULL) |
372 | 0 | goto error; |
373 | 11.8k | } else { |
374 | 11.8k | if (StringParseI32RangeCheck( |
375 | 11.8k | &data->offset, 10, (uint16_t)strlen(args[1]), args[1], -65535, 65535) <= 0) { |
376 | 448 | SCLogError("Malformed offset: %s", optstr); |
377 | 448 | goto error; |
378 | 448 | } |
379 | 11.8k | } |
380 | | |
381 | | /* The remaining options are flags. */ |
382 | | /** \todo Error on dups? */ |
383 | 33.2k | for (i = 2; i < numargs; i++) { |
384 | 22.9k | if (strcmp("relative", args[i]) == 0) { |
385 | 6.82k | data->flags |= DETECT_BYTEJUMP_RELATIVE; |
386 | 16.1k | } else if (strcasecmp("string", args[i]) == 0) { |
387 | 2.49k | data->flags |= DETECT_BYTEJUMP_STRING; |
388 | 13.6k | } else if (strcasecmp("dec", args[i]) == 0) { |
389 | 307 | data->base |= DETECT_BYTEJUMP_BASE_DEC; |
390 | 13.3k | } else if (strcasecmp("hex", args[i]) == 0) { |
391 | 0 | data->base |= DETECT_BYTEJUMP_BASE_HEX; |
392 | 13.3k | } else if (strcasecmp("oct", args[i]) == 0) { |
393 | 0 | data->base |= DETECT_BYTEJUMP_BASE_OCT; |
394 | 13.3k | } else if (strcasecmp("big", args[i]) == 0) { |
395 | 4 | if (data->flags & DETECT_BYTEJUMP_LITTLE) { |
396 | 0 | data->flags ^= DETECT_BYTEJUMP_LITTLE; |
397 | 0 | } |
398 | 4 | data->flags |= DETECT_BYTEJUMP_BIG; |
399 | 13.3k | } else if (strcasecmp("little", args[i]) == 0) { |
400 | 2.80k | data->flags |= DETECT_BYTEJUMP_LITTLE; |
401 | 10.5k | } else if (strcasecmp("from_beginning", args[i]) == 0) { |
402 | 33 | data->flags |= DETECT_BYTEJUMP_BEGIN; |
403 | 10.4k | } else if (strcasecmp("from_end", args[i]) == 0) { |
404 | 2.03k | data->flags |= DETECT_BYTEJUMP_END; |
405 | 8.44k | } else if (strcasecmp("align", args[i]) == 0) { |
406 | 1.80k | data->flags |= DETECT_BYTEJUMP_ALIGN; |
407 | 6.64k | } else if (strncasecmp("multiplier ", args[i], 11) == 0) { |
408 | 38 | if (StringParseU16RangeCheck(&data->multiplier, 10, (uint16_t)strlen(args[i]) - 11, |
409 | 38 | args[i] + 11, 1, 65535) <= 0) { |
410 | 13 | SCLogError("Malformed multiplier: %s", optstr); |
411 | 13 | goto error; |
412 | 13 | } |
413 | 6.60k | } else if (strncasecmp("post_offset ", args[i], 12) == 0) { |
414 | 5.31k | if (StringParseI32RangeCheck(&data->post_offset, 10, (uint16_t)strlen(args[i]) - 12, |
415 | 5.31k | args[i] + 12, -65535, 65535) <= 0) { |
416 | 296 | SCLogError("Malformed post_offset: %s", optstr); |
417 | 296 | goto error; |
418 | 296 | } |
419 | 5.02k | SCLogDebug("post_offset: %s [%d]", optstr, data->post_offset); |
420 | 5.02k | } else if (strcasecmp("dce", args[i]) == 0) { |
421 | 60 | data->flags |= DETECT_BYTEJUMP_DCE; |
422 | 1.22k | } else { |
423 | 1.22k | SCLogError("Unknown option: \"%s\"", args[i]); |
424 | 1.22k | goto error; |
425 | 1.22k | } |
426 | 22.9k | } |
427 | | |
428 | 10.2k | if ((data->flags & DETECT_BYTEJUMP_END) && (data->flags & DETECT_BYTEJUMP_BEGIN)) { |
429 | 1 | SCLogError("'from_end' and 'from_beginning' " |
430 | 1 | "cannot be used in the same byte_jump statement"); |
431 | 1 | goto error; |
432 | 1 | } |
433 | | |
434 | 10.2k | if (!(data->flags & DETECT_BYTEJUMP_NBYTES_VAR)) { |
435 | 10.0k | if (!DetectBytejumpValidateNbytes(data, nbytes)) { |
436 | 88 | goto error; |
437 | 88 | } |
438 | | |
439 | | /* This is max 23 so it will fit in a byte (see validation function) */ |
440 | 10.0k | data->nbytes = (uint8_t)nbytes; |
441 | 10.0k | } |
442 | 10.1k | if (!(data->flags & DETECT_BYTEJUMP_STRING)) { |
443 | 7.95k | if (data->base != DETECT_BYTEJUMP_BASE_UNSET) { |
444 | 11 | SCLogError("Cannot use a base " |
445 | 11 | "without \"string\": %s", |
446 | 11 | optstr); |
447 | 11 | goto error; |
448 | 11 | } |
449 | 7.95k | } |
450 | | |
451 | 10.1k | pcre2_match_data_free(match); |
452 | 10.1k | return data; |
453 | | |
454 | 3.26k | error: |
455 | 3.26k | if (offset != NULL && *offset != NULL) { |
456 | 243 | SCFree(*offset); |
457 | 243 | *offset = NULL; |
458 | 243 | } |
459 | 3.26k | if (nbytes_str != NULL && *nbytes_str != NULL) { |
460 | 238 | SCFree(*nbytes_str); |
461 | 238 | *nbytes_str = NULL; |
462 | 238 | } |
463 | 3.26k | if (data != NULL) |
464 | 2.34k | DetectBytejumpFree(de_ctx, data); |
465 | 3.26k | if (match) { |
466 | 3.26k | pcre2_match_data_free(match); |
467 | 3.26k | } |
468 | 3.26k | return NULL; |
469 | 10.1k | } |
470 | | |
471 | | static int DetectBytejumpSetup(DetectEngineCtx *de_ctx, Signature *s, const char *optstr) |
472 | 42.4k | { |
473 | 42.4k | SigMatch *prev_pm = NULL; |
474 | 42.4k | DetectBytejumpData *data = NULL; |
475 | 42.4k | char *offset = NULL; |
476 | 42.4k | char *nbytes = NULL; |
477 | 42.4k | int ret = -1; |
478 | | |
479 | 42.4k | data = DetectBytejumpParse(de_ctx, optstr, &nbytes, &offset); |
480 | 42.4k | if (data == NULL) |
481 | 11.3k | goto error; |
482 | | |
483 | 31.0k | int sm_list; |
484 | 31.0k | if (s->init_data->list != DETECT_SM_LIST_NOTSET) { |
485 | 5.26k | if (DetectBufferGetActiveList(de_ctx, s) == -1) |
486 | 1 | goto error; |
487 | | |
488 | 5.26k | sm_list = s->init_data->list; |
489 | | |
490 | 5.26k | if (data->flags & DETECT_BYTEJUMP_RELATIVE) { |
491 | 1.84k | prev_pm = DetectGetLastSMFromLists(s, DETECT_CONTENT, DETECT_PCRE, -1); |
492 | 1.84k | } |
493 | 25.8k | } else if (data->flags & DETECT_BYTEJUMP_DCE) { |
494 | 487 | if (data->flags & DETECT_BYTEJUMP_RELATIVE) { |
495 | 135 | prev_pm = DetectGetLastSMFromLists(s, |
496 | 135 | DETECT_CONTENT, DETECT_PCRE, |
497 | 135 | DETECT_BYTETEST, DETECT_BYTEJUMP, DETECT_BYTE_EXTRACT, |
498 | 135 | DETECT_ISDATAAT, DETECT_BYTEMATH, -1); |
499 | 135 | if (prev_pm == NULL) { |
500 | 66 | sm_list = DETECT_SM_LIST_PMATCH; |
501 | 69 | } else { |
502 | 69 | sm_list = SigMatchListSMBelongsTo(s, prev_pm); |
503 | 69 | if (sm_list < 0) |
504 | 0 | goto error; |
505 | 69 | } |
506 | 352 | } else { |
507 | 352 | sm_list = DETECT_SM_LIST_PMATCH; |
508 | 352 | } |
509 | | |
510 | 487 | if (SCDetectSignatureSetAppProto(s, ALPROTO_DCERPC) != 0) |
511 | 267 | goto error; |
512 | | |
513 | 25.3k | } else if (data->flags & DETECT_BYTEJUMP_RELATIVE) { |
514 | 13.8k | prev_pm = DetectGetLastSMFromLists(s, |
515 | 13.8k | DETECT_CONTENT, DETECT_PCRE, |
516 | 13.8k | DETECT_BYTETEST, DETECT_BYTEJUMP, DETECT_BYTE_EXTRACT, |
517 | 13.8k | DETECT_ISDATAAT, DETECT_BYTEMATH, -1); |
518 | 13.8k | if (prev_pm == NULL) { |
519 | 3.16k | sm_list = DETECT_SM_LIST_PMATCH; |
520 | 10.6k | } else { |
521 | 10.6k | sm_list = SigMatchListSMBelongsTo(s, prev_pm); |
522 | 10.6k | if (sm_list < 0) |
523 | 0 | goto error; |
524 | 10.6k | } |
525 | | |
526 | 13.8k | } else { |
527 | 11.4k | sm_list = DETECT_SM_LIST_PMATCH; |
528 | 11.4k | } |
529 | | |
530 | 30.8k | if (data->flags & DETECT_BYTEJUMP_DCE) { |
531 | 490 | if ((data->flags & DETECT_BYTEJUMP_STRING) || |
532 | 426 | (data->flags & DETECT_BYTEJUMP_LITTLE) || |
533 | 426 | (data->flags & DETECT_BYTEJUMP_BIG) || |
534 | 424 | (data->flags & DETECT_BYTEJUMP_BEGIN) || |
535 | 424 | (data->flags & DETECT_BYTEJUMP_END) || |
536 | 380 | (data->base == DETECT_BYTEJUMP_BASE_DEC) || |
537 | 380 | (data->base == DETECT_BYTEJUMP_BASE_HEX) || |
538 | 380 | (data->base == DETECT_BYTEJUMP_BASE_OCT) ) { |
539 | 110 | SCLogError("Invalid option. " |
540 | 110 | "A byte_jump keyword with dce holds other invalid modifiers."); |
541 | 110 | goto error; |
542 | 110 | } |
543 | 490 | } |
544 | | |
545 | 30.7k | if (nbytes != NULL) { |
546 | 547 | DetectByteIndexType index; |
547 | 547 | if (!DetectByteRetrieveSMVar(nbytes, s, sm_list, &index)) { |
548 | 167 | SCLogError("Unknown byte_extract var " |
549 | 167 | "seen in byte_jump - %s", |
550 | 167 | nbytes); |
551 | 167 | goto error; |
552 | 167 | } |
553 | 380 | data->nbytes = index; |
554 | 380 | SCFree(nbytes); |
555 | 380 | nbytes = NULL; |
556 | 380 | } |
557 | | |
558 | 30.5k | if (offset != NULL) { |
559 | 1.84k | DetectByteIndexType index; |
560 | 1.84k | if (!DetectByteRetrieveSMVar(offset, s, sm_list, &index)) { |
561 | 350 | SCLogError("Unknown byte_extract var " |
562 | 350 | "seen in byte_jump - %s", |
563 | 350 | offset); |
564 | 350 | goto error; |
565 | 350 | } |
566 | 1.49k | data->offset = index; |
567 | 1.49k | data->flags |= DETECT_BYTEJUMP_OFFSET_VAR; |
568 | 1.49k | SCFree(offset); |
569 | 1.49k | offset = NULL; |
570 | 1.49k | } |
571 | | |
572 | 30.1k | if (SCSigMatchAppendSMToList(de_ctx, s, DETECT_BYTEJUMP, (SigMatchCtx *)data, sm_list) == |
573 | 30.1k | NULL) { |
574 | 0 | goto error; |
575 | 0 | } |
576 | | |
577 | 30.1k | if (!(data->flags & DETECT_BYTEJUMP_RELATIVE)) |
578 | 14.4k | goto okay; |
579 | | |
580 | 15.7k | if (prev_pm == NULL) |
581 | 4.16k | goto okay; |
582 | | |
583 | 11.5k | if (prev_pm->type == DETECT_CONTENT) { |
584 | 7.89k | DetectContentData *cd = (DetectContentData *)prev_pm->ctx; |
585 | 7.89k | cd->flags |= DETECT_CONTENT_RELATIVE_NEXT; |
586 | 7.89k | } else if (prev_pm->type == DETECT_PCRE) { |
587 | 824 | DetectPcreData *pd = (DetectPcreData *)prev_pm->ctx; |
588 | 824 | pd->flags |= DETECT_PCRE_RELATIVE_NEXT; |
589 | 824 | } |
590 | | |
591 | 30.1k | okay: |
592 | 30.1k | ret = 0; |
593 | 30.1k | return ret; |
594 | | |
595 | 12.2k | error: |
596 | 12.2k | if (nbytes != NULL) { |
597 | 168 | SCFree(nbytes); |
598 | 168 | } |
599 | 12.2k | if (offset != NULL) { |
600 | 484 | SCFree(offset); |
601 | 484 | } |
602 | 12.2k | DetectBytejumpFree(de_ctx, data); |
603 | 12.2k | return ret; |
604 | 11.5k | } |
605 | | |
606 | | /** |
607 | | * \brief this function will free memory associated with DetectBytejumpData |
608 | | * |
609 | | * \param data pointer to DetectBytejumpData |
610 | | */ |
611 | | static void DetectBytejumpFree(DetectEngineCtx *de_ctx, void *ptr) |
612 | 51.5k | { |
613 | 51.5k | if (ptr == NULL) |
614 | 11.3k | return; |
615 | | |
616 | 40.2k | DetectBytejumpData *data = (DetectBytejumpData *)ptr; |
617 | 40.2k | SCFree(data); |
618 | 40.2k | } |
619 | | |
620 | | |
621 | | /* UNITTESTS */ |
622 | | #ifdef UNITTESTS |
623 | | #include "util-unittest-helper.h" |
624 | | static int g_file_data_buffer_id = 0; |
625 | | static int g_dce_stub_data_buffer_id = 0; |
626 | | |
627 | | /** |
628 | | * \test DetectBytejumpTestParse01 is a test to make sure that we return |
629 | | * "something" when given valid bytejump opt |
630 | | */ |
631 | | static int DetectBytejumpTestParse01(void) |
632 | | { |
633 | | DetectBytejumpData *data = NULL; |
634 | | data = DetectBytejumpParse(NULL, "4,0", NULL, NULL); |
635 | | FAIL_IF_NULL(data); |
636 | | |
637 | | DetectBytejumpFree(NULL, data); |
638 | | PASS; |
639 | | } |
640 | | |
641 | | /** |
642 | | * \test DetectBytejumpTestParse02 is a test for setting the required opts |
643 | | */ |
644 | | static int DetectBytejumpTestParse02(void) |
645 | | { |
646 | | DetectBytejumpData *data = NULL; |
647 | | data = DetectBytejumpParse(NULL, "4, 0", NULL, NULL); |
648 | | FAIL_IF_NULL(data); |
649 | | FAIL_IF_NOT(data->nbytes == 4); |
650 | | FAIL_IF_NOT(data->offset == 0); |
651 | | FAIL_IF_NOT(data->multiplier == 1); |
652 | | FAIL_IF_NOT(data->post_offset == 0); |
653 | | FAIL_IF_NOT(data->flags == 0); |
654 | | FAIL_IF_NOT(data->base == DETECT_BYTEJUMP_BASE_UNSET); |
655 | | |
656 | | DetectBytejumpFree(NULL, data); |
657 | | PASS; |
658 | | } |
659 | | |
660 | | /** |
661 | | * \test DetectBytejumpTestParse03 is a test for setting the optional flags |
662 | | */ |
663 | | static int DetectBytejumpTestParse03(void) |
664 | | { |
665 | | DetectBytejumpData *data = NULL; |
666 | | data = DetectBytejumpParse(NULL, |
667 | | " 4,0 , relative , little, string, " |
668 | | "dec, align, from_beginning", |
669 | | NULL, NULL); |
670 | | FAIL_IF_NULL(data); |
671 | | FAIL_IF_NOT(data->nbytes == 4); |
672 | | FAIL_IF_NOT(data->offset == 0); |
673 | | FAIL_IF_NOT(data->multiplier == 1); |
674 | | FAIL_IF_NOT(data->post_offset == 0); |
675 | | FAIL_IF_NOT(data->flags == |
676 | | (DETECT_BYTEJUMP_RELATIVE | DETECT_BYTEJUMP_LITTLE | DETECT_BYTEJUMP_STRING | |
677 | | DETECT_BYTEJUMP_ALIGN | DETECT_BYTEJUMP_BEGIN)); |
678 | | FAIL_IF_NOT(data->base == DETECT_BYTEJUMP_BASE_DEC); |
679 | | |
680 | | DetectBytejumpFree(NULL, data); |
681 | | PASS; |
682 | | } |
683 | | |
684 | | /** |
685 | | * \test DetectBytejumpTestParse04 is a test for setting the optional flags |
686 | | * with parameters |
687 | | * |
688 | | * \todo This fails because we can only have 9 captures and there are 10. |
689 | | */ |
690 | | static int DetectBytejumpTestParse04(void) |
691 | | { |
692 | | DetectBytejumpData *data = NULL; |
693 | | data = DetectBytejumpParse(NULL, |
694 | | " 4,0 , relative , little, string, " |
695 | | "dec, align, from_beginning , " |
696 | | "multiplier 2 , post_offset -16 ", |
697 | | NULL, NULL); |
698 | | FAIL_IF_NULL(data); |
699 | | FAIL_IF_NOT(data->nbytes == 4); |
700 | | FAIL_IF_NOT(data->offset == 0); |
701 | | FAIL_IF_NOT(data->multiplier == 2); |
702 | | FAIL_IF_NOT(data->post_offset == -16); |
703 | | FAIL_IF_NOT(data->flags == |
704 | | (DETECT_BYTEJUMP_RELATIVE | DETECT_BYTEJUMP_LITTLE | DETECT_BYTEJUMP_ALIGN | |
705 | | DETECT_BYTEJUMP_STRING | DETECT_BYTEJUMP_BEGIN)); |
706 | | FAIL_IF_NOT(data->base == DETECT_BYTEJUMP_BASE_DEC); |
707 | | |
708 | | DetectBytejumpFree(NULL, data); |
709 | | PASS; |
710 | | } |
711 | | |
712 | | /** |
713 | | * \test DetectBytejumpTestParse05 is a test for setting base without string |
714 | | */ |
715 | | static int DetectBytejumpTestParse05(void) |
716 | | { |
717 | | DetectBytejumpData *data = NULL; |
718 | | data = DetectBytejumpParse(NULL, |
719 | | " 4,0 , relative , little, dec, " |
720 | | "align, from_beginning", |
721 | | NULL, NULL); |
722 | | FAIL_IF_NOT_NULL(data); |
723 | | |
724 | | PASS; |
725 | | } |
726 | | |
727 | | /** |
728 | | * \test DetectBytejumpTestParse06 is a test for too many bytes to extract |
729 | | */ |
730 | | static int DetectBytejumpTestParse06(void) |
731 | | { |
732 | | DetectBytejumpData *data = NULL; |
733 | | data = DetectBytejumpParse(NULL, "9, 0", NULL, NULL); |
734 | | FAIL_IF_NOT_NULL(data); |
735 | | |
736 | | PASS; |
737 | | } |
738 | | |
739 | | /** |
740 | | * \test DetectBytejumpTestParse07 is a test for too many string bytes to extract |
741 | | */ |
742 | | static int DetectBytejumpTestParse07(void) |
743 | | { |
744 | | DetectBytejumpData *data = NULL; |
745 | | data = DetectBytejumpParse(NULL, "24, 0, string, dec", NULL, NULL); |
746 | | FAIL_IF_NOT_NULL(data); |
747 | | |
748 | | PASS; |
749 | | } |
750 | | |
751 | | /** |
752 | | * \test DetectBytejumpTestParse08 is a test for offset too big |
753 | | */ |
754 | | static int DetectBytejumpTestParse08(void) |
755 | | { |
756 | | DetectBytejumpData *data = NULL; |
757 | | data = DetectBytejumpParse(NULL, "4, 0xffffffffffffffff", NULL, NULL); |
758 | | FAIL_IF_NOT_NULL(data); |
759 | | |
760 | | PASS; |
761 | | } |
762 | | |
763 | | /** |
764 | | * \test Test dce option. |
765 | | */ |
766 | | static int DetectBytejumpTestParse09(void) |
767 | | { |
768 | | Signature *s = SigAlloc(); |
769 | | FAIL_IF_NULL(s); |
770 | | |
771 | | FAIL_IF(SCDetectSignatureSetAppProto(s, ALPROTO_DCERPC) < 0); |
772 | | |
773 | | FAIL_IF_NOT(DetectBytejumpSetup(NULL, s, |
774 | | "4,0, align, multiplier 2, " |
775 | | "post_offset -16,dce") == 0); |
776 | | FAIL_IF_NOT(DetectBytejumpSetup(NULL, s, |
777 | | "4,0, multiplier 2, " |
778 | | "post_offset -16,dce") == 0); |
779 | | FAIL_IF_NOT(DetectBytejumpSetup(NULL, s, "4,0,post_offset -16,dce") == 0); |
780 | | FAIL_IF_NOT(DetectBytejumpSetup(NULL, s, "4,0,dce") == 0); |
781 | | FAIL_IF_NOT(DetectBytejumpSetup(NULL, s, "4,0,dce") == 0); |
782 | | FAIL_IF_NOT(DetectBytejumpSetup(NULL, s, "4,0, string, dce") == -1); |
783 | | FAIL_IF_NOT(DetectBytejumpSetup(NULL, s, "4,0, big, dce") == -1); |
784 | | FAIL_IF_NOT(DetectBytejumpSetup(NULL, s, "4,0, little, dce") == -1); |
785 | | FAIL_IF_NOT(DetectBytejumpSetup(NULL, s, "4,0, string, dec, dce") == -1); |
786 | | FAIL_IF_NOT(DetectBytejumpSetup(NULL, s, "4,0, string, oct, dce") == -1); |
787 | | FAIL_IF_NOT(DetectBytejumpSetup(NULL, s, "4,0, string, hex, dce") == -1); |
788 | | FAIL_IF_NOT(DetectBytejumpSetup(NULL, s, "4,0, from_beginning, dce") == -1); |
789 | | |
790 | | FAIL_IF_NULL(s->init_data->smlists[DETECT_SM_LIST_PMATCH]); |
791 | | SigMatch *sm = DetectBufferGetFirstSigMatch(s, g_dce_stub_data_buffer_id); |
792 | | FAIL_IF_NOT_NULL(sm); |
793 | | |
794 | | SigFree(NULL, s); |
795 | | PASS; |
796 | | } |
797 | | |
798 | | /** |
799 | | * \test Test dce option. |
800 | | */ |
801 | | static int DetectBytejumpTestParse10(void) |
802 | | { |
803 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
804 | | FAIL_IF_NULL(de_ctx); |
805 | | de_ctx->flags |= DE_QUIET; |
806 | | |
807 | | Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " |
808 | | "(msg:\"Testing bytejump_body\"; " |
809 | | "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " |
810 | | "dce_stub_data; " |
811 | | "content:\"one\"; distance:0; " |
812 | | "byte_jump:4,0,align,multiplier 2, " |
813 | | "post_offset -16,relative,dce; sid:1;)"); |
814 | | FAIL_IF_NULL(s); |
815 | | SigMatch *sm = DetectBufferGetFirstSigMatch(s, g_dce_stub_data_buffer_id); |
816 | | FAIL_IF_NULL(sm); |
817 | | FAIL_IF_NOT(sm->type == DETECT_CONTENT); |
818 | | FAIL_IF_NULL(sm->next); |
819 | | sm = sm->next; |
820 | | FAIL_IF_NOT(sm->type == DETECT_BYTEJUMP); |
821 | | |
822 | | DetectBytejumpData *bd = (DetectBytejumpData *)sm->ctx; |
823 | | FAIL_IF_NOT(bd->flags & DETECT_BYTEJUMP_DCE); |
824 | | FAIL_IF_NOT(bd->flags & DETECT_BYTEJUMP_RELATIVE); |
825 | | FAIL_IF(bd->flags & DETECT_BYTEJUMP_STRING); |
826 | | FAIL_IF(bd->flags & DETECT_BYTEJUMP_BIG); |
827 | | FAIL_IF(bd->flags & DETECT_BYTEJUMP_LITTLE); |
828 | | |
829 | | s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " |
830 | | "(msg:\"Testing bytejump_body\"; " |
831 | | "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " |
832 | | "dce_stub_data; " |
833 | | "content:\"one\"; distance:0; " |
834 | | "byte_jump:4,0,align,multiplier 2, " |
835 | | "post_offset -16,relative,dce; sid:2;)"); |
836 | | FAIL_IF_NULL(s); |
837 | | sm = DetectBufferGetFirstSigMatch(s, g_dce_stub_data_buffer_id); |
838 | | FAIL_IF_NULL(sm); |
839 | | |
840 | | FAIL_IF_NOT(sm->type == DETECT_CONTENT); |
841 | | FAIL_IF_NULL(sm->next); |
842 | | sm = sm->next; |
843 | | FAIL_IF_NOT(sm->type == DETECT_BYTEJUMP); |
844 | | |
845 | | bd = (DetectBytejumpData *)sm->ctx; |
846 | | FAIL_IF_NOT(bd->flags & DETECT_BYTEJUMP_DCE); |
847 | | FAIL_IF_NOT(bd->flags & DETECT_BYTEJUMP_RELATIVE); |
848 | | FAIL_IF(bd->flags & DETECT_BYTEJUMP_STRING); |
849 | | FAIL_IF(bd->flags & DETECT_BYTEJUMP_BIG); |
850 | | FAIL_IF(bd->flags & DETECT_BYTEJUMP_LITTLE); |
851 | | |
852 | | s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " |
853 | | "(msg:\"Testing bytejump_body\"; " |
854 | | "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " |
855 | | "dce_stub_data; " |
856 | | "content:\"one\"; distance:0; " |
857 | | "byte_jump:4,0,align,multiplier 2, " |
858 | | "post_offset -16,relative; sid:3;)"); |
859 | | FAIL_IF_NULL(s); |
860 | | sm = DetectBufferGetFirstSigMatch(s, g_dce_stub_data_buffer_id); |
861 | | FAIL_IF_NULL(sm); |
862 | | |
863 | | FAIL_IF_NOT(sm->type == DETECT_CONTENT); |
864 | | FAIL_IF_NULL(sm->next); |
865 | | sm = sm->next; |
866 | | FAIL_IF_NOT(sm->type == DETECT_BYTEJUMP); |
867 | | |
868 | | bd = (DetectBytejumpData *)sm->ctx; |
869 | | FAIL_IF(bd->flags & DETECT_BYTEJUMP_DCE); |
870 | | FAIL_IF_NOT(bd->flags & DETECT_BYTEJUMP_RELATIVE); |
871 | | FAIL_IF(bd->flags & DETECT_BYTEJUMP_STRING); |
872 | | FAIL_IF(bd->flags & DETECT_BYTEJUMP_BIG); |
873 | | FAIL_IF(bd->flags & DETECT_BYTEJUMP_LITTLE); |
874 | | |
875 | | DetectEngineCtxFree(de_ctx); |
876 | | PASS; |
877 | | } |
878 | | |
879 | | /** |
880 | | * \test Test dce option. |
881 | | */ |
882 | | static int DetectBytejumpTestParse11(void) |
883 | | { |
884 | | DetectEngineCtx *de_ctx = NULL; |
885 | | Signature *s = NULL; |
886 | | |
887 | | de_ctx = DetectEngineCtxInit(); |
888 | | FAIL_IF_NULL(de_ctx); |
889 | | |
890 | | de_ctx->flags |= DE_QUIET; |
891 | | s = SigInit(de_ctx, "alert tcp any any -> any any " |
892 | | "(msg:\"Testing bytejump_body\"; " |
893 | | "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " |
894 | | "dce_stub_data; " |
895 | | "content:\"one\"; byte_jump:4,0,align,multiplier 2, " |
896 | | "post_offset -16,string,dce; sid:1;)"); |
897 | | FAIL_IF_NOT_NULL(s); |
898 | | |
899 | | s = SigInit(de_ctx, "alert tcp any any -> any any " |
900 | | "(msg:\"Testing bytejump_body\"; " |
901 | | "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " |
902 | | "dce_sub_data; " |
903 | | "content:\"one\"; byte_jump:4,0,align,multiplier 2, " |
904 | | "post_offset -16,big,dce; sid:1;)"); |
905 | | FAIL_IF_NOT_NULL(s); |
906 | | |
907 | | s = SigInit(de_ctx, "alert tcp any any -> any any " |
908 | | "(msg:\"Testing bytejump_body\"; " |
909 | | "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " |
910 | | "dce_stub_data; " |
911 | | "content:\"one\"; byte_jump:4,0,align,multiplier 2, " |
912 | | "post_offset -16,little,dce; sid:1;)"); |
913 | | FAIL_IF_NOT_NULL(s); |
914 | | |
915 | | s = SigInit(de_ctx, "alert tcp any any -> any any " |
916 | | "(msg:\"Testing bytejump_body\"; " |
917 | | "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " |
918 | | "dce_stub_data; " |
919 | | "content:\"one\"; byte_jump:4,0,align,multiplier 2, " |
920 | | "post_offset -16,string,hex,dce; sid:1;)"); |
921 | | FAIL_IF_NOT_NULL(s); |
922 | | |
923 | | s = SigInit(de_ctx, "alert tcp any any -> any any " |
924 | | "(msg:\"Testing bytejump_body\"; " |
925 | | "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " |
926 | | "dce_stub_data; " |
927 | | "content:\"one\"; byte_jump:4,0,align,multiplier 2, " |
928 | | "post_offset -16,string,dec,dce; sid:1;)"); |
929 | | FAIL_IF_NOT_NULL(s); |
930 | | |
931 | | s = SigInit(de_ctx, "alert tcp any any -> any any " |
932 | | "(msg:\"Testing bytejump_body\"; " |
933 | | "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " |
934 | | "dce_stub_data; " |
935 | | "content:\"one\"; byte_jump:4,0,align,multiplier 2, " |
936 | | "post_offset -16,string,oct,dce; sid:1;)"); |
937 | | FAIL_IF_NOT_NULL(s); |
938 | | |
939 | | s = SigInit(de_ctx, "alert tcp any any -> any any " |
940 | | "(msg:\"Testing bytejump_body\"; " |
941 | | "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " |
942 | | "dce_stub_data; " |
943 | | "content:\"one\"; byte_jump:4,0,align,multiplier 2, " |
944 | | "post_offset -16,from_beginning,dce; sid:1;)"); |
945 | | FAIL_IF_NOT_NULL(s); |
946 | | |
947 | | SigGroupCleanup(de_ctx); |
948 | | SigCleanSignatures(de_ctx); |
949 | | DetectEngineCtxFree(de_ctx); |
950 | | PASS; |
951 | | } |
952 | | |
953 | | /** |
954 | | * \test Test file_data |
955 | | */ |
956 | | static int DetectBytejumpTestParse12(void) |
957 | | { |
958 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
959 | | FAIL_IF_NULL(de_ctx); |
960 | | de_ctx->flags |= DE_QUIET; |
961 | | |
962 | | Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " |
963 | | "(file_data; byte_jump:4,0,align,multiplier 2, " |
964 | | "post_offset -16,relative; sid:1;)"); |
965 | | FAIL_IF_NULL(s); |
966 | | |
967 | | SigMatch *sm = DetectBufferGetFirstSigMatch(s, g_file_data_buffer_id); |
968 | | FAIL_IF_NULL(sm); |
969 | | FAIL_IF_NOT(sm->type == DETECT_BYTEJUMP); |
970 | | |
971 | | DetectBytejumpData *bd = (DetectBytejumpData *)sm->ctx; |
972 | | FAIL_IF(bd->flags & DETECT_BYTEJUMP_DCE); |
973 | | FAIL_IF((bd->flags & |
974 | | (DETECT_BYTEJUMP_RELATIVE | DETECT_BYTEJUMP_STRING | DETECT_BYTEJUMP_BIG)) == |
975 | | (DETECT_BYTEJUMP_RELATIVE | DETECT_BYTEJUMP_STRING | DETECT_BYTEJUMP_BIG)); |
976 | | |
977 | | DetectEngineCtxFree(de_ctx); |
978 | | PASS; |
979 | | } |
980 | | |
981 | | static int DetectBytejumpTestParse13(void) |
982 | | { |
983 | | DetectBytejumpData *data = DetectBytejumpParse(NULL, |
984 | | " 4,0 , relative , little, string, dec, " |
985 | | "align, from_end", |
986 | | NULL, NULL); |
987 | | FAIL_IF_NULL(data); |
988 | | FAIL_IF_NOT(data->flags & DETECT_BYTEJUMP_END); |
989 | | |
990 | | DetectBytejumpFree(NULL, data); |
991 | | |
992 | | PASS; |
993 | | } |
994 | | |
995 | | static int DetectBytejumpTestParse14(void) |
996 | | { |
997 | | DetectBytejumpData *data = DetectBytejumpParse(NULL, |
998 | | " 4,0 , relative , little, string, dec, " |
999 | | "align, from_beginning, from_end", |
1000 | | NULL, NULL); |
1001 | | |
1002 | | FAIL_IF_NOT_NULL(data); |
1003 | | |
1004 | | PASS; |
1005 | | } |
1006 | | |
1007 | | /** |
1008 | | * \test DetectByteJumpTestPacket01 is a test to check matches of |
1009 | | * byte_jump and byte_jump relative works if the previous keyword is pcre |
1010 | | * (bug 142) |
1011 | | */ |
1012 | | static int DetectByteJumpTestPacket01 (void) |
1013 | | { |
1014 | | uint8_t *buf = (uint8_t *)"GET /AllWorkAndNoPlayMakesWillADullBoy HTTP/1.0" |
1015 | | "User-Agent: Wget/1.11.4" |
1016 | | "Accept: */*" |
1017 | | "Host: www.google.com" |
1018 | | "Connection: Keep-Alive" |
1019 | | "Date: Mon, 04 Jan 2010 17:29:39 GMT"; |
1020 | | uint16_t buflen = strlen((char *)buf); |
1021 | | Packet *p; |
1022 | | p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); |
1023 | | |
1024 | | FAIL_IF_NULL(p); |
1025 | | |
1026 | | char sig[] = "alert tcp any any -> any any (msg:\"pcre + byte_test + " |
1027 | | "relative\"; pcre:\"/AllWorkAndNoPlayMakesWillADullBoy/\"; byte_jump:1,6," |
1028 | | "relative,string,dec; content:\"0\"; sid:134; rev:1;)"; |
1029 | | |
1030 | | FAIL_IF_NOT(UTHPacketMatchSig(p, sig)); |
1031 | | |
1032 | | UTHFreePacket(p); |
1033 | | PASS; |
1034 | | } |
1035 | | |
1036 | | /** |
1037 | | * \test DetectByteJumpTestPacket02 is a test to check matches of |
1038 | | * byte_jump and byte_jump relative works if the previous keyword is byte_jump |
1039 | | * (bug 165) |
1040 | | */ |
1041 | | static int DetectByteJumpTestPacket02 (void) |
1042 | | { |
1043 | | uint8_t buf[] = { 0x00, 0x00, 0x00, 0x77, 0xff, 0x53, |
1044 | | 0x4d, 0x42, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x18, |
1045 | | 0x01, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1046 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, |
1047 | | 0x92, 0xa4, 0x01, 0x08, 0x17, 0x5c, 0x0e, 0xff, |
1048 | | 0x00, 0x00, 0x00, 0x01, 0x40, 0x48, 0x00, 0x00, |
1049 | | 0x00, 0xff }; |
1050 | | uint16_t buflen = sizeof(buf); |
1051 | | Packet *p; |
1052 | | p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); |
1053 | | |
1054 | | FAIL_IF_NULL(p); |
1055 | | |
1056 | | char sig[] = "alert tcp any any -> any any (msg:\"byte_jump with byte_jump" |
1057 | | " + relative\"; byte_jump:1,13; byte_jump:4,0,relative; " |
1058 | | "content:\"|48 00 00|\"; within:3; sid:144; rev:1;)"; |
1059 | | |
1060 | | FAIL_IF_NOT(UTHPacketMatchSig(p, sig)); |
1061 | | |
1062 | | UTHFreePacket(p); |
1063 | | PASS; |
1064 | | } |
1065 | | |
1066 | | static int DetectByteJumpTestPacket03(void) |
1067 | | { |
1068 | | uint8_t *buf = NULL; |
1069 | | uint16_t buflen = 0; |
1070 | | buf = SCMalloc(4); |
1071 | | if (unlikely(buf == NULL)) { |
1072 | | printf("malloc failed\n"); |
1073 | | exit(EXIT_FAILURE); |
1074 | | } |
1075 | | memcpy(buf, "boom", 4); |
1076 | | buflen = 4; |
1077 | | |
1078 | | Packet *p; |
1079 | | p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); |
1080 | | |
1081 | | FAIL_IF_NULL(p); |
1082 | | |
1083 | | char sig[] = "alert tcp any any -> any any (msg:\"byte_jump\"; " |
1084 | | "byte_jump:1,214748364; sid:1; rev:1;)"; |
1085 | | |
1086 | | FAIL_IF(UTHPacketMatchSig(p, sig)); |
1087 | | |
1088 | | UTHFreePacket(p); |
1089 | | FAIL_IF_NULL(buf); |
1090 | | |
1091 | | SCFree(buf); |
1092 | | PASS; |
1093 | | } |
1094 | | |
1095 | | /** |
1096 | | * \test check matches of with from_beginning (bug 626/627) |
1097 | | */ |
1098 | | static int DetectByteJumpTestPacket04 (void) |
1099 | | { |
1100 | | uint8_t *buf = (uint8_t *)"XYZ04abcdABCD"; |
1101 | | uint16_t buflen = strlen((char *)buf); |
1102 | | Packet *p; |
1103 | | p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); |
1104 | | |
1105 | | FAIL_IF_NULL(p); |
1106 | | |
1107 | | char sig[] = "alert tcp any any -> any any (content:\"XYZ\"; byte_jump:2,0,relative,string,dec; content:\"ABCD\"; distance:0; within:4; sid:1; rev:1;)"; |
1108 | | |
1109 | | FAIL_IF_NOT(UTHPacketMatchSig(p, sig)); |
1110 | | |
1111 | | UTHFreePacket(p); |
1112 | | PASS; |
1113 | | } |
1114 | | |
1115 | | /** |
1116 | | * \test check matches of with from_beginning (bug 626/627) |
1117 | | */ |
1118 | | static int DetectByteJumpTestPacket05 (void) |
1119 | | { |
1120 | | uint8_t *buf = (uint8_t *)"XYZ04abcdABCD"; |
1121 | | uint16_t buflen = strlen((char *)buf); |
1122 | | Packet *p; |
1123 | | p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); |
1124 | | |
1125 | | FAIL_IF_NULL(p); |
1126 | | |
1127 | | char sig[] = "alert tcp any any -> any any (content:\"XYZ\"; byte_jump:2,0,relative,string,dec; content:\"cdABCD\"; within:6; sid:1; rev:1;)"; |
1128 | | |
1129 | | FAIL_IF_NOT(UTHPacketMatchSig(p, sig) ? 0 : 1); |
1130 | | |
1131 | | UTHFreePacket(p); |
1132 | | PASS; |
1133 | | } |
1134 | | |
1135 | | /** |
1136 | | * \test check matches of with from_beginning (bug 626/627) |
1137 | | */ |
1138 | | static int DetectByteJumpTestPacket06 (void) |
1139 | | { |
1140 | | uint8_t *buf = (uint8_t *)"XX04abcdABCD"; |
1141 | | uint16_t buflen = strlen((char *)buf); |
1142 | | Packet *p; |
1143 | | p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); |
1144 | | |
1145 | | FAIL_IF_NULL(p); |
1146 | | |
1147 | | char sig[] = "alert tcp any any -> any any (content:\"XX\"; byte_jump:2,0,relative,string,dec,from_beginning; content:\"ABCD\"; distance:4; within:4; sid:1; rev:1;)"; |
1148 | | |
1149 | | FAIL_IF_NOT(UTHPacketMatchSig(p, sig)); |
1150 | | |
1151 | | UTHFreePacket(p); |
1152 | | PASS; |
1153 | | } |
1154 | | |
1155 | | /** |
1156 | | * \test check matches of with from_beginning (bug 626/627) |
1157 | | */ |
1158 | | static int DetectByteJumpTestPacket07 (void) |
1159 | | { |
1160 | | uint8_t *buf = (uint8_t *)"XX04abcdABCD"; |
1161 | | uint16_t buflen = strlen((char *)buf); |
1162 | | Packet *p; |
1163 | | p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); |
1164 | | |
1165 | | FAIL_IF_NULL(p); |
1166 | | |
1167 | | char sig[] = "alert tcp any any -> any any (content:\"XX\"; byte_jump:2,0,relative,string,dec,from_beginning; content:\"abcdABCD\"; distance:0; within:8; sid:1; rev:1;)"; |
1168 | | |
1169 | | FAIL_IF_NOT(UTHPacketMatchSig(p, sig) ? 1 : 0); |
1170 | | |
1171 | | UTHFreePacket(p); |
1172 | | PASS; |
1173 | | } |
1174 | | |
1175 | | /** |
1176 | | * \test check matches of with from_end |
1177 | | */ |
1178 | | static int DetectByteJumpTestPacket08 (void) |
1179 | | { |
1180 | | uint8_t *buf = (uint8_t *)"XX04abcdABCD"; |
1181 | | uint16_t buflen = strlen((char *)buf); |
1182 | | Packet *p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); |
1183 | | |
1184 | | FAIL_IF_NULL(p); |
1185 | | |
1186 | | char sig[] = "alert tcp any any -> any any (content:\"XX\"; byte_jump:2,0," |
1187 | | "relative,string,dec,from_end, post_offset -8; content:\"ABCD\"; sid:1; rev:1;)"; |
1188 | | |
1189 | | FAIL_IF_NOT(UTHPacketMatchSig(p, sig)); |
1190 | | |
1191 | | UTHFreePacket(p); |
1192 | | |
1193 | | PASS; |
1194 | | } |
1195 | | |
1196 | | /** |
1197 | | * \brief this function registers unit tests for DetectBytejump |
1198 | | */ |
1199 | | static void DetectBytejumpRegisterTests(void) |
1200 | | { |
1201 | | g_file_data_buffer_id = DetectBufferTypeGetByName("file_data"); |
1202 | | g_dce_stub_data_buffer_id = DetectBufferTypeGetByName("dce_stub_data"); |
1203 | | |
1204 | | UtRegisterTest("DetectBytejumpTestParse01", DetectBytejumpTestParse01); |
1205 | | UtRegisterTest("DetectBytejumpTestParse02", DetectBytejumpTestParse02); |
1206 | | UtRegisterTest("DetectBytejumpTestParse03", DetectBytejumpTestParse03); |
1207 | | UtRegisterTest("DetectBytejumpTestParse04", DetectBytejumpTestParse04); |
1208 | | UtRegisterTest("DetectBytejumpTestParse05", DetectBytejumpTestParse05); |
1209 | | UtRegisterTest("DetectBytejumpTestParse06", DetectBytejumpTestParse06); |
1210 | | UtRegisterTest("DetectBytejumpTestParse07", DetectBytejumpTestParse07); |
1211 | | UtRegisterTest("DetectBytejumpTestParse08", DetectBytejumpTestParse08); |
1212 | | UtRegisterTest("DetectBytejumpTestParse09", DetectBytejumpTestParse09); |
1213 | | UtRegisterTest("DetectBytejumpTestParse10", DetectBytejumpTestParse10); |
1214 | | UtRegisterTest("DetectBytejumpTestParse11", DetectBytejumpTestParse11); |
1215 | | UtRegisterTest("DetectBytejumpTestParse12", DetectBytejumpTestParse12); |
1216 | | UtRegisterTest("DetectBytejumpTestParse13", DetectBytejumpTestParse13); |
1217 | | UtRegisterTest("DetectBytejumpTestParse14", DetectBytejumpTestParse14); |
1218 | | |
1219 | | UtRegisterTest("DetectByteJumpTestPacket01", DetectByteJumpTestPacket01); |
1220 | | UtRegisterTest("DetectByteJumpTestPacket02", DetectByteJumpTestPacket02); |
1221 | | UtRegisterTest("DetectByteJumpTestPacket03", DetectByteJumpTestPacket03); |
1222 | | UtRegisterTest("DetectByteJumpTestPacket04", DetectByteJumpTestPacket04); |
1223 | | UtRegisterTest("DetectByteJumpTestPacket05", DetectByteJumpTestPacket05); |
1224 | | UtRegisterTest("DetectByteJumpTestPacket06", DetectByteJumpTestPacket06); |
1225 | | UtRegisterTest("DetectByteJumpTestPacket07", DetectByteJumpTestPacket07); |
1226 | | UtRegisterTest("DetectByteJumpTestPacket08", DetectByteJumpTestPacket08); |
1227 | | } |
1228 | | #endif /* UNITTESTS */ |