From 06beca62f58621a05c6027021d093d836ce02323 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 1 Sep 2015 12:36:00 -0600 Subject: [PATCH] app-layer: template for application layer content inspection --- src/Makefile.am | 2 + src/detect-engine-content-inspection.h | 1 + src/detect-engine-state.h | 1 + src/detect-engine-template.c | 46 +++++++ src/detect-engine-template.h | 25 ++++ src/detect-engine.c | 18 +++ src/detect-parse.c | 5 + src/detect-template-buffer.c | 165 +++++++++++++++++++++++++ src/detect-template-buffer.h | 25 ++++ src/detect.c | 12 ++ src/detect.h | 4 + 11 files changed, 304 insertions(+) create mode 100644 src/detect-engine-template.c create mode 100644 src/detect-engine-template.h create mode 100644 src/detect-template-buffer.c create mode 100644 src/detect-template-buffer.h diff --git a/src/Makefile.am b/src/Makefile.am index 9d3809c2f4..674043f5db 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -123,6 +123,7 @@ detect-engine-siggroup.c detect-engine-siggroup.h \ detect-engine-sigorder.c detect-engine-sigorder.h \ detect-engine-state.c detect-engine-state.h \ detect-engine-tag.c detect-engine-tag.h \ +detect-engine-template.c detect-engine-template.h \ detect-engine-threshold.c detect-engine-threshold.h \ detect-engine-uri.c detect-engine-uri.h \ detect-fast-pattern.c detect-fast-pattern.h \ @@ -195,6 +196,7 @@ detect-ssl-version.c detect-ssl-version.h \ detect-stream_size.c detect-stream_size.h \ detect-tag.c detect-tag.h \ detect-template.c detect-template.h \ +detect-template-buffer.c detect-template-buffer.h \ detect-threshold.c detect-threshold.h \ detect-tls.c detect-tls.h \ detect-tls-version.c detect-tls-version.h \ diff --git a/src/detect-engine-content-inspection.h b/src/detect-engine-content-inspection.h index 6d3accaaa3..dc0b5026be 100644 --- a/src/detect-engine-content-inspection.h +++ b/src/detect-engine-content-inspection.h @@ -50,6 +50,7 @@ enum { DETECT_ENGINE_CONTENT_INSPECTION_MODE_HRHHD, DETECT_ENGINE_CONTENT_INSPECTION_MODE_DNSQUERY, DETECT_ENGINE_CONTENT_INSPECTION_MODE_FD_SMTP, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_TEMPLATE_BUFFER, }; int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, diff --git a/src/detect-engine-state.h b/src/detect-engine-state.h index 51f67448e7..c8944cffd1 100644 --- a/src/detect-engine-state.h +++ b/src/detect-engine-state.h @@ -81,6 +81,7 @@ #define DE_STATE_FLAG_FD_SMTP_INSPECT (1 << 21) #define DE_STATE_FLAG_DNSREQUEST_INSPECT (1 << 22) #define DE_STATE_FLAG_DNSRESPONSE_INSPECT (1 << 23) +#define DE_STATE_FLAG_TEMPLATE_BUFFER_INSPECT (1 << 24) /* state flags */ #define DETECT_ENGINE_STATE_FLAG_FILE_STORE_DISABLED 0x0001 diff --git a/src/detect-engine-template.c b/src/detect-engine-template.c new file mode 100644 index 0000000000..49c29c6a6a --- /dev/null +++ b/src/detect-engine-template.c @@ -0,0 +1,46 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "suricata-common.h" +#include "stream.h" +#include "detect-engine-content-inspection.h" + +#include "app-layer-template.h" + +int DetectEngineInspectTemplateBuffer(ThreadVars *tv, DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f, uint8_t flags, + void *alstate, void *txv, uint64_t tx_id) +{ + TemplateTransaction *tx = (TemplateTransaction *)txv; + int ret = 0; + + if (flags & STREAM_TOSERVER && tx->request_buffer != NULL) { + ret = DetectEngineContentInspection(de_ctx, det_ctx, s, + s->sm_lists[DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH], f, + tx->request_buffer, tx->request_buffer_len, 0, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_TEMPLATE_BUFFER, NULL); + } + else if (flags & STREAM_TOCLIENT && tx->response_buffer != NULL) { + ret = DetectEngineContentInspection(de_ctx, det_ctx, s, + s->sm_lists[DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH], f, + tx->response_buffer, tx->response_buffer_len, 0, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_TEMPLATE_BUFFER, NULL); + } + + SCLogNotice("Returning %d.", ret); + return ret; +} diff --git a/src/detect-engine-template.h b/src/detect-engine-template.h new file mode 100644 index 0000000000..61eb8d0103 --- /dev/null +++ b/src/detect-engine-template.h @@ -0,0 +1,25 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#ifndef __DETECT_TEMPLATE_ENGINE_H__ +#define __DETECT_TEMPLATE_ENGINE_H__ + +int DetectEngineInspectTemplateBuffer(ThreadVars *, DetectEngineCtx *, + DetectEngineThreadCtx *, Signature *, Flow *, uint8_t, void *, void *, + uint64_t); + +#endif /* __DETECT_TEMPLATE_ENGINE_H__ */ diff --git a/src/detect-engine.c b/src/detect-engine.c index 7de049693f..c6e1a83f4c 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -62,6 +62,7 @@ #include "detect-engine-dns.h" #include "detect-engine-modbus.h" #include "detect-engine-filedata-smtp.h" +#include "detect-engine-template.h" #include "detect-engine.h" #include "detect-engine-state.h" @@ -285,6 +286,13 @@ void DetectEngineRegisterAppInspectionEngines(void) DE_STATE_FLAG_FD_SMTP_INSPECT, 0, DetectEngineInspectSMTPFiledata }, + /* Template. */ + { IPPROTO_TCP, + ALPROTO_TEMPLATE, + DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH, + DE_STATE_FLAG_TEMPLATE_BUFFER_INSPECT, + 0, + DetectEngineInspectTemplateBuffer }, }; struct tmp_t data_toclient[] = { @@ -352,6 +360,13 @@ void DetectEngineRegisterAppInspectionEngines(void) DE_STATE_FLAG_DNSRESPONSE_INSPECT, 1, DetectEngineInspectDnsResponse }, + /* Template. */ + { IPPROTO_TCP, + ALPROTO_TEMPLATE, + DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH, + DE_STATE_FLAG_TEMPLATE_BUFFER_INSPECT, + 1, + DetectEngineInspectTemplateBuffer }, }; size_t i; @@ -2630,6 +2645,9 @@ const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type) case DETECT_SM_LIST_MODBUS_MATCH: return "modbus"; + case DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH: + return "template_buffer"; + case DETECT_SM_LIST_POSTMATCH: return "post-match"; diff --git a/src/detect-parse.c b/src/detect-parse.c index d077791e34..fedfebe864 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -1479,6 +1479,11 @@ static Signature *SigInitHelper(DetectEngineCtx *de_ctx, char *sigstr, if (sig->sm_lists[DETECT_SM_LIST_HRHHDMATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; + /* Template. */ + if (sig->sm_lists[DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH]) { + sig->flags |= SIG_FLAG_STATE_MATCH; + } + /* DNS */ if (sig->sm_lists[DETECT_SM_LIST_DNSQUERYNAME_MATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; diff --git a/src/detect-template-buffer.c b/src/detect-template-buffer.c new file mode 100644 index 0000000000..64f948c2b4 --- /dev/null +++ b/src/detect-template-buffer.c @@ -0,0 +1,165 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file Set up of the "template_buffer" keyword to allow content inspections + * on the decoded template application layer buffers. + */ + +#include "suricata-common.h" +#include "detect.h" +#include "app-layer-template.h" + +static int DetectTemplateBufferSetup(DetectEngineCtx *, Signature *, char *); +static void DetectTemplateBufferRegisterTests(void); + +void DetectTemplateBufferRegister(void) +{ + sigmatch_table[DETECT_AL_TEMPLATE_BUFFER].name = "template_buffer"; + sigmatch_table[DETECT_AL_TEMPLATE_BUFFER].desc = + "Template content modififier to match on the template buffers"; + sigmatch_table[DETECT_AL_TEMPLATE_BUFFER].alproto = ALPROTO_TEMPLATE; + sigmatch_table[DETECT_AL_TEMPLATE_BUFFER].Setup = DetectTemplateBufferSetup; + sigmatch_table[DETECT_AL_TEMPLATE_BUFFER].RegisterTests = + DetectTemplateBufferRegisterTests; + + sigmatch_table[DETECT_AL_TEMPLATE_BUFFER].flags |= SIGMATCH_NOOPT; + sigmatch_table[DETECT_AL_TEMPLATE_BUFFER].flags |= SIGMATCH_PAYLOAD; + + SCLogNotice("Template application layer detect registered."); +} + +static int DetectTemplateBufferSetup(DetectEngineCtx *de_ctx, Signature *s, + char *str) +{ + s->list = DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH; + s->alproto = ALPROTO_TEMPLATE; + return 0; +} + +#ifdef UNITTESTS + +#include "util-unittest.h" +#include "util-unittest-helper.h" +#include "app-layer-parser.h" +#include "detect-engine.h" +#include "detect-parse.h" +#include "flow-util.h" +#include "stream-tcp.h" + +static int DetectTemplateBufferTest(void) +{ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + Flow f; + Packet *p; + TcpSession tcp; + ThreadVars tv; + Signature *s; + + int result = 0; + + uint8_t request[] = "Hello World!"; + + /* Setup flow. */ + memset(&f, 0, sizeof(Flow)); + memset(&tcp, 0, sizeof(TcpSession)); + memset(&tv, 0, sizeof(ThreadVars)); + p = UTHBuildPacket(request, sizeof(request), IPPROTO_TCP); + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_TEMPLATE; + f.protoctx = (void *)&tcp; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + + /* This rule should match. */ + s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (" + "msg:\"TEMPLATE Test Rule\"; " + "template_buffer; content:\"World!\"; " + "sid:1; rev:1;)"); + if (s == NULL) { + goto end; + } + + /* This rule should not match. */ + s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (" + "msg:\"TEMPLATE Test Rule\"; " + "template_buffer; content:\"W0rld!\"; " + "sid:2; rev:1;)"); + if (s == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + AppLayerParserParse(alp_tctx, &f, ALPROTO_TEMPLATE, STREAM_TOSERVER, + request, sizeof(request)); + SCMutexUnlock(&f.m); + + /* Check that we have app-layer state. */ + if (f.alstate == NULL) { + goto end; + } + + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + if (!PacketAlertCheck(p, 1)) { + goto end; + } + if (PacketAlertCheck(p, 2)) { + goto end; + } + + result = 1; +end: + /* Cleanup. */ + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + + return result; +} + +#endif + +static void DetectTemplateBufferRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("DetectTemplateBufferTest", DetectTemplateBufferTest, 1); +#endif /* UNITTESTS */ +} diff --git a/src/detect-template-buffer.h b/src/detect-template-buffer.h new file mode 100644 index 0000000000..8a2ab8bad1 --- /dev/null +++ b/src/detect-template-buffer.h @@ -0,0 +1,25 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#ifndef __DETECT_TEMPLATE_BUFFER_H__ +#define __DETECT_TEMPLATE_BUFFER_H__ + +#include "app-layer-template.h" + +void DetectTemplateBufferRegister(void); + +#endif /* __DETECT_TEMPLATE_BUFFER_H__ */ diff --git a/src/detect.c b/src/detect.c index a1516200d0..e0b5bfd3f0 100644 --- a/src/detect.c +++ b/src/detect.c @@ -156,6 +156,7 @@ #include "detect-dns-query.h" #include "detect-app-layer-protocol.h" #include "detect-template.h" +#include "detect-template-buffer.h" #include "util-rule-vars.h" @@ -163,6 +164,7 @@ #include "app-layer-protos.h" #include "app-layer-htp.h" #include "app-layer-smtp.h" +#include "app-layer-template.h" #include "detect-tls.h" #include "detect-tls-version.h" #include "detect-ssh-proto-version.h" @@ -2431,6 +2433,10 @@ PacketCreateMask(Packet *p, SignatureMask *mask, AppProto alproto, int has_state SCLogDebug("packet/flow has smtp state"); (*mask) |= SIG_MASK_REQUIRE_SMTP_STATE; break; + case ALPROTO_TEMPLATE: + SCLogDebug("packet/flow has template state"); + (*mask) |= SIG_MASK_REQUIRE_TEMPLATE_STATE; + break; default: SCLogDebug("packet/flow has other state"); break; @@ -2668,6 +2674,10 @@ static int SignatureCreateMask(Signature *s) s->mask |= SIG_MASK_REQUIRE_SMTP_STATE; SCLogDebug("sig requires smtp state"); } + if (s->alproto == ALPROTO_TEMPLATE) { + s->mask |= SIG_MASK_REQUIRE_TEMPLATE_STATE; + SCLogDebug("sig requires template state"); + } if ((s->mask & SIG_MASK_REQUIRE_DCE_STATE) || (s->mask & SIG_MASK_REQUIRE_HTTP_STATE) || @@ -2675,6 +2685,7 @@ static int SignatureCreateMask(Signature *s) (s->mask & SIG_MASK_REQUIRE_DNS_STATE) || (s->mask & SIG_MASK_REQUIRE_FTP_STATE) || (s->mask & SIG_MASK_REQUIRE_SMTP_STATE) || + (s->mask & SIG_MASK_REQUIRE_TEMPLATE_STATE) || (s->mask & SIG_MASK_REQUIRE_TLS_STATE)) { s->mask |= SIG_MASK_REQUIRE_FLOW; @@ -5238,6 +5249,7 @@ void SigTableSetup(void) DetectModbusRegister(); DetectAppLayerProtocolRegister(); DetectTemplateRegister(); + DetectTemplateBufferRegister(); } void SigTableRegisterTests(void) diff --git a/src/detect.h b/src/detect.h index 236f69aa24..30adc9c4f8 100644 --- a/src/detect.h +++ b/src/detect.h @@ -126,6 +126,8 @@ enum DetectSigmatchListEnum { DETECT_SM_LIST_MODBUS_MATCH, + DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH, + /* list for post match actions: flowbit set, flowint increment, etc */ DETECT_SM_LIST_POSTMATCH, @@ -305,6 +307,7 @@ typedef struct DetectPort_ { #define SIG_MASK_REQUIRE_DNS_STATE (1<<10) #define SIG_MASK_REQUIRE_FTP_STATE (1<<11) #define SIG_MASK_REQUIRE_SMTP_STATE (1<<12) +#define SIG_MASK_REQUIRE_TEMPLATE_STATE (1<<13) /* for now a uint8_t is enough */ #define SignatureMask uint16_t @@ -1229,6 +1232,7 @@ enum { DETECT_XBITS, DETECT_TEMPLATE, + DETECT_AL_TEMPLATE_BUFFER, /* make sure this stays last */ DETECT_TBLSIZE, -- 2.47.2