aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAshlee Young <ashlee@wildernessvoice.com>2015-12-01 05:55:33 -0800
committerAshlee Young <ashlee@wildernessvoice.com>2015-12-01 05:55:33 -0800
commit7953c59ffd47e409829542e456d90e1219bfe508 (patch)
treea3c166fa8772ca87a372c9f985585f75d4d1c3f4
parente63291850fd0795c5700e25e67e5dee89ba54c5f (diff)
suricata commit 019f85644251fc56ae12122ec0fc6279017d96b9
Change-Id: Ief92b5c3ab87033e0ab3420c3004fcfdfee147d0 Signed-off-by: Ashlee Young <ashlee@wildernessvoice.com>
-rw-r--r--framework/src/suricata/.travis.yml12
-rw-r--r--framework/src/suricata/src/detect-base64-data.c236
-rw-r--r--framework/src/suricata/src/detect-base64-data.h25
-rw-r--r--framework/src/suricata/src/detect-base64-decode.c778
-rw-r--r--framework/src/suricata/src/detect-base64-decode.h33
-rw-r--r--framework/src/suricata/src/util-lua-ssh.c227
-rw-r--r--framework/src/suricata/src/util-lua-ssh.h33
7 files changed, 1344 insertions, 0 deletions
diff --git a/framework/src/suricata/.travis.yml b/framework/src/suricata/.travis.yml
new file mode 100644
index 00000000..8ae46e34
--- /dev/null
+++ b/framework/src/suricata/.travis.yml
@@ -0,0 +1,12 @@
+language: c
+compiler:
+ - gcc
+ - clang
+# Change this to your needs
+script: sh autogen.sh && ./configure --enable-nfqueue --enable-unittests --enable-hiredis && make && make check
+before_install:
+ - sudo add-apt-repository -y ppa:npalix/coccinelle
+ - sudo apt-get update -qq
+ - sudo apt-get install -y libpcre3 libpcre3-dbg libpcre3-dev build-essential autoconf automake libtool libpcap-dev libnet1-dev libyaml-0-2 libyaml-dev zlib1g zlib1g-dev libcap-ng-dev libcap-ng0 make libmagic-dev libnetfilter-queue-dev libnetfilter-queue1 libnfnetlink-dev libnfnetlink0 coccinelle libjansson-dev libhiredis-dev
+ - ./qa/travis-libhtp.sh
+
diff --git a/framework/src/suricata/src/detect-base64-data.c b/framework/src/suricata/src/detect-base64-data.c
new file mode 100644
index 00000000..b056b97a
--- /dev/null
+++ b/framework/src/suricata/src/detect-base64-data.c
@@ -0,0 +1,236 @@
+/* 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 "detect.h"
+#include "detect-engine-content-inspection.h"
+#include "detect-parse.h"
+
+#include "util-unittest.h"
+
+static int DetectBase64DataSetup(DetectEngineCtx *, Signature *, char *);
+static void DetectBase64DataRegisterTests(void);
+
+void DetectBase64DataRegister(void)
+{
+ sigmatch_table[DETECT_BASE64_DATA].name = "base64_data";
+ sigmatch_table[DETECT_BASE64_DATA].desc =
+ "Content match base64 decoded data.";
+ sigmatch_table[DETECT_BASE64_DATA].url =
+ "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Payload_keywords#base64_data";
+ sigmatch_table[DETECT_BASE64_DATA].Setup = DetectBase64DataSetup;
+ sigmatch_table[DETECT_BASE64_DATA].RegisterTests =
+ DetectBase64DataRegisterTests;
+
+ sigmatch_table[DETECT_BASE64_DATA].flags |= SIGMATCH_NOOPT;
+}
+
+static int DetectBase64DataSetup(DetectEngineCtx *de_ctx, Signature *s,
+ char *str)
+{
+ SigMatch *pm = NULL;
+
+ /* Check for a preceding base64_decode. */
+ pm = SigMatchGetLastSMFromLists(s, 28,
+ DETECT_BASE64_DECODE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH],
+ DETECT_BASE64_DECODE, s->sm_lists_tail[DETECT_SM_LIST_UMATCH],
+ DETECT_BASE64_DECODE, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH],
+ DETECT_BASE64_DECODE, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA],
+ DETECT_BASE64_DECODE, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH],
+ DETECT_BASE64_DECODE, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH],
+ DETECT_BASE64_DECODE, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH],
+ DETECT_BASE64_DECODE, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH],
+ DETECT_BASE64_DECODE, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH],
+ DETECT_BASE64_DECODE, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH],
+ DETECT_BASE64_DECODE, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH],
+ DETECT_BASE64_DECODE, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH],
+ DETECT_BASE64_DECODE, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH],
+ DETECT_BASE64_DECODE, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]);
+ if (pm == NULL) {
+ SCLogError(SC_ERR_INVALID_SIGNATURE,
+ "\"base64_data\" keyword seen without preceding base64_decode.");
+ return -1;
+ }
+
+ s->list = DETECT_SM_LIST_BASE64_DATA;
+ return 0;
+}
+
+int DetectBase64DataDoMatch(DetectEngineCtx *de_ctx,
+ DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f)
+{
+ if (det_ctx->base64_decoded_len) {
+ return DetectEngineContentInspection(de_ctx, det_ctx, s,
+ s->sm_lists[DETECT_SM_LIST_BASE64_DATA], f, det_ctx->base64_decoded,
+ det_ctx->base64_decoded_len, 0,
+ DETECT_ENGINE_CONTENT_INSPECTION_MODE_BASE64, NULL);
+ }
+
+ return 0;
+}
+
+#ifdef UNITTESTS
+
+#include "detect-engine.h"
+
+static int DetectBase64DataSetupTest01(void)
+{
+ DetectEngineCtx *de_ctx = NULL;
+ SigMatch *sm;
+ int retval = 0;
+
+ de_ctx = DetectEngineCtxInit();
+ if (de_ctx == NULL) {
+ goto end;
+ }
+
+ de_ctx->flags |= DE_QUIET;
+ de_ctx->sig_list = SigInit(de_ctx,
+ "alert smtp any any -> any any (msg:\"DetectBase64DataSetupTest\"; "
+ "base64_decode; base64_data; content:\"content\"; sid:1; rev:1;)");
+ if (de_ctx->sig_list == NULL) {
+ printf("SigInit failed: ");
+ goto end;
+ }
+
+ sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH];
+ if (sm == NULL) {
+ printf("DETECT_SM_LIST_PMATCH should not be NULL: ");
+ goto end;
+ }
+ if (sm->type != DETECT_BASE64_DECODE) {
+ printf("sm->type should be DETECT_BASE64_DECODE: ");
+ goto end;
+ }
+
+ if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_BASE64_DATA] == NULL) {
+ printf("DETECT_SM_LIST_BASE64_DATA should not be NULL: ");
+ goto end;
+ }
+
+ retval = 1;
+end:
+ if (de_ctx != NULL) {
+ SigGroupCleanup(de_ctx);
+ SigCleanSignatures(de_ctx);
+ DetectEngineCtxFree(de_ctx);
+ }
+ return retval;
+}
+
+static int DetectBase64DataSetupTest02(void)
+{
+ DetectEngineCtx *de_ctx = NULL;
+ SigMatch *sm;
+ int retval = 0;
+
+ de_ctx = DetectEngineCtxInit();
+ if (de_ctx == NULL) {
+ goto end;
+ }
+
+ de_ctx->flags |= DE_QUIET;
+ de_ctx->sig_list = SigInit(de_ctx,
+ "alert smtp any any -> any any ( "
+ "msg:\"DetectBase64DataSetupTest\"; "
+ "file_data; "
+ "content:\"SGV\"; "
+ "base64_decode: bytes 16; "
+ "base64_data; "
+ "content:\"content\"; "
+ "sid:1; rev:1;)");
+ if (de_ctx->sig_list == NULL) {
+ printf("SigInit failed: ");
+ goto end;
+ }
+
+ sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH];
+ if (sm != NULL) {
+ printf("DETECT_SM_LIST_PMATCH is not NULL: ");
+ goto end;
+ }
+
+ sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_FILEDATA];
+ if (sm == NULL) {
+ printf("DETECT_SM_LIST_FILEDATA is NULL: ");
+ goto end;
+ }
+
+ sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_BASE64_DATA];
+ if (sm == NULL) {
+ printf("DETECT_SM_LIST_BASE64_DATA is NULL: ");
+ goto end;
+ }
+
+ retval = 1;
+end:
+ if (de_ctx != NULL) {
+ SigGroupCleanup(de_ctx);
+ SigCleanSignatures(de_ctx);
+ DetectEngineCtxFree(de_ctx);
+ }
+ return retval;
+}
+
+static int DetectBase64DataSetupTest03(void)
+{
+ DetectEngineCtx *de_ctx = NULL;
+ int retval = 0;
+
+ de_ctx = DetectEngineCtxInit();
+ if (de_ctx == NULL) {
+ goto end;
+ }
+
+ de_ctx->flags |= DE_QUIET;
+ de_ctx->sig_list = SigInit(de_ctx,
+ "alert smtp any any -> any any ( "
+ "msg:\"DetectBase64DataSetupTest\"; "
+ "base64_decode: bytes 16; "
+ "base64_data; "
+ "content:\"content\"; "
+ "file_data; "
+ "content:\"SGV\"; "
+ "sid:1; rev:1;)");
+ if (de_ctx->sig_list != NULL) {
+ printf("SigInit should have failed: ");
+ goto end;
+ }
+
+ retval = 1;
+end:
+ if (de_ctx != NULL) {
+ SigGroupCleanup(de_ctx);
+ SigCleanSignatures(de_ctx);
+ DetectEngineCtxFree(de_ctx);
+ }
+ return retval;
+}
+
+#endif
+
+static void DetectBase64DataRegisterTests(void)
+{
+#ifdef UNITTESTS
+ UtRegisterTest("DetectBase64DataSetupTest01", DetectBase64DataSetupTest01,
+ 1);
+ UtRegisterTest("DetectBase64DataSetupTest02", DetectBase64DataSetupTest02,
+ 1);
+ UtRegisterTest("DetectBase64DataSetupTest03", DetectBase64DataSetupTest03,
+ 1);
+#endif /* UNITTESTS */
+}
diff --git a/framework/src/suricata/src/detect-base64-data.h b/framework/src/suricata/src/detect-base64-data.h
new file mode 100644
index 00000000..12fa60de
--- /dev/null
+++ b/framework/src/suricata/src/detect-base64-data.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_BASE64_DATA_H__
+#define __DETECT_BASE64_DATA_H__
+
+void DetectBase64DataRegister(void);
+int DetectBase64DataDoMatch(DetectEngineCtx *, DetectEngineThreadCtx *,
+ Signature *, Flow *);
+
+#endif /* __DETECT_BASE64_DATA_H__ */
diff --git a/framework/src/suricata/src/detect-base64-decode.c b/framework/src/suricata/src/detect-base64-decode.c
new file mode 100644
index 00000000..bd9baea5
--- /dev/null
+++ b/framework/src/suricata/src/detect-base64-decode.c
@@ -0,0 +1,778 @@
+/* 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 "detect.h"
+#include "detect-parse.h"
+#include "detect-base64-decode.h"
+#include "util-base64.h"
+#include "util-byte.h"
+#include "util-print.h"
+
+/* Arbitrary maximum buffer size for decoded base64 data. */
+#define BASE64_DECODE_MAX 65535
+
+static const char decode_pattern[] = "\\s*(bytes\\s+(\\d+),?)?"
+ "\\s*(offset\\s+(\\d+),?)?"
+ "\\s*(\\w+)?";
+static pcre *decode_pcre = NULL;
+static pcre_extra *decode_pcre_study = NULL;
+
+static int DetectBase64DecodeSetup(DetectEngineCtx *, Signature *, char *);
+static void DetectBase64DecodeFree(void *);
+static void DetectBase64DecodeRegisterTests(void);
+
+void DetectBase64DecodeRegister(void)
+{
+ const char *pcre_errptr;
+ int pcre_erroffset;
+
+ sigmatch_table[DETECT_BASE64_DECODE].name = "base64_decode";
+ sigmatch_table[DETECT_BASE64_DECODE].desc =
+ "Decodes base64 encoded data.";
+ sigmatch_table[DETECT_BASE64_DECODE].url =
+ "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Payload_keywords#base64_decode";
+ sigmatch_table[DETECT_BASE64_DECODE].Setup = DetectBase64DecodeSetup;
+ sigmatch_table[DETECT_BASE64_DECODE].Free = DetectBase64DecodeFree;
+ sigmatch_table[DETECT_BASE64_DECODE].RegisterTests =
+ DetectBase64DecodeRegisterTests;
+
+ sigmatch_table[DETECT_BASE64_DECODE].flags |= SIGMATCH_PAYLOAD;
+ sigmatch_table[DETECT_BASE64_DECODE].flags |= SIGMATCH_OPTIONAL_OPT;
+
+ decode_pcre = pcre_compile(decode_pattern, 0, &pcre_errptr, &pcre_erroffset,
+ NULL);
+ if (decode_pcre == NULL) {
+ SCLogError(SC_ERR_PCRE_COMPILE, "Failed to compile pattern \"%s\" at"
+ " offset %d: %s", decode_pattern, pcre_erroffset, pcre_errptr);
+ exit(EXIT_FAILURE);
+ }
+
+ decode_pcre_study = pcre_study(decode_pcre, 0, &pcre_errptr);
+ if (pcre_errptr != NULL) {
+ SCLogError(SC_ERR_PCRE_STUDY, "Failed to study pattern \"%s\": %s",
+ decode_pattern, pcre_errptr);
+ exit(EXIT_FAILURE);
+ }
+}
+
+int DetectBase64DecodeDoMatch(DetectEngineThreadCtx *det_ctx, Signature *s,
+ const SigMatch *sm, uint8_t *payload, uint32_t payload_len)
+{
+ DetectBase64Decode *data = (DetectBase64Decode *)sm->ctx;
+ int decode_len;
+
+#if 0
+ printf("Input data:\n");
+ PrintRawDataFp(stdout, payload, payload_len);
+#endif
+
+ if (data->relative) {
+ payload += det_ctx->buffer_offset;
+ payload_len -= det_ctx->buffer_offset;
+ }
+
+ if (data->offset) {
+ if (data->offset >= payload_len) {
+ return 0;
+ }
+ payload = payload + data->offset;
+ payload_len -= data->offset;
+ }
+
+ decode_len = MIN(payload_len, data->bytes);
+
+#if 0
+ printf("Decoding:\n");
+ PrintRawDataFp(stdout, payload, decode_len);
+#endif
+
+ det_ctx->base64_decoded_len = DecodeBase64(det_ctx->base64_decoded,
+ payload, decode_len, 0);
+ SCLogDebug("Decoded %d bytes from base64 data.",
+ det_ctx->base64_decoded_len);
+#if 0
+ if (det_ctx->base64_decoded_len) {
+ printf("Decoded data:\n");
+ PrintRawDataFp(stdout, det_ctx->base64_decoded,
+ det_ctx->base64_decoded_len);
+ }
+#endif
+
+ return det_ctx->base64_decoded_len > 0;
+}
+
+static int DetectBase64DecodeParse(const char *str, uint32_t *bytes,
+ uint32_t *offset, uint8_t *relative)
+{
+ static const int max = 30;
+ int ov[max];
+ int pcre_rc;
+ const char *bytes_str = NULL;
+ const char *offset_str = NULL;
+ const char *relative_str = NULL;
+ int retval = 0;
+
+ *bytes = 0;
+ *offset = 0;
+ *relative = 0;
+
+ pcre_rc = pcre_exec(decode_pcre, decode_pcre_study, str, strlen(str), 0, 0,
+ ov, max);
+ if (pcre_rc < 3) {
+ goto error;
+ }
+
+ if (pcre_rc >= 3) {
+ if (pcre_get_substring((char *)str, ov, max, 2, &bytes_str) > 0) {
+ if (ByteExtractStringUint32(bytes, 10, 0, bytes_str) <= 0) {
+ SCLogError(SC_ERR_INVALID_RULE_ARGUMENT,
+ "Bad value for bytes: \"%s\"", bytes_str);
+ goto error;
+ }
+ }
+ }
+
+ if (pcre_rc >= 5) {
+ if (pcre_get_substring((char *)str, ov, max, 4, &offset_str)) {
+ if (ByteExtractStringUint32(offset, 10, 0, offset_str) <= 0) {
+ SCLogError(SC_ERR_INVALID_RULE_ARGUMENT,
+ "Bad value for offset: \"%s\"", offset_str);
+ goto error;
+ }
+ }
+ }
+
+ if (pcre_rc >= 6) {
+ if (pcre_get_substring((char *)str, ov, max, 5, &relative_str)) {
+ if (strcmp(relative_str, "relative") == 0) {
+ *relative = 1;
+ }
+ else {
+ SCLogError(SC_ERR_INVALID_RULE_ARGUMENT,
+ "Invalid argument: \"%s\"", relative_str);
+ goto error;
+ }
+ }
+ }
+
+ retval = 1;
+error:
+ if (bytes_str != NULL) {
+ pcre_free_substring(bytes_str);
+ }
+ if (offset_str != NULL) {
+ pcre_free_substring(offset_str);
+ }
+ if (relative_str != NULL) {
+ pcre_free_substring(relative_str);
+ }
+ return retval;
+}
+
+static int DetectBase64DecodeSetup(DetectEngineCtx *de_ctx, Signature *s,
+ char *str)
+{
+ uint32_t bytes = 0;
+ uint32_t offset = 0;
+ uint8_t relative = 0;
+ DetectBase64Decode *data = NULL;
+ int sm_list;
+ SigMatch *sm = NULL;
+ SigMatch *pm = NULL;
+
+ if (str != NULL) {
+ if (!DetectBase64DecodeParse(str, &bytes, &offset, &relative)) {
+ goto error;
+ }
+ }
+ data = SCCalloc(1, sizeof(DetectBase64Decode));
+ if (unlikely(data == NULL)) {
+ goto error;
+ }
+ data->bytes = bytes;
+ data->offset = offset;
+ data->relative = relative;
+
+ if (s->list != DETECT_SM_LIST_NOTSET) {
+ sm_list = s->list;
+#if 0
+ if (data->relative) {
+ pm = SigMatchGetLastSMFromLists(s, 4,
+ DETECT_CONTENT, s->sm_lists_tail[sm_list],
+ DETECT_PCRE, s->sm_lists_tail[sm_list]);
+ }
+#endif
+ }
+ else {
+ /* Copied from detect-isdataat.c. */
+ pm = SigMatchGetLastSMFromLists(s, 168,
+ DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH],
+ DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH],
+ DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH],
+ DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA],
+ DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH],
+ DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH],
+ DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH],
+ DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH],
+ DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH],
+ DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH],
+ DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH],
+ DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH],
+ DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH],
+ DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH],
+ DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH],
+ DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_UMATCH],
+ DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH],
+ DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA],
+ DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH],
+ DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH],
+ DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH],
+ DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH],
+ DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH],
+ DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH],
+ DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH],
+ DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH],
+ DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH],
+ DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH],
+ DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_PMATCH],
+ DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_UMATCH],
+ DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH],
+ DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA],
+ DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH],
+ DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH],
+ DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH],
+ DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH],
+ DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH],
+ DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH],
+ DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH],
+ DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH],
+ DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH],
+ DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH],
+ DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_PMATCH],
+ DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_UMATCH],
+ DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH],
+ DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA],
+ DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH],
+ DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH],
+ DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH],
+ DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH],
+ DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH],
+ DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH],
+ DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH],
+ DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH],
+ DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH],
+ DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH],
+ DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH],
+ DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH],
+ DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH],
+ DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA],
+ DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH],
+ DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH],
+ DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH],
+ DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH],
+ DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH],
+ DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH],
+ DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH],
+ DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH],
+ DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH],
+ DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH],
+ DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH],
+ DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH],
+ DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH],
+ DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA],
+ DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH],
+ DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH],
+ DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH],
+ DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH],
+ DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH],
+ DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH],
+ DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH],
+ DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH],
+ DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH],
+ DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]);
+ if (pm == NULL) {
+ sm_list = DETECT_SM_LIST_PMATCH;
+ }
+ else {
+ sm_list = SigMatchListSMBelongsTo(s, pm);
+ }
+ }
+
+ sm = SigMatchAlloc();
+ if (sm == NULL) {
+ goto error;
+ }
+ sm->type = DETECT_BASE64_DECODE;
+ sm->ctx = (SigMatchCtx *)data;
+ SigMatchAppendSMToList(s, sm, sm_list);
+
+ if (!data->bytes) {
+ data->bytes = BASE64_DECODE_MAX;
+ }
+ if (data->bytes > de_ctx->base64_decode_max_len) {
+ de_ctx->base64_decode_max_len = data->bytes;
+ }
+
+ return 0;
+error:
+ if (data != NULL) {
+ SCFree(data);
+ }
+ return -1;
+}
+
+static void DetectBase64DecodeFree(void *ptr)
+{
+ DetectBase64Decode *data = ptr;
+ SCFree(data);
+}
+
+
+#ifdef UNITTESTS
+
+#include "detect.h"
+#include "detect-engine.h"
+#include "detect-parse.h"
+#include "util-unittest.h"
+#include "util-unittest-helper.h"
+#include "app-layer-parser.h"
+#include "flow-util.h"
+#include "stream-tcp.h"
+
+static int DetectBase64TestDecodeParse(void)
+{
+ int retval = 0;
+ uint32_t bytes = 0;
+ uint32_t offset = 0;
+ uint8_t relative = 0;
+
+ if (!DetectBase64DecodeParse("bytes 1", &bytes, &offset, &relative)) {
+ goto end;
+ }
+ if (bytes != 1 || offset != 0 || relative != 0) {
+ goto end;
+ }
+
+ if (!DetectBase64DecodeParse("offset 9", &bytes, &offset, &relative)) {
+ goto end;
+ }
+ if (bytes != 0 || offset != 9 || relative != 0) {
+ goto end;
+ }
+
+ if (!DetectBase64DecodeParse("relative", &bytes, &offset, &relative)) {
+ goto end;
+ }
+ if (bytes != 0 || offset != 0 || relative != 1) {
+ goto end;
+ }
+
+ if (!DetectBase64DecodeParse("bytes 1, offset 2", &bytes, &offset,
+ &relative)) {
+ goto end;
+ }
+ if (bytes != 1 || offset != 2 || relative != 0) {
+ goto end;
+ }
+
+ if (!DetectBase64DecodeParse("bytes 1, offset 2, relative", &bytes, &offset,
+ &relative)) {
+ goto end;
+ }
+ if (bytes != 1 || offset != 2 || relative != 1) {
+ goto end;
+ }
+
+ if (!DetectBase64DecodeParse("offset 2, relative", &bytes, &offset,
+ &relative)) {
+ goto end;
+ }
+ if (bytes != 0 || offset != 2 || relative != 1) {
+ goto end;
+ }
+
+ /* Misspelled relative. */
+ if (DetectBase64DecodeParse("bytes 1, offset 2, relatve", &bytes, &offset,
+ &relative)) {
+ goto end;
+ }
+
+ /* Misspelled bytes. */
+ if (DetectBase64DecodeParse("byts 1, offset 2, relatve", &bytes, &offset,
+ &relative)) {
+ goto end;
+ }
+
+ /* Misspelled offset. */
+ if (DetectBase64DecodeParse("bytes 1, offst 2, relatve", &bytes, &offset,
+ &relative)) {
+ goto end;
+ }
+
+ /* Misspelled empty string. */
+ if (DetectBase64DecodeParse("", &bytes, &offset, &relative)) {
+ goto end;
+ }
+
+ retval = 1;
+end:
+ return retval;
+}
+
+/**
+ * Test keyword setup on basic content.
+ */
+static int DetectBase64DecodeTestSetup(void)
+{
+ DetectEngineCtx *de_ctx = NULL;
+ Signature *s;
+ int retval = 0;
+
+ de_ctx = DetectEngineCtxInit();
+ if (de_ctx == NULL) {
+ goto end;
+ }
+
+ de_ctx->sig_list = SigInit(de_ctx,
+ "alert tcp any any -> any any ("
+ "msg:\"DetectBase64DecodeTestSetup\"; "
+ "base64_decode; content:\"content\"; "
+ "sid:1; rev:1;)");
+ if (de_ctx->sig_list == NULL) {
+ goto end;
+ }
+ s = de_ctx->sig_list;
+ if (s == NULL) {
+ goto end;
+ }
+ if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) {
+ goto end;
+ }
+
+ retval = 1;
+end:
+ if (de_ctx != NULL) {
+ SigGroupCleanup(de_ctx);
+ SigCleanSignatures(de_ctx);
+ DetectEngineCtxFree(de_ctx);
+ }
+ return retval;
+}
+
+/**
+ * Test keyword setup when the prior rule has a content modifier on
+ * it.
+ */
+static int DetectBase64DecodeHttpHeaderTestSetup(void)
+{
+ DetectEngineCtx *de_ctx = NULL;
+ Signature *s;
+ int retval = 0;
+
+ de_ctx = DetectEngineCtxInit();
+ if (de_ctx == NULL) {
+ goto end;
+ }
+
+ de_ctx->sig_list = SigInit(de_ctx,
+ "alert tcp any any -> any any ("
+ "msg:\"DetectBase64DecodeTestSetup\"; "
+ "content:\"Authorization: basic \"; http_header; "
+ "base64_decode; content:\"content\"; "
+ "sid:1; rev:1;)");
+ if (de_ctx->sig_list == NULL) {
+ goto end;
+ }
+ s = de_ctx->sig_list;
+ if (s == NULL) {
+ goto end;
+ }
+
+ /* I'm not complete sure if this list should not be NULL. */
+ if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) {
+ goto end;
+ }
+
+ /* Test that the http header list is not NULL. */
+ if (s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH] == NULL) {
+ goto end;
+ }
+
+ retval = 1;
+end:
+ if (de_ctx != NULL) {
+ SigGroupCleanup(de_ctx);
+ SigCleanSignatures(de_ctx);
+ DetectEngineCtxFree(de_ctx);
+ }
+ return retval;
+}
+
+static int DetectBase64DecodeTestDecode(void)
+{
+ ThreadVars tv;
+ DetectEngineCtx *de_ctx = NULL;
+ DetectEngineThreadCtx *det_ctx = NULL;
+ Packet *p = NULL;
+ int retval = 0;
+
+ uint8_t payload[] = {
+ 'S', 'G', 'V', 's', 'b', 'G', '8', 'g',
+ 'V', '2', '9', 'y', 'b', 'G', 'Q', '=',
+ };
+
+ memset(&tv, 0, sizeof(tv));
+
+ if ((de_ctx = DetectEngineCtxInit()) == NULL) {
+ goto end;
+ }
+
+ de_ctx->sig_list = SigInit(de_ctx,
+ "alert tcp any any -> any any (msg:\"base64 test\"; "
+ "base64_decode; "
+ "sid:1; rev:1;)");
+ if (de_ctx->sig_list == NULL) {
+ goto end;
+ }
+ SigGroupBuild(de_ctx);
+ DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
+
+ p = UTHBuildPacket(payload, sizeof(payload), IPPROTO_TCP);
+ if (p == NULL) {
+ goto end;
+ }
+
+ SigMatchSignatures(&tv, de_ctx, det_ctx, p);
+ if (det_ctx->base64_decoded_len == 0) {
+ goto end;
+ }
+
+ retval = 1;
+end:
+ if (det_ctx != NULL) {
+ DetectEngineThreadCtxDeinit(&tv, det_ctx);
+ }
+ if (de_ctx != NULL) {
+ SigCleanSignatures(de_ctx);
+ SigGroupCleanup(de_ctx);
+ DetectEngineCtxFree(de_ctx);
+ }
+ if (p != NULL) {
+ UTHFreePacket(p);
+ }
+ return retval;
+}
+
+static int DetectBase64DecodeTestDecodeWithOffset(void)
+{
+ ThreadVars tv;
+ DetectEngineCtx *de_ctx = NULL;
+ DetectEngineThreadCtx *det_ctx = NULL;
+ Packet *p = NULL;
+ int retval = 0;
+
+ uint8_t payload[] = {
+ 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
+ 'S', 'G', 'V', 's', 'b', 'G', '8', 'g',
+ 'V', '2', '9', 'y', 'b', 'G', 'Q', '=',
+ };
+ char decoded[] = "Hello World";
+
+ memset(&tv, 0, sizeof(tv));
+
+ if ((de_ctx = DetectEngineCtxInit()) == NULL) {
+ goto end;
+ }
+
+ de_ctx->sig_list = SigInit(de_ctx,
+ "alert tcp any any -> any any (msg:\"base64 test\"; "
+ "base64_decode: offset 8; "
+ "sid:1; rev:1;)");
+ if (de_ctx->sig_list == NULL) {
+ goto end;
+ }
+ SigGroupBuild(de_ctx);
+ DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
+
+ p = UTHBuildPacket(payload, sizeof(payload), IPPROTO_TCP);
+ if (p == NULL) {
+ goto end;
+ }
+
+ SigMatchSignatures(&tv, de_ctx, det_ctx, p);
+ if (det_ctx->base64_decoded_len != (int)strlen(decoded)) {
+ goto end;
+ }
+ if (memcmp(det_ctx->base64_decoded, decoded, strlen(decoded))) {
+ goto end;
+ }
+
+ retval = 1;
+end:
+ if (det_ctx != NULL) {
+ DetectEngineThreadCtxDeinit(&tv, det_ctx);
+ }
+ if (de_ctx != NULL) {
+ SigCleanSignatures(de_ctx);
+ SigGroupCleanup(de_ctx);
+ DetectEngineCtxFree(de_ctx);
+ }
+ if (p != NULL) {
+ UTHFreePacket(p);
+ }
+ return retval;
+}
+
+static int DetectBase64DecodeTestDecodeLargeOffset(void)
+{
+ ThreadVars tv;
+ DetectEngineCtx *de_ctx = NULL;
+ DetectEngineThreadCtx *det_ctx = NULL;
+ Packet *p = NULL;
+ int retval = 0;
+
+ uint8_t payload[] = {
+ 'S', 'G', 'V', 's', 'b', 'G', '8', 'g',
+ 'V', '2', '9', 'y', 'b', 'G', 'Q', '=',
+ };
+
+ memset(&tv, 0, sizeof(tv));
+
+ if ((de_ctx = DetectEngineCtxInit()) == NULL) {
+ goto end;
+ }
+
+ /* Offset is out of range. */
+ de_ctx->sig_list = SigInit(de_ctx,
+ "alert tcp any any -> any any (msg:\"base64 test\"; "
+ "base64_decode: bytes 16, offset 32; "
+ "sid:1; rev:1;)");
+ if (de_ctx->sig_list == NULL) {
+ goto end;
+ }
+ SigGroupBuild(de_ctx);
+ DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
+
+ p = UTHBuildPacket(payload, sizeof(payload), IPPROTO_TCP);
+ if (p == NULL) {
+ goto end;
+ }
+
+ SigMatchSignatures(&tv, de_ctx, det_ctx, p);
+ if (det_ctx->base64_decoded_len != 0) {
+ goto end;
+ }
+
+ retval = 1;
+end:
+ if (det_ctx != NULL) {
+ DetectEngineThreadCtxDeinit(&tv, det_ctx);
+ }
+ if (de_ctx != NULL) {
+ SigCleanSignatures(de_ctx);
+ SigGroupCleanup(de_ctx);
+ DetectEngineCtxFree(de_ctx);
+ }
+ if (p != NULL) {
+ UTHFreePacket(p);
+ }
+ return retval;
+}
+
+static int DetectBase64DecodeTestDecodeRelative(void)
+{
+ ThreadVars tv;
+ DetectEngineCtx *de_ctx = NULL;
+ DetectEngineThreadCtx *det_ctx = NULL;
+ Packet *p = NULL;
+ int retval = 0;
+
+ uint8_t payload[] = {
+ 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
+ 'S', 'G', 'V', 's', 'b', 'G', '8', 'g',
+ 'V', '2', '9', 'y', 'b', 'G', 'Q', '=',
+ };
+ char decoded[] = "Hello World";
+
+ memset(&tv, 0, sizeof(tv));
+
+ if ((de_ctx = DetectEngineCtxInit()) == NULL) {
+ goto end;
+ }
+
+ de_ctx->sig_list = SigInit(de_ctx,
+ "alert tcp any any -> any any (msg:\"base64 test\"; "
+ "content:\"aaaaaaaa\"; "
+ "base64_decode: relative; "
+ "sid:1; rev:1;)");
+ if (de_ctx->sig_list == NULL) {
+ goto end;
+ }
+ SigGroupBuild(de_ctx);
+ DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
+
+ p = UTHBuildPacket(payload, sizeof(payload), IPPROTO_TCP);
+ if (p == NULL) {
+ goto end;
+ }
+
+ SigMatchSignatures(&tv, de_ctx, det_ctx, p);
+ if (det_ctx->base64_decoded_len != (int)strlen(decoded)) {
+ goto end;
+ }
+ if (memcmp(det_ctx->base64_decoded, decoded, strlen(decoded))) {
+ goto end;
+ }
+
+ retval = 1;
+end:
+ if (det_ctx != NULL) {
+ DetectEngineThreadCtxDeinit(&tv, det_ctx);
+ }
+ if (de_ctx != NULL) {
+ SigCleanSignatures(de_ctx);
+ SigGroupCleanup(de_ctx);
+ DetectEngineCtxFree(de_ctx);
+ }
+ if (p != NULL) {
+ UTHFreePacket(p);
+ }
+ return retval;
+}
+
+#endif
+
+static void DetectBase64DecodeRegisterTests(void)
+{
+#ifdef UNITTESTS
+ UtRegisterTest("DetectBase64TestDecodeParse", DetectBase64TestDecodeParse,
+ 1);
+ UtRegisterTest("DetectBase64DecodeTestSetup", DetectBase64DecodeTestSetup,
+ 1);
+ UtRegisterTest("DetectBase64DecodeHttpHeaderTestSetup",
+ DetectBase64DecodeHttpHeaderTestSetup, 1);
+ UtRegisterTest("DetectBase64DecodeTestDecode", DetectBase64DecodeTestDecode,
+ 1);
+ UtRegisterTest("DetectBase64DecodeTestDecodeWithOffset",
+ DetectBase64DecodeTestDecodeWithOffset, 1);
+ UtRegisterTest("DetectBase64DecodeTestDecodeLargeOffset",
+ DetectBase64DecodeTestDecodeLargeOffset, 1);
+ UtRegisterTest("DetectBase64DecodeTestDecodeRelative",
+ DetectBase64DecodeTestDecodeRelative, 1);
+#endif /* UNITTESTS */
+}
diff --git a/framework/src/suricata/src/detect-base64-decode.h b/framework/src/suricata/src/detect-base64-decode.h
new file mode 100644
index 00000000..a1ce388f
--- /dev/null
+++ b/framework/src/suricata/src/detect-base64-decode.h
@@ -0,0 +1,33 @@
+/* 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_BASE64_DECODE_H__
+#define __DETECT_BASE64_DECODE_H__
+
+#include "app-layer-template.h"
+
+typedef struct DetectBase64Decode_ {
+ uint32_t bytes;
+ uint32_t offset;
+ uint8_t relative;
+} DetectBase64Decode;
+
+void DetectBase64DecodeRegister(void);
+int DetectBase64DecodeDoMatch(DetectEngineThreadCtx *, Signature *,
+ const SigMatch *, uint8_t *, uint32_t);
+
+#endif /* __DETECT_BASE64_DECODE_H__ */
diff --git a/framework/src/suricata/src/util-lua-ssh.c b/framework/src/suricata/src/util-lua-ssh.c
new file mode 100644
index 00000000..df232c81
--- /dev/null
+++ b/framework/src/suricata/src/util-lua-ssh.c
@@ -0,0 +1,227 @@
+/* Copyright (C) 2014 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 Mats Klepsland <mats.klepsland@gmail.com>
+ *
+ */
+
+#include "suricata-common.h"
+#include "debug.h"
+#include "detect.h"
+#include "pkt-var.h"
+#include "conf.h"
+
+#include "threads.h"
+#include "threadvars.h"
+#include "tm-threads.h"
+
+#include "util-print.h"
+#include "util-unittest.h"
+
+#include "util-debug.h"
+
+#include "output.h"
+#include "app-layer.h"
+#include "app-layer-parser.h"
+#include "app-layer-ssh.h"
+#include "util-privs.h"
+#include "util-buffer.h"
+#include "util-proto-name.h"
+#include "util-logopenfile.h"
+#include "util-time.h"
+
+#ifdef HAVE_LUA
+
+#include <lua.h>
+#include <lualib.h>
+#include <lauxlib.h>
+
+#include "util-lua.h"
+#include "util-lua-common.h"
+
+static int GetServerProtoVersion(lua_State *luastate, const Flow *f)
+{
+ void *state = FlowGetAppState(f);
+ if (state == NULL)
+ return LuaCallbackError(luastate, "error: no app layer state");
+
+ SshState *ssh_state = (SshState *)state;
+
+ if (ssh_state->srv_hdr.proto_version == NULL)
+ return LuaCallbackError(luastate, "error: no server proto version");
+
+ return LuaPushStringBuffer(luastate, ssh_state->srv_hdr.proto_version,
+ strlen((char *)ssh_state->srv_hdr.proto_version));
+}
+
+static int SshGetServerProtoVersion(lua_State *luastate)
+{
+ int r;
+
+ if (!(LuaStateNeedProto(luastate, ALPROTO_SSH)))
+ return LuaCallbackError(luastate, "error: protocol not ssh");
+
+ int lock_hint = 0;
+ Flow *f = LuaStateGetFlow(luastate, &lock_hint);
+ if (f == NULL)
+ return LuaCallbackError(luastate, "internal error: no flow");
+
+ if (lock_hint == LUA_FLOW_NOT_LOCKED_BY_PARENT) {
+ FLOWLOCK_RDLOCK(f);
+ r = GetServerProtoVersion(luastate, f);
+ FLOWLOCK_UNLOCK(f);
+ } else {
+ r = GetServerProtoVersion(luastate, f);
+ }
+ return r;
+}
+
+static int GetServerSoftwareVersion(lua_State *luastate, const Flow *f)
+{
+ void *state = FlowGetAppState(f);
+ if (state == NULL)
+ return LuaCallbackError(luastate, "error: no app layer state");
+
+ SshState *ssh_state = (SshState *)state;
+
+ if (ssh_state->srv_hdr.software_version == NULL)
+ return LuaCallbackError(luastate, "error: no server software version");
+
+ return LuaPushStringBuffer(luastate, ssh_state->srv_hdr.software_version,
+ strlen((char *)ssh_state->srv_hdr.software_version));
+}
+
+static int SshGetServerSoftwareVersion(lua_State *luastate)
+{
+ int r;
+
+ if (!(LuaStateNeedProto(luastate, ALPROTO_SSH)))
+ return LuaCallbackError(luastate, "error: protocol not ssh");
+
+ int lock_hint = 0;
+ Flow *f = LuaStateGetFlow(luastate, &lock_hint);
+ if (f == NULL)
+ return LuaCallbackError(luastate, "internal error: no flow");
+
+ if (lock_hint == LUA_FLOW_NOT_LOCKED_BY_PARENT) {
+ FLOWLOCK_RDLOCK(f);
+ r = GetServerSoftwareVersion(luastate, f);
+ FLOWLOCK_UNLOCK(f);
+ } else {
+ r = GetServerSoftwareVersion(luastate, f);
+ }
+ return r;
+}
+
+static int GetClientProtoVersion(lua_State *luastate, const Flow *f)
+{
+ void *state = FlowGetAppState(f);
+ if (state == NULL)
+ return LuaCallbackError(luastate, "error: no app layer state");
+
+ SshState *ssh_state = (SshState *)state;
+
+ if (ssh_state->cli_hdr.proto_version == NULL)
+ return LuaCallbackError(luastate, "error: no client proto version");
+
+ return LuaPushStringBuffer(luastate, ssh_state->cli_hdr.proto_version,
+ strlen((char *)ssh_state->cli_hdr.proto_version));
+}
+
+static int SshGetClientProtoVersion(lua_State *luastate)
+{
+ int r;
+
+ if (!(LuaStateNeedProto(luastate, ALPROTO_SSH)))
+ return LuaCallbackError(luastate, "error: protocol not ssh");
+
+ int lock_hint = 0;
+ Flow *f = LuaStateGetFlow(luastate, &lock_hint);
+ if (f == NULL)
+ return LuaCallbackError(luastate, "internal error: no flow");
+
+ if (lock_hint == LUA_FLOW_NOT_LOCKED_BY_PARENT) {
+ FLOWLOCK_RDLOCK(f);
+ r = GetClientProtoVersion(luastate, f);
+ FLOWLOCK_UNLOCK(f);
+ } else {
+ r = GetClientProtoVersion(luastate, f);
+ }
+ return r;
+}
+
+static int GetClientSoftwareVersion(lua_State *luastate, const Flow *f)
+{
+ void *state = FlowGetAppState(f);
+ if (state == NULL)
+ return LuaCallbackError(luastate, "error: no app layer state");
+
+ SshState *ssh_state = (SshState *)state;
+
+ if (ssh_state->cli_hdr.software_version == NULL)
+ return LuaCallbackError(luastate, "error: no client software version");
+
+ return LuaPushStringBuffer(luastate, ssh_state->cli_hdr.software_version,
+ strlen((char *)ssh_state->cli_hdr.software_version));
+}
+
+static int SshGetClientSoftwareVersion(lua_State *luastate)
+{
+ int r;
+
+ if (!(LuaStateNeedProto(luastate, ALPROTO_SSH)))
+ return LuaCallbackError(luastate, "error: protocol not ssh");
+
+ int lock_hint = 0;
+ Flow *f = LuaStateGetFlow(luastate, &lock_hint);
+ if (f == NULL)
+ return LuaCallbackError(luastate, "internal error: no flow");
+
+ if (lock_hint == LUA_FLOW_NOT_LOCKED_BY_PARENT) {
+ FLOWLOCK_RDLOCK(f);
+ r = GetClientSoftwareVersion(luastate, f);
+ FLOWLOCK_UNLOCK(f);
+ } else {
+ r = GetClientSoftwareVersion(luastate, f);
+ }
+ return r;
+}
+
+/** \brief register ssh lua extensions in a luastate */
+int LuaRegisterSshFunctions(lua_State *luastate)
+{
+ /* registration of the callbacks */
+ lua_pushcfunction(luastate, SshGetServerProtoVersion);
+ lua_setglobal(luastate, "SshGetServerProtoVersion");
+
+ lua_pushcfunction(luastate, SshGetServerSoftwareVersion);
+ lua_setglobal(luastate, "SshGetServerSoftwareVersion");
+
+ lua_pushcfunction(luastate, SshGetClientProtoVersion);
+ lua_setglobal(luastate, "SshGetClientProtoVersion");
+
+ lua_pushcfunction(luastate, SshGetClientSoftwareVersion);
+ lua_setglobal(luastate, "SshGetClientSoftwareVersion");
+
+ return 0;
+}
+
+#endif /* HAVE_LUA */
diff --git a/framework/src/suricata/src/util-lua-ssh.h b/framework/src/suricata/src/util-lua-ssh.h
new file mode 100644
index 00000000..aa6b6d70
--- /dev/null
+++ b/framework/src/suricata/src/util-lua-ssh.h
@@ -0,0 +1,33 @@
+/* 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
+ *
+ * \author Mats Klepsland <mats.klepsland@gmail.com>
+ */
+
+#ifndef __UTIL_LUA_SSH_H__
+#define __UTIL_LUA_SSH_H__
+
+#ifdef HAVE_LUA
+
+int LuaRegisterSshFunctions(lua_State *luastate);
+
+#endif /* HAVE_LUA */
+
+#endif /* __UTIL_LUA_SSH_H__ */