suricata
detect-http-user-agent.c
Go to the documentation of this file.
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 * \ingroup httplayer
20 *
21 * @{
22 */
23
24
25/** \file
26 *
27 * \author Anoop Saldanha <anoopsaldanha@gmail.com>
28 * \author Victor Julien <victor@inliniac.net>
29 *
30 * \brief Handle HTTP user agent match
31 *
32 */
33
34#include "suricata-common.h"
35#include "suricata.h"
36#include "flow-util.h"
37#include "flow.h"
38#include "app-layer-parser.h"
39#include "util-unittest.h"
41#include "app-layer.h"
42#include "app-layer-htp.h"
43#include "app-layer-protos.h"
44#include "detect-engine-build.h"
45#include "detect-engine-alert.h"
46
47static int DetectEngineHttpUATest(
48 const uint8_t *buf, const uint32_t buf_len, const char *sig, const bool expect)
49{
50 TcpSession ssn;
51 ThreadVars th_v;
52 DetectEngineThreadCtx *det_ctx = NULL;
53 Flow f;
54
57
58 memset(&th_v, 0, sizeof(th_v));
59 memset(&f, 0, sizeof(f));
60 memset(&ssn, 0, sizeof(ssn));
61
62 Packet *p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
63 FAIL_IF_NULL(p);
64
66 f.protoctx = (void *)&ssn;
67 f.proto = IPPROTO_TCP;
68 f.flags |= FLOW_IPV4;
69 p->flow = &f;
74
76
80
82 FAIL_IF_NULL(s);
83
85 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
86 FAIL_IF_NULL(det_ctx);
87
88 int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, buf, buf_len);
89 FAIL_IF_NOT(r == 0);
91
92 /* do detect */
93 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
94
95 bool match = PacketAlertCheck(p, 1);
96 FAIL_IF_NOT(match == expect);
97
99
102 FLOW_DESTROY(&f);
103 UTHFreePackets(&p, 1);
104 PASS;
105}
106
107static int DetectEngineHttpUATest01(void)
108{
109 uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n"
110 "User-Agent: CONNECT\r\n"
111 "Host: www.onetwothreefourfivesixseven.org\r\n\r\n";
112 uint32_t http_len = sizeof(http_buf) - 1;
113 return DetectEngineHttpUATest(http_buf, http_len,
114 "alert http any any -> any any "
115 "(msg:\"http user agent test\"; "
116 "content:\"CONNECT\"; http_user_agent; "
117 "sid:1;)",
118 true);
119}
120
121static int DetectEngineHttpUATest02(void)
122{
123 uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n"
124 "User-Agent: CONNECT\r\n"
125 "Host: www.onetwothreefourfivesixseven.org\r\n\r\n";
126 uint32_t http_len = sizeof(http_buf) - 1;
127 return DetectEngineHttpUATest(http_buf, http_len,
128 "alert http any any -> any any "
129 "(msg:\"http user agent test\"; "
130 "content:\"CO\"; depth:4; http_user_agent; "
131 "sid:1;)",
132 true);
133}
134
135static int DetectEngineHttpUATest03(void)
136{
137 uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n"
138 "User-Agent: CONNECT\r\n"
139 "Host: www.onetwothreefourfivesixseven.org\r\n\r\n";
140 uint32_t http_len = sizeof(http_buf) - 1;
141 return DetectEngineHttpUATest(http_buf, http_len,
142 "alert http any any -> any any "
143 "(msg:\"http_user_agent test\"; "
144 "content:!\"ECT\"; depth:4; http_user_agent; "
145 "sid:1;)",
146 true);
147}
148
149static int DetectEngineHttpUATest04(void)
150{
151 uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n"
152 "User-Agent: CONNECT\r\n"
153 "Host: www.onetwothreefourfivesixseven.org\r\n\r\n";
154 uint32_t http_len = sizeof(http_buf) - 1;
155 return DetectEngineHttpUATest(http_buf, http_len,
156 "alert http any any -> any any "
157 "(msg:\"http user agent test\"; "
158 "content:\"ECT\"; depth:4; http_user_agent; "
159 "sid:1;)",
160 false);
161}
162
163static int DetectEngineHttpUATest05(void)
164{
165 uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n"
166 "User-Agent: CONNECT\r\n"
167 "Host: www.onetwothreefourfivesixseven.org\r\n\r\n";
168 uint32_t http_len = sizeof(http_buf) - 1;
169 return DetectEngineHttpUATest(http_buf, http_len,
170 "alert http any any -> any any "
171 "(msg:\"http user agent test\"; "
172 "content:!\"CON\"; depth:4; http_user_agent; "
173 "sid:1;)",
174 false);
175}
176
177static int DetectEngineHttpUATest06(void)
178{
179 uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n"
180 "User-Agent: CONNECT\r\n"
181 "Host: www.onetwothreefourfivesixseven.org\r\n\r\n";
182 uint32_t http_len = sizeof(http_buf) - 1;
183 return DetectEngineHttpUATest(http_buf, http_len,
184 "alert http any any -> any any "
185 "(msg:\"http user agent test\"; "
186 "content:\"ECT\"; offset:3; http_user_agent; "
187 "sid:1;)",
188 true);
189}
190
191static int DetectEngineHttpUATest07(void)
192{
193 uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n"
194 "User-Agent: CONNECT\r\n"
195 "Host: www.onetwothreefourfivesixseven.org\r\n\r\n";
196 uint32_t http_len = sizeof(http_buf) - 1;
197 return DetectEngineHttpUATest(http_buf, http_len,
198 "alert http any any -> any any "
199 "(msg:\"http user agent test\"; "
200 "content:!\"CO\"; offset:3; http_user_agent; "
201 "sid:1;)",
202 true);
203}
204
205static int DetectEngineHttpUATest08(void)
206{
207 uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n"
208 "User-Agent: CONNECT\r\n"
209 "Host: www.onetwothreefourfivesixseven.org\r\n\r\n";
210 uint32_t http_len = sizeof(http_buf) - 1;
211 return DetectEngineHttpUATest(http_buf, http_len,
212 "alert http any any -> any any "
213 "(msg:\"http user agent test\"; "
214 "content:!\"ECT\"; offset:3; http_user_agent; "
215 "sid:1;)",
216 false);
217}
218
219static int DetectEngineHttpUATest09(void)
220{
221 uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n"
222 "User-Agent: CONNECT\r\n"
223 "Host: www.onetwothreefourfivesixseven.org\r\n\r\n";
224 uint32_t http_len = sizeof(http_buf) - 1;
225 return DetectEngineHttpUATest(http_buf, http_len,
226 "alert http any any -> any any "
227 "(msg:\"http user agent test\"; "
228 "content:\"CON\"; offset:3; http_user_agent; "
229 "sid:1;)",
230 false);
231}
232
233static int DetectEngineHttpUATest10(void)
234{
235 uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n"
236 "User-Agent: CONNECT\r\n"
237 "Host: www.onetwothreefourfivesixseven.org\r\n\r\n";
238 uint32_t http_len = sizeof(http_buf) - 1;
239 return DetectEngineHttpUATest(http_buf, http_len,
240 "alert http any any -> any any "
241 "(msg:\"http_user_agent test\"; "
242 "content:\"CO\"; http_user_agent; "
243 "content:\"EC\"; within:4; http_user_agent; "
244 "sid:1;)",
245 true);
246}
247
248static int DetectEngineHttpUATest11(void)
249{
250 uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n"
251 "User-Agent: CONNECT\r\n"
252 "Host: www.onetwothreefourfivesixseven.org\r\n\r\n";
253 uint32_t http_len = sizeof(http_buf) - 1;
254 return DetectEngineHttpUATest(http_buf, http_len,
255 "alert http any any -> any any "
256 "(msg:\"http user agent test\"; "
257 "content:\"CO\"; http_user_agent; "
258 "content:!\"EC\"; within:3; http_user_agent; "
259 "sid:1;)",
260 true);
261}
262
263static int DetectEngineHttpUATest12(void)
264{
265 uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n"
266 "User-Agent: CONNECT\r\n"
267 "Host: www.onetwothreefourfivesixseven.org\r\n\r\n";
268 uint32_t http_len = sizeof(http_buf) - 1;
269 return DetectEngineHttpUATest(http_buf, http_len,
270 "alert http any any -> any any "
271 "(msg:\"http_user_agent test\"; "
272 "content:\"CO\"; http_user_agent; "
273 "content:\"EC\"; within:3; http_user_agent; "
274 "sid:1;)",
275 false);
276}
277
278static int DetectEngineHttpUATest13(void)
279{
280 uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n"
281 "User-Agent: CONNECT\r\n"
282 "Host: www.onetwothreefourfivesixseven.org\r\n\r\n";
283 uint32_t http_len = sizeof(http_buf) - 1;
284 return DetectEngineHttpUATest(http_buf, http_len,
285 "alert http any any -> any any "
286 "(msg:\"http user agent test\"; "
287 "content:\"CO\"; http_user_agent; "
288 "content:!\"EC\"; within:4; http_user_agent; "
289 "sid:1;)",
290 false);
291}
292
293static int DetectEngineHttpUATest14(void)
294{
295 uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n"
296 "User-Agent: CONNECT\r\n"
297 "Host: www.onetwothreefourfivesixseven.org\r\n\r\n";
298 uint32_t http_len = sizeof(http_buf) - 1;
299 return DetectEngineHttpUATest(http_buf, http_len,
300 "alert http any any -> any any "
301 "(msg:\"http_user_agent test\"; "
302 "content:\"CO\"; http_user_agent; "
303 "content:\"EC\"; distance:2; http_user_agent; "
304 "sid:1;)",
305 true);
306}
307
308static int DetectEngineHttpUATest15(void)
309{
310 uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n"
311 "User-Agent: CONNECT\r\n"
312 "Host: www.onetwothreefourfivesixseven.org\r\n\r\n";
313 uint32_t http_len = sizeof(http_buf) - 1;
314 return DetectEngineHttpUATest(http_buf, http_len,
315 "alert http any any -> any any "
316 "(msg:\"http user agent test\"; "
317 "content:\"CO\"; http_user_agent; "
318 "content:!\"EC\"; distance:3; http_user_agent; "
319 "sid:1;)",
320 true);
321}
322
323static int DetectEngineHttpUATest16(void)
324{
325 uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n"
326 "User-Agent: CONNECT\r\n"
327 "Host: www.onetwothreefourfivesixseven.org\r\n\r\n";
328 uint32_t http_len = sizeof(http_buf) - 1;
329 return DetectEngineHttpUATest(http_buf, http_len,
330 "alert http any any -> any any "
331 "(msg:\"http user agent test\"; "
332 "content:\"CO\"; http_user_agent; "
333 "content:\"EC\"; distance:3; http_user_agent; "
334 "sid:1;)",
335 false);
336}
337
338static int DetectEngineHttpUATest17(void)
339{
340 uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n"
341 "User-Agent: CONNECT\r\n"
342 "Host: www.onetwothreefourfivesixseven.org\r\n\r\n";
343 uint32_t http_len = sizeof(http_buf) - 1;
344 return DetectEngineHttpUATest(http_buf, http_len,
345 "alert http any any -> any any "
346 "(msg:\"http_user_agent test\"; "
347 "content:\"CO\"; http_user_agent; "
348 "content:!\"EC\"; distance:2; http_user_agent; "
349 "sid:1;)",
350 false);
351}
352
353static int DetectHttpUATestSigParse(const char *sig, const bool expect)
354{
358
360 bool parsed = (s != NULL);
361 FAIL_IF_NOT(parsed == expect);
363 PASS;
364}
365
366/**
367 * \test Test that a signature containing a http_user_agent is correctly parsed
368 * and the keyword is registered.
369 */
370static int DetectHttpUATest01(void)
371{
372 return DetectHttpUATestSigParse("alert tcp any any -> any any "
373 "(msg:\"Testing http_user_agent\"; "
374 "content:\"one\"; http_user_agent; sid:1;)",
375 true);
376}
377
378/**
379 * \test Test that a signature containing an valid http_user_agent entry is
380 * parsed.
381 */
382static int DetectHttpUATest02(void)
383{
384 return DetectHttpUATestSigParse("alert tcp any any -> any any "
385 "(msg:\"Testing http_user_agent\"; "
386 "content:\"one\"; http_user_agent:; sid:1;)",
387 true);
388}
389
390/**
391 * \test Test that an invalid signature containing no content but a
392 * http_user_agent is invalidated.
393 */
394static int DetectHttpUATest03(void)
395{
396 return DetectHttpUATestSigParse("alert tcp any any -> any any "
397 "(msg:\"Testing http_user_agent\"; "
398 "http_user_agent; sid:1;)",
399 false);
400}
401
402/**
403 * \test Test that an invalid signature containing a rawbytes along with a
404 * http_user_agent is invalidated.
405 */
406static int DetectHttpUATest04(void)
407{
408 return DetectHttpUATestSigParse("alert tcp any any -> any any "
409 "(msg:\"Testing http_user_agent\"; "
410 "content:\"one\"; rawbytes; http_user_agent; sid:1;)",
411 false);
412}
413
414/**
415 * \test Test that a http_user_agent with nocase is parsed.
416 */
417static int DetectHttpUATest05(void)
418{
419 return DetectHttpUATestSigParse("alert tcp any any -> any any "
420 "(msg:\"Testing http_user_agent\"; "
421 "content:\"one\"; http_user_agent; nocase; sid:1;)",
422 true);
423}
424
425/**
426 *\test Test that the http_user_agent content matches against a http request
427 * which holds the content.
428 */
429static int DetectHttpUATest06(void)
430{
431 TcpSession ssn;
432 ThreadVars th_v;
433 DetectEngineThreadCtx *det_ctx = NULL;
434 Flow f;
435 uint8_t http_buf[] =
436 "GET /index.html HTTP/1.0\r\n"
437 "Host: www.openinfosecfoundation.org\r\n"
438 "User-Agent: This is dummy message body\r\n"
439 "Content-Type: text/html\r\n"
440 "\r\n";
441 uint32_t http_len = sizeof(http_buf) - 1;
443
444 memset(&th_v, 0, sizeof(th_v));
445 memset(&f, 0, sizeof(f));
446 memset(&ssn, 0, sizeof(ssn));
447
448 Packet *p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
449 FAIL_IF_NULL(p);
450
451 FLOW_INITIALIZE(&f);
452 f.protoctx = (void *)&ssn;
453 f.proto = IPPROTO_TCP;
454 f.flags |= FLOW_IPV4;
455
456 p->flow = &f;
461
463
467
468 Signature *s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any "
469 "(msg:\"http user agent test\"; "
470 "content:\"message\"; http_user_agent; "
471 "sid:1;)");
472 FAIL_IF_NULL(s);
473
475 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
476
477 int r = AppLayerParserParse(
478 NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, http_buf, http_len);
479 FAIL_IF_NOT(r == 0);
481
482 /* do detect */
483 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
484
486
489
491 FLOW_DESTROY(&f);
492 UTHFreePackets(&p, 1);
493 PASS;
494}
495
496/**
497 *\test Test that the http_user_agent content matches against a http request
498 * which holds the content.
499 */
500static int DetectHttpUATest07(void)
501{
502 TcpSession ssn;
503 Packet *p1 = NULL;
504 Packet *p2 = NULL;
505 ThreadVars th_v;
506 DetectEngineThreadCtx *det_ctx = NULL;
507 Flow f;
508 uint8_t http1_buf[] =
509 "GET /index.html HTTP/1.0\r\n"
510 "Host: www.openinfosecfoundation.org\r\n"
511 "User-Agent: This is dummy message";
512 uint8_t http2_buf[] =
513 "body1\r\n\r\n";
514 uint32_t http1_len = sizeof(http1_buf) - 1;
515 uint32_t http2_len = sizeof(http2_buf) - 1;
517
518 memset(&th_v, 0, sizeof(th_v));
519 memset(&f, 0, sizeof(f));
520 memset(&ssn, 0, sizeof(ssn));
521
522 p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
523 p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
524
525 FLOW_INITIALIZE(&f);
526 f.protoctx = (void *)&ssn;
527 f.proto = IPPROTO_TCP;
528 f.flags |= FLOW_IPV4;
529
530 p1->flow = &f;
534 p2->flow = &f;
539
541
545
546 Signature *s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any "
547 "(msg:\"http user agent test\"; "
548 "content:\"message\"; http_user_agent; "
549 "sid:1;)");
550 FAIL_IF_NULL(s);
551
553 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
554
555 int r = AppLayerParserParse(
556 NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, http1_buf, http1_len);
557 FAIL_IF_NOT(r == 0);
559
560 /* do detect */
561 SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
562
564
566 NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, http2_buf, http2_len);
567 FAIL_IF_NOT(r == 0);
569
570 /* do detect */
571 SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
573
576
578 FLOW_DESTROY(&f);
579 UTHFreePackets(&p1, 1);
580 UTHFreePackets(&p2, 1);
581 PASS;
582}
583
584/**
585 *\test Test that the http_user_agent content matches against a http request
586 * which holds the content.
587 */
588static int DetectHttpUATest08(void)
589{
590 TcpSession ssn;
591 Packet *p1 = NULL;
592 Packet *p2 = NULL;
593 ThreadVars th_v;
594 DetectEngineThreadCtx *det_ctx = NULL;
595 Flow f;
596 uint8_t http1_buf[] =
597 "GET /index.html HTTP/1.0\r\n"
598 "Host: www.openinfosecfoundation.org\r\n"
599 "User-Agent: This is dummy mess";
600 uint8_t http2_buf[] =
601 "age body\r\n\r\n";
602 uint32_t http1_len = sizeof(http1_buf) - 1;
603 uint32_t http2_len = sizeof(http2_buf) - 1;
605
606 memset(&th_v, 0, sizeof(th_v));
607 memset(&f, 0, sizeof(f));
608 memset(&ssn, 0, sizeof(ssn));
609
610 p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
611 p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
612
613 FLOW_INITIALIZE(&f);
614 f.protoctx = (void *)&ssn;
615 f.proto = IPPROTO_TCP;
616 f.flags |= FLOW_IPV4;
617
618 p1->flow = &f;
622 p2->flow = &f;
627
629
633
634 Signature *s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any "
635 "(msg:\"http user agent test\"; "
636 "content:\"message\"; http_user_agent; "
637 "sid:1;)");
638 FAIL_IF_NULL(s);
639
641 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
642
643 int r = AppLayerParserParse(
644 NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, http1_buf, http1_len);
645 FAIL_IF_NOT(r == 0);
647
648 /* do detect */
649 SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
651
653 NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, http2_buf, http2_len);
654 FAIL_IF_NOT(r == 0);
656
657 /* do detect */
658 SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
659
661
664
666 FLOW_DESTROY(&f);
667 UTHFreePackets(&p1, 1);
668 UTHFreePackets(&p2, 1);
669 PASS;
670}
671
672/**
673 *\test Test that the http_user_agent content matches against a http request
674 * which holds the content, against a cross boundary present pattern.
675 */
676static int DetectHttpUATest09(void)
677{
678 TcpSession ssn;
679 Packet *p1 = NULL;
680 Packet *p2 = NULL;
681 ThreadVars th_v;
682 DetectEngineThreadCtx *det_ctx = NULL;
683 Flow f;
684 uint8_t http1_buf[] =
685 "GET /index.html HTTP/1.0\r\n"
686 "Host: www.openinfosecfoundation.org\r\n"
687 "User-Agent: This is dummy body1";
688 uint8_t http2_buf[] =
689 "This is dummy message body2\r\n"
690 "Content-Type: text/html\r\n"
691 "Content-Length: 46\r\n"
692 "\r\n"
693 "This is dummy body1";
694 uint32_t http1_len = sizeof(http1_buf) - 1;
695 uint32_t http2_len = sizeof(http2_buf) - 1;
697
698 memset(&th_v, 0, sizeof(th_v));
699 memset(&f, 0, sizeof(f));
700 memset(&ssn, 0, sizeof(ssn));
701
702 p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
703 p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
704
705 FLOW_INITIALIZE(&f);
706 f.protoctx = (void *)&ssn;
707 f.proto = IPPROTO_TCP;
708 f.flags |= FLOW_IPV4;
709
710 p1->flow = &f;
714 p2->flow = &f;
719
721
725
726 Signature *s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any "
727 "(msg:\"http user agent test\"; "
728 "content:\"body1This\"; http_user_agent; "
729 "sid:1;)");
730 FAIL_IF_NULL(s);
731
733 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
734
735 int r = AppLayerParserParse(
736 NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, http1_buf, http1_len);
737 FAIL_IF_NOT(r == 0);
739
740 /* do detect */
741 SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
743
745 NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, http2_buf, http2_len);
746 FAIL_IF_NOT(r == 0);
748
749 /* do detect */
750 SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
751
753
757 FLOW_DESTROY(&f);
758 UTHFreePackets(&p1, 1);
759 UTHFreePackets(&p2, 1);
760 PASS;
761}
762
763/**
764 *\test Test that the http_user_agent content matches against a http request
765 * against a case insensitive pattern.
766 */
767static int DetectHttpUATest10(void)
768{
769 TcpSession ssn;
770 Packet *p1 = NULL;
771 Packet *p2 = NULL;
772 ThreadVars th_v;
773 DetectEngineThreadCtx *det_ctx = NULL;
774 Flow f;
775 uint8_t http1_buf[] =
776 "GET /index.html HTTP/1.0\r\n"
777 "Host: www.openinfosecfoundation.org\r\n"
778 "User-Agent: This is dummy bodY1";
779 uint8_t http2_buf[] =
780 "This is dummy message body2\r\n"
781 "Content-Type: text/html\r\n"
782 "Content-Length: 46\r\n"
783 "\r\n"
784 "This is dummy bodY1";
785 uint32_t http1_len = sizeof(http1_buf) - 1;
786 uint32_t http2_len = sizeof(http2_buf) - 1;
788
789 memset(&th_v, 0, sizeof(th_v));
790 memset(&f, 0, sizeof(f));
791 memset(&ssn, 0, sizeof(ssn));
792
793 p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
794 p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
795
796 FLOW_INITIALIZE(&f);
797 f.protoctx = (void *)&ssn;
798 f.proto = IPPROTO_TCP;
799 f.flags |= FLOW_IPV4;
800
801 p1->flow = &f;
805 p2->flow = &f;
810
812
816
817 Signature *s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any "
818 "(msg:\"http user agent test\"; "
819 "content:\"body1this\"; http_user_agent; nocase;"
820 "sid:1;)");
821 FAIL_IF_NULL(s);
822
824 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
825
826 int r = AppLayerParserParse(
827 NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, http1_buf, http1_len);
828 FAIL_IF_NOT(r == 0);
830
831 /* do detect */
832 SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
834
836 NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, http2_buf, http2_len);
837 FAIL_IF_NOT(r == 0);
839
840 /* do detect */
841 SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
843
847 FLOW_DESTROY(&f);
848 UTHFreePackets(&p1, 1);
849 UTHFreePackets(&p2, 1);
850 PASS;
851}
852
853/**
854 *\test Test that the negated http_user_agent content matches against a
855 * http request which doesn't hold the content.
856 */
857static int DetectHttpUATest11(void)
858{
859 TcpSession ssn;
860 Packet *p = NULL;
861 ThreadVars th_v;
862 DetectEngineThreadCtx *det_ctx = NULL;
863 Flow f;
864 uint8_t http_buf[] =
865 "GET /index.html HTTP/1.0\r\n"
866 "Host: www.openinfosecfoundation.org\r\n"
867 "User-Agent: This is dummy message body\r\n"
868 "Content-Type: text/html\r\n"
869 "\r\n";
870 uint32_t http_len = sizeof(http_buf) - 1;
872
873 memset(&th_v, 0, sizeof(th_v));
874 memset(&f, 0, sizeof(f));
875 memset(&ssn, 0, sizeof(ssn));
876
877 p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
878
879 FLOW_INITIALIZE(&f);
880 f.protoctx = (void *)&ssn;
881 f.proto = IPPROTO_TCP;
882 f.flags |= FLOW_IPV4;
883
884 p->flow = &f;
889
891
895
896 Signature *s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any "
897 "(msg:\"http user agent test\"; "
898 "content:!\"message\"; http_user_agent; "
899 "sid:1;)");
900 FAIL_IF_NULL(s);
901
903 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
904
905 int r = AppLayerParserParse(
906 NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, http_buf, http_len);
907 FAIL_IF_NOT(r == 0);
909
910 /* do detect */
911 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
912
914
918 FLOW_DESTROY(&f);
919 UTHFreePackets(&p, 1);
920 PASS;
921}
922
923/**
924 *\test Negative test that the negated http_user_agent content matches against a
925 * http request which holds hold the content.
926 */
927static int DetectHttpUATest12(void)
928{
929 TcpSession ssn;
930 Packet *p = NULL;
931 ThreadVars th_v;
932 DetectEngineThreadCtx *det_ctx = NULL;
933 Flow f;
934 uint8_t http_buf[] =
935 "GET /index.html HTTP/1.0\r\n"
936 "Host: www.openinfosecfoundation.org\r\n"
937 "User-Agent: This is dummy body\r\n"
938 "\r\n";
939 uint32_t http_len = sizeof(http_buf) - 1;
941
942 memset(&th_v, 0, sizeof(th_v));
943 memset(&f, 0, sizeof(f));
944 memset(&ssn, 0, sizeof(ssn));
945
946 p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
947
948 FLOW_INITIALIZE(&f);
949 f.protoctx = (void *)&ssn;
950 f.proto = IPPROTO_TCP;
951 f.flags |= FLOW_IPV4;
952
953 p->flow = &f;
958
960
964
965 Signature *s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any "
966 "(msg:\"http user agent test\"; "
967 "content:!\"message\"; http_user_agent; "
968 "sid:1;)");
969 FAIL_IF_NULL(s);
970
972 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
973
974 int r = AppLayerParserParse(
975 NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, http_buf, http_len);
976 FAIL_IF_NOT(r == 0);
978
979 /* do detect */
980 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
982
985
987 FLOW_DESTROY(&f);
988 UTHFreePackets(&p, 1);
989 PASS;
990}
991
992/**
993 * \test Test that the http_user_agent content matches against a http request
994 * which holds the content.
995 */
996static int DetectHttpUATest13(void)
997{
998 TcpSession ssn;
999 Packet *p = NULL;
1000 ThreadVars th_v;
1001 DetectEngineThreadCtx *det_ctx = NULL;
1002 Flow f;
1003 uint8_t http_buf[] =
1004 "GET /index.html HTTP/1.0\r\n"
1005 "Host: www.openinfosecfoundation.org\r\n"
1006 "User-Agent: longbufferabcdefghijklmnopqrstuvwxyz0123456789bufferend\r\n"
1007 "Content-Type: text/html\r\n"
1008 "\r\n";
1009 uint32_t http_len = sizeof(http_buf) - 1;
1011
1012 memset(&th_v, 0, sizeof(th_v));
1013 memset(&f, 0, sizeof(f));
1014 memset(&ssn, 0, sizeof(ssn));
1015
1016 p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1017
1018 FLOW_INITIALIZE(&f);
1019 f.protoctx = (void *)&ssn;
1020 f.proto = IPPROTO_TCP;
1021 f.flags |= FLOW_IPV4;
1022
1023 p->flow = &f;
1028
1029 StreamTcpInitConfig(true);
1030
1033 de_ctx->flags |= DE_QUIET;
1034
1036 "alert http any any -> any any "
1037 "(msg:\"http user agent test\"; "
1038 "content:\"abcdefghijklmnopqrstuvwxyz0123456789\"; http_user_agent; "
1039 "sid:1;)");
1040 FAIL_IF_NULL(s);
1041
1043 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1044
1045 int r = AppLayerParserParse(
1046 NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, http_buf, http_len);
1047 FAIL_IF_NOT(r == 0);
1049
1050 /* do detect */
1051 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1052
1054
1057 StreamTcpFreeConfig(true);
1058 FLOW_DESTROY(&f);
1059 UTHFreePackets(&p, 1);
1060 PASS;
1061}
1062
1063/**
1064 * \test multiple http transactions and body chunks of request handling
1065 */
1066static int DetectHttpUATest14(void)
1067{
1068 Signature *s = NULL;
1069 DetectEngineThreadCtx *det_ctx = NULL;
1070 ThreadVars th_v;
1071 Flow f;
1072 TcpSession ssn;
1073 Packet *p = NULL;
1074 uint8_t httpbuf1[] = "POST / HTTP/1.1\r\n";
1075 uint8_t httpbuf2[] = "Cookie: dummy1\r\n";
1076 uint8_t httpbuf3[] = "User-Agent: Body one!!\r\n\r\n";
1077 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1078 uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1079 uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
1080 uint8_t httpbuf4[] = "GET /?var=val HTTP/1.1\r\n";
1081 uint8_t httpbuf5[] = "Cookie: dummy2\r\n";
1082 uint8_t httpbuf6[] = "User-Agent: Body two\r\n\r\n";
1083 uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
1084 uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */
1085 uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */
1087
1088 memset(&th_v, 0, sizeof(th_v));
1089 memset(&f, 0, sizeof(f));
1090 memset(&ssn, 0, sizeof(ssn));
1091
1092 p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1093
1094 FLOW_INITIALIZE(&f);
1095 f.protoctx = (void *)&ssn;
1096 f.proto = IPPROTO_TCP;
1097 f.flags |= FLOW_IPV4;
1098
1099 p->flow = &f;
1104
1105 StreamTcpInitConfig(true);
1106
1109 de_ctx->flags |= DE_QUIET;
1110
1111 s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"POST\"; http_method; content:\"dummy1\"; http_cookie; content:\"Body one\"; http_user_agent; sid:1; rev:1;)");
1112 FAIL_IF_NULL(s);
1113 s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"GET\"; http_method; content:\"dummy2\"; http_cookie; content:\"Body two\"; http_user_agent; sid:2; rev:1;)");
1114 FAIL_IF_NULL(s);
1115
1117 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1118
1119 int r = AppLayerParserParse(
1120 NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf1, httplen1);
1121 FAIL_IF_NOT(r == 0);
1122
1123 /* do detect */
1124 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1126
1127 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf2, httplen2);
1128 FAIL_IF_NOT(r == 0);
1129
1130 /* do detect */
1131 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1133
1134 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf3, httplen3);
1135 FAIL_IF_NOT(r == 0);
1136
1137 /* do detect */
1138 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1140 p->alerts.cnt = 0;
1141
1142 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf4, httplen4);
1143 FAIL_IF_NOT(r == 0);
1144
1145 /* do detect */
1146 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1149
1150 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf5, httplen5);
1151 FAIL_IF_NOT(r == 0);
1152
1153 /* do detect */
1154 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1157
1158 SCLogDebug("sending data chunk 7");
1159
1160 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf6, httplen6);
1161 FAIL_IF_NOT(r == 0);
1162
1163 /* do detect */
1164 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1167 p->alerts.cnt = 0;
1168
1169 HtpState *htp_state = f.alstate;
1170 FAIL_IF_NULL(htp_state);
1171 FAIL_IF_NOT(AppLayerParserGetTxCnt(&f, htp_state) == 2);
1172
1174 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1176
1177 StreamTcpFreeConfig(true);
1178 FLOW_DESTROY(&f);
1179 UTHFreePacket(p);
1180 PASS;
1181}
1182
1183static void DetectHttpUARegisterTests(void)
1184{
1185 UtRegisterTest("DetectEngineHttpUATest01", DetectEngineHttpUATest01);
1186 UtRegisterTest("DetectEngineHttpUATest02", DetectEngineHttpUATest02);
1187 UtRegisterTest("DetectEngineHttpUATest03", DetectEngineHttpUATest03);
1188 UtRegisterTest("DetectEngineHttpUATest04", DetectEngineHttpUATest04);
1189 UtRegisterTest("DetectEngineHttpUATest05", DetectEngineHttpUATest05);
1190 UtRegisterTest("DetectEngineHttpUATest06", DetectEngineHttpUATest06);
1191 UtRegisterTest("DetectEngineHttpUATest07", DetectEngineHttpUATest07);
1192 UtRegisterTest("DetectEngineHttpUATest08", DetectEngineHttpUATest08);
1193 UtRegisterTest("DetectEngineHttpUATest09", DetectEngineHttpUATest09);
1194 UtRegisterTest("DetectEngineHttpUATest10", DetectEngineHttpUATest10);
1195 UtRegisterTest("DetectEngineHttpUATest11", DetectEngineHttpUATest11);
1196 UtRegisterTest("DetectEngineHttpUATest12", DetectEngineHttpUATest12);
1197 UtRegisterTest("DetectEngineHttpUATest13", DetectEngineHttpUATest13);
1198 UtRegisterTest("DetectEngineHttpUATest14", DetectEngineHttpUATest14);
1199 UtRegisterTest("DetectEngineHttpUATest15", DetectEngineHttpUATest15);
1200 UtRegisterTest("DetectEngineHttpUATest16", DetectEngineHttpUATest16);
1201 UtRegisterTest("DetectEngineHttpUATest17", DetectEngineHttpUATest17);
1202
1203 UtRegisterTest("DetectHttpUATest01", DetectHttpUATest01);
1204 UtRegisterTest("DetectHttpUATest02", DetectHttpUATest02);
1205 UtRegisterTest("DetectHttpUATest03", DetectHttpUATest03);
1206 UtRegisterTest("DetectHttpUATest04", DetectHttpUATest04);
1207 UtRegisterTest("DetectHttpUATest05", DetectHttpUATest05);
1208 UtRegisterTest("DetectHttpUATest06", DetectHttpUATest06);
1209 UtRegisterTest("DetectHttpUATest07", DetectHttpUATest07);
1210 UtRegisterTest("DetectHttpUATest08", DetectHttpUATest08);
1211 UtRegisterTest("DetectHttpUATest09", DetectHttpUATest09);
1212 UtRegisterTest("DetectHttpUATest10", DetectHttpUATest10);
1213 UtRegisterTest("DetectHttpUATest11", DetectHttpUATest11);
1214 UtRegisterTest("DetectHttpUATest12", DetectHttpUATest12);
1215 UtRegisterTest("DetectHttpUATest13", DetectHttpUATest13);
1216 UtRegisterTest("DetectHttpUATest14", DetectHttpUATest14);
1217}
1218
1219/**
1220 * @}
1221 */
AppLayerParserThreadCtx * AppLayerParserThreadCtxAlloc(void)
Gets a new app layer protocol's parser thread context.
uint64_t AppLayerParserGetTxCnt(const Flow *f, void *alstate)
void AppLayerParserThreadCtxFree(AppLayerParserThreadCtx *tctx)
Destroys the app layer parser thread context obtained using AppLayerParserThreadCtxAlloc().
int AppLayerParserParse(ThreadVars *tv, AppLayerParserThreadCtx *alp_tctx, Flow *f, AppProto alproto, uint8_t flags, const uint8_t *input, uint32_t input_len)
@ ALPROTO_HTTP1
#define PKT_HAS_FLOW
Definition decode.h:1266
#define PKT_STREAM_EST
Definition decode.h:1262
int PacketAlertCheck(Packet *p, uint32_t sid)
Check if a certain sid alerted, this is used in the test functions.
int SigGroupBuild(DetectEngineCtx *de_ctx)
Convert the signature list into the runtime match structure.
DetectEngineCtx * DetectEngineCtxInit(void)
void DetectEngineCtxFree(DetectEngineCtx *)
Free a DetectEngineCtx::
Signature * DetectEngineAppendSig(DetectEngineCtx *, const char *)
Parse and append a Signature into the Detection Engine Context signature list.
TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data)
initialize thread specific detection engine context
TmEcode DetectEngineThreadCtxDeinit(ThreadVars *tv, void *data)
void SigMatchSignatures(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p)
wrapper for old tests
Definition detect.c:2420
#define DE_QUIET
Definition detect.h:330
#define FLOW_INITIALIZE(f)
Definition flow-util.h:38
#define FLOW_DESTROY(f)
Definition flow-util.h:119
#define FLOW_PKT_TOSERVER
Definition flow.h:233
#define FLOW_PKT_ESTABLISHED
Definition flow.h:235
#define FLOW_IPV4
Definition flow.h:100
AppLayerParserThreadCtx * alp_tctx
DetectEngineCtx * de_ctx
#define FAIL_IF_NULL(expr)
Fail a test if expression evaluates to NULL.
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
#define FAIL_IF_NOT(expr)
Fail a test if expression evaluates to false.
#define PASS
Pass the test.
#define FAIL_IF(expr)
Fail a test if expression evaluates to true.
void StreamTcpFreeConfig(bool quiet)
Definition stream-tcp.c:859
void StreamTcpInitConfig(bool)
To initialize the stream global configuration data.
Definition stream-tcp.c:488
main detection engine ctx
Definition detect.h:932
uint8_t flags
Definition detect.h:934
Flow data structure.
Definition flow.h:356
uint8_t proto
Definition flow.h:378
uint32_t flags
Definition flow.h:421
AppProto alproto
application level protocol
Definition flow.h:450
void * alstate
Definition flow.h:479
void * protoctx
Definition flow.h:441
uint16_t cnt
Definition decode.h:287
uint8_t flowflags
Definition decode.h:532
PacketAlerts alerts
Definition decode.h:620
struct Flow_ * flow
Definition decode.h:546
uint32_t flags
Definition decode.h:544
Signature container.
Definition detect.h:668
Per thread variable structure.
Definition threadvars.h:58
#define SCLogDebug(...)
Definition util-debug.h:275
void UTHFreePackets(Packet **p, int numpkts)
UTHFreePackets: function to release the allocated data from UTHBuildPacket and the packet itself.
Packet * UTHBuildPacket(uint8_t *payload, uint16_t payload_len, uint8_t ipproto)
UTHBuildPacket is a wrapper that build packets with default ip and port fields.
void UTHFreePacket(Packet *p)
UTHFreePacket: function to release the allocated data from UTHBuildPacket and the packet itself.