detect-asn1.c detect-asn1.h \
detect-base64-data.c detect-base64-data.h \
detect-base64-decode.c detect-base64-decode.h \
+detect-bsize.c detect-bsize.h \
detect-byte-extract.c detect-byte-extract.h \
detect-bytejump.c detect-bytejump.h \
detect-bytetest.c detect-bytetest.h \
--- /dev/null
+/* Copyright (C) 2017 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
+ *
+ * \author Victor Julien <victor@inliniac.net>
+ *
+ * Implements the bsize generic buffer length keyword
+ */
+
+#include "suricata-common.h"
+#include "util-unittest.h"
+#include "util-unittest-helper.h"
+
+#include "detect.h"
+#include "detect-parse.h"
+#include "detect-engine.h"
+#include "detect-content.h"
+
+#include "detect-bsize.h"
+
+#include "util-misc.h"
+
+/*prototypes*/
+static int DetectBsizeSetup (DetectEngineCtx *, Signature *, const char *);
+static void DetectBsizeFree (void *);
+#ifdef UNITTESTS
+static void DetectBsizeRegisterTests (void);
+#endif
+
+/**
+ * \brief Registration function for bsize: keyword
+ */
+
+void DetectBsizeRegister(void)
+{
+ sigmatch_table[DETECT_BSIZE].name = "bsize";
+ sigmatch_table[DETECT_BSIZE].desc = "match on the length of a buffer";
+ sigmatch_table[DETECT_BSIZE].url = DOC_URL DOC_VERSION "/rules/payload-keywords.html#bsize";
+ sigmatch_table[DETECT_BSIZE].Match = NULL;
+ sigmatch_table[DETECT_BSIZE].Setup = DetectBsizeSetup;
+ sigmatch_table[DETECT_BSIZE].Free = DetectBsizeFree;
+#ifdef UNITTESTS
+ sigmatch_table[DETECT_BSIZE].RegisterTests = DetectBsizeRegisterTests;
+#endif
+}
+
+#define DETECT_BSIZE_LT 0
+#define DETECT_BSIZE_GT 1
+#define DETECT_BSIZE_RA 2
+#define DETECT_BSIZE_EQ 3
+
+typedef struct DetectBsizeData {
+ uint8_t mode;
+ uint64_t lo;
+ uint64_t hi;
+} DetectBsizeData;
+
+/** \brief bsize match function
+ *
+ * \param ctx match ctx
+ * \param buffer_size size of the buffer
+ * \param eof is the buffer closed?
+ *
+ * \retval r 1 match, 0 no match, -1 can't match
+ *
+ * \todo check logic around < vs <=
+ */
+int DetectBsizeMatch(const SigMatchCtx *ctx, const uint64_t buffer_size, bool eof)
+{
+ const DetectBsizeData *bsz = (const DetectBsizeData *)ctx;
+ switch (bsz->mode) {
+ case DETECT_BSIZE_LT:
+ if (buffer_size < bsz->lo) {
+ return 1;
+ }
+ return -1;
+
+ case DETECT_BSIZE_GT:
+ if (buffer_size > bsz->lo) {
+ return 1;
+ } else if (eof) {
+ return -1;
+ }
+ return 0;
+
+ case DETECT_BSIZE_EQ:
+ if (buffer_size == bsz->lo) {
+ return 1;
+ } else if (buffer_size > bsz->lo) {
+ return -1;
+ } else if (eof) {
+ return -1;
+ } else {
+ return 0;
+ }
+
+ case DETECT_BSIZE_RA:
+ if (buffer_size > bsz->lo && buffer_size < bsz->hi) {
+ return 1;
+ } else if (buffer_size <= bsz->lo && eof) {
+ return -1;
+ } else if (buffer_size <= bsz->lo) {
+ return 0;
+ } else if (buffer_size >= bsz->hi) {
+ return -1;
+ }
+ }
+ return 0;
+}
+
+#define ERR(...) do { \
+ char _buf[2048]; \
+ snprintf(_buf, sizeof(_buf), __VA_ARGS__); \
+ SCLogError(SC_ERR_INVALID_RULE_ARGUMENT, "bsize: bad input, %s", _buf); \
+} while(0)
+
+/**
+ * \brief This function is used to parse bsize options passed via bsize: keyword
+ *
+ * \param bsizestr Pointer to the user provided bsize options
+ *
+ * \retval bsized pointer to DetectBsizeData on success
+ * \retval NULL on failure
+ */
+
+static DetectBsizeData *DetectBsizeParse (const char *str)
+{
+ uint32_t lo = 0;
+ uint32_t hi = 0;
+
+ if (str == NULL)
+ return NULL;
+
+ size_t len = strlen(str);
+ if (len == 0)
+ return NULL;
+
+ /* allow for leading spaces */
+ while (isspace(*str))
+ (str++);
+ len = strlen(str);
+ if (len == 0)
+ return NULL;
+
+ int mode = DETECT_BSIZE_EQ;
+ switch (*str) {
+ case '>':
+ mode = DETECT_BSIZE_GT;
+ str++;
+ break;
+ case '<':
+ mode = DETECT_BSIZE_LT;
+ str++;
+ break;
+ }
+
+ /* allow for spaces between mode and value */
+ while (isspace(*str))
+ (str++);
+
+ char str1[11], *p = str1;
+ memset(str1, 0, sizeof(str1));
+ while (*str && isdigit(*str)) {
+ if (p - str1 >= (int)sizeof(str1))
+ return NULL;
+ *p++ = *str++;
+ }
+ /* skip trailing space */
+ while (*str && isspace(*str)) {
+ str++;
+ }
+ if (*str == '\0') {
+ // done
+ SCLogDebug("str1 '%s'", str1);
+
+ uint64_t val = 0;
+ if (ParseSizeStringU64(str1, &val) < 0) {
+ return NULL;
+ }
+ lo = val;
+
+ } else if (*str == '<') {
+ str++;
+ if (*str != '>') {
+ ERR("only '<>' allowed");
+ return NULL;
+ }
+ str++;
+
+ // range
+ if (mode != DETECT_BSIZE_EQ) {
+ ERR("mode already set");
+ return NULL;
+ }
+ mode = DETECT_BSIZE_RA;
+
+ uint64_t val = 0;
+ if (ParseSizeStringU64(str1, &val) < 0) {
+ return NULL;
+ }
+ lo = val;
+
+ /* allow for spaces between mode and value */
+ while (*str && isspace(*str))
+ (str++);
+
+ char str2[11];
+ p = str2;
+ memset(str2, 0, sizeof(str2));
+ while (*str && isdigit(*str)) {
+ if (p - str2 >= (int)sizeof(str2))
+ return NULL;
+ *p++ = *str++;
+ }
+ /* skip trailing space */
+ while (*str && isspace(*str)) {
+ str++;
+ }
+ if (*str == '\0') {
+ // done
+ SCLogDebug("str2 '%s'", str2);
+
+ if (ParseSizeStringU64(str2, &val) < 0) {
+ ERR("'%s' is not a valid u32", str2);
+ return NULL;
+ }
+ hi = val;
+ if (lo >= hi) {
+ ERR("%u > %u", lo, hi);
+ return NULL;
+ }
+
+ } else {
+ ERR("trailing data");
+ return NULL;
+ }
+
+ } else {
+ ERR("'%s'", str);
+ return NULL;
+ }
+
+ DetectBsizeData *bsz = SCCalloc(1, sizeof(*bsz));
+ if (bsz == NULL) {
+ return NULL;
+ }
+ bsz->mode = (uint8_t)mode;
+ bsz->lo = lo;
+ bsz->hi = hi;
+ return bsz;
+}
+
+/**
+ * \brief this function is used to parse bsize data into the current signature
+ *
+ * \param de_ctx pointer to the Detection Engine Context
+ * \param s pointer to the Current Signature
+ * \param bsizestr pointer to the user provided bsize options
+ *
+ * \retval 0 on Success
+ * \retval -1 on Failure
+ */
+static int DetectBsizeSetup (DetectEngineCtx *de_ctx, Signature *s, const char *sizestr)
+{
+ SCEnter();
+ SigMatch *sm = NULL;
+
+ int list = s->init_data->list;
+ if (list == DETECT_SM_LIST_NOTSET)
+ SCReturnInt(-1);
+
+ DetectBsizeData *bsz = DetectBsizeParse(sizestr);
+ if (bsz == NULL)
+ goto error;
+ sm = SigMatchAlloc();
+ if (sm == NULL)
+ goto error;
+ sm->type = DETECT_BSIZE;
+ sm->ctx = (void *)bsz;
+
+ SigMatchAppendSMToList(s, sm, list);
+
+ SCReturnInt(0);
+
+error:
+ DetectBsizeFree(bsz);
+ SCReturnInt(-1);
+}
+
+/**
+ * \brief this function will free memory associated with DetectBsizeData
+ *
+ * \param ptr pointer to DetectBsizeData
+ */
+void DetectBsizeFree(void *ptr)
+{
+ if (ptr == NULL)
+ return;
+
+ DetectBsizeData *bsz = (DetectBsizeData *)ptr;
+ SCFree(bsz);
+}
+
+#ifdef UNITTESTS
+#include "tests/detect-bsize.c"
+#endif
--- /dev/null
+/* Copyright (C) 2017 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
+ *
+ * \author Victor Julien <victor@inliniac.net>
+ */
+
+#ifndef __DETECT_BSIZE_H__
+#define __DETECT_BSIZE_H__
+
+//bool DetectBsizeValidateContent(const Signature *s, int list, const char **);
+//void DetectBsizeApplyToContent(Signature *s, int list);
+void DetectBsizeRegister(void);
+int DetectBsizeMatch(const SigMatchCtx *ctx, const uint64_t buffer_size, bool eof);
+
+#endif /* __DETECT_URILEN_H__ */
#include "detect-engine-content-inspection.h"
#include "detect-uricontent.h"
#include "detect-urilen.h"
+#include "detect-bsize.h"
#include "detect-lua.h"
#include "detect-base64-decode.h"
#include "detect-base64-data.h"
goto match;
- /* we should never get here, but bail out just in case */
+ } else if (smd->type == DETECT_BSIZE) {
+
+ bool eof = (flags & DETECT_CI_FLAGS_END);
+ const uint64_t data_size = buffer_len + stream_start_offset;
+ int r = DetectBsizeMatch(smd->ctx, data_size, eof);
+ if (r < 0) {
+ det_ctx->discontinue_matching = 1;
+ goto no_match;
+
+ } else if (r == 0) {
+ goto no_match;
+ }
+ goto match;
+
} else if (smd->type == DETECT_AL_URILEN) {
SCLogDebug("inspecting uri len");
#include "detect-dce-opnum.h"
#include "detect-dce-stub-data.h"
#include "detect-urilen.h"
+#include "detect-bsize.h"
#include "detect-detection-filter.h"
#include "detect-http-client-body.h"
#include "detect-http-server-body.h"
DetectNfsProcedureRegister();
DetectNfsVersionRegister();
DetectUrilenRegister();
+ DetectBsizeRegister();
DetectDetectionFilterRegister();
DetectAsn1Register();
DetectSshProtocolRegister();
DETECT_GID,
DETECT_MARK,
+ DETECT_BSIZE,
+
DETECT_AL_TLS_VERSION,
DETECT_AL_TLS_SUBJECT,
DETECT_AL_TLS_ISSUERDN,
--- /dev/null
+/* Copyright (C) 2017 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 "../util-unittest.h"
+
+#define TEST_OK(str, m, lo, hi) { \
+ DetectBsizeData *bsz = DetectBsizeParse((str)); \
+ FAIL_IF_NULL(bsz); \
+ FAIL_IF_NOT(bsz->mode == (m)); \
+ DetectBsizeFree(bsz); \
+ SCLogDebug("str %s OK", (str)); \
+}
+#define TEST_FAIL(str) { \
+ DetectBsizeData *bsz = DetectBsizeParse((str)); \
+ FAIL_IF_NOT_NULL(bsz); \
+}
+
+static int DetectBsizeTest01(void)
+{
+ TEST_OK("50", DETECT_BSIZE_EQ, 50, 0);
+ TEST_OK(" 50", DETECT_BSIZE_EQ, 50, 0);
+ TEST_OK(" 50", DETECT_BSIZE_EQ, 50, 0);
+ TEST_OK(" 50 ", DETECT_BSIZE_EQ, 50, 0);
+ TEST_OK(" 50 ", DETECT_BSIZE_EQ, 50, 0);
+
+ TEST_FAIL("AA");
+ TEST_FAIL("5A");
+ TEST_FAIL("A5");
+ PASS;
+}
+
+static int DetectBsizeTest02(void)
+{
+ TEST_OK(">50", DETECT_BSIZE_GT, 50, 0);
+ TEST_OK("> 50", DETECT_BSIZE_GT, 50, 0);
+ TEST_OK("> 50", DETECT_BSIZE_GT, 50, 0);
+ TEST_OK(" >50", DETECT_BSIZE_GT, 50, 0);
+ TEST_OK(" > 50", DETECT_BSIZE_GT, 50, 0);
+ TEST_OK(" > 50", DETECT_BSIZE_GT, 50, 0);
+ TEST_OK(" >50 ", DETECT_BSIZE_GT, 50, 0);
+ TEST_OK(" > 50 ", DETECT_BSIZE_GT, 50, 0);
+ TEST_OK(" > 50 ", DETECT_BSIZE_GT, 50, 0);
+
+ TEST_FAIL(">>50");
+ TEST_FAIL("<>50");
+ TEST_FAIL(" > 50A");
+ PASS;
+}
+
+static int DetectBsizeTest03(void)
+{
+ TEST_OK("<50", DETECT_BSIZE_LT, 50, 0);
+ TEST_OK("< 50", DETECT_BSIZE_LT, 50, 0);
+ TEST_OK("< 50", DETECT_BSIZE_LT, 50, 0);
+ TEST_OK(" <50", DETECT_BSIZE_LT, 50, 0);
+ TEST_OK(" < 50", DETECT_BSIZE_LT, 50, 0);
+ TEST_OK(" < 50", DETECT_BSIZE_LT, 50, 0);
+ TEST_OK(" <50 ", DETECT_BSIZE_LT, 50, 0);
+ TEST_OK(" < 50 ", DETECT_BSIZE_LT, 50, 0);
+ TEST_OK(" < 50 ", DETECT_BSIZE_LT, 50, 0);
+
+ TEST_FAIL(">>50");
+ TEST_FAIL(" < 50A");
+ PASS;
+}
+
+static int DetectBsizeTest04(void)
+{
+ TEST_OK("50<>100", DETECT_BSIZE_RA, 50, 100);
+
+ TEST_FAIL("50<$50");
+ TEST_FAIL("100<>50");
+ TEST_FAIL(">50<>100");
+ PASS;
+}
+
+#undef TEST_OK
+#undef TEST_FAIL
+
+#define TEST_OK(rule) \
+{ \
+ DetectEngineCtx *de_ctx = DetectEngineCtxInit(); \
+ FAIL_IF_NULL(de_ctx); \
+ Signature *s = DetectEngineAppendSig(de_ctx, (rule)); \
+ FAIL_IF_NULL(s); \
+ DetectEngineCtxFree(de_ctx); \
+}
+
+#define TEST_FAIL(rule) \
+{ \
+ DetectEngineCtx *de_ctx = DetectEngineCtxInit(); \
+ FAIL_IF_NULL(de_ctx); \
+ Signature *s = DetectEngineAppendSig(de_ctx, (rule)); \
+ FAIL_IF_NOT_NULL(s); \
+ DetectEngineCtxFree(de_ctx); \
+}
+
+static int DetectBsizeSigTest01(void)
+{
+ TEST_OK("alert http any any -> any any (http_request_line; bsize:10; sid:1;)");
+ TEST_OK("alert http any any -> any any (file_data; bsize:>1000; sid:2;)");
+
+ TEST_FAIL("alert tcp any any -> any any (content:\"abc\"; bsize:10; sid:3;)");
+ TEST_FAIL("alert http any any -> any any (content:\"GET\"; http_method; bsize:10; sid:4;)");
+ TEST_FAIL("alert http any any -> any any (http_request_line; content:\"GET\"; bsize:<10>; sid:5;)");
+ PASS;
+}
+
+#undef TEST_OK
+#undef TEST_FAIL
+
+static void DetectBsizeRegisterTests(void)
+{
+ UtRegisterTest("DetectBsizeTest01 EQ", DetectBsizeTest01);
+ UtRegisterTest("DetectBsizeTest02 GT", DetectBsizeTest02);
+ UtRegisterTest("DetectBsizeTest03 LT", DetectBsizeTest03);
+ UtRegisterTest("DetectBsizeTest04 RA", DetectBsizeTest04);
+
+ UtRegisterTest("DetectBsizeSigTest01", DetectBsizeSigTest01);
+}