From 7953c59ffd47e409829542e456d90e1219bfe508 Mon Sep 17 00:00:00 2001 From: Ashlee Young Date: Tue, 1 Dec 2015 05:55:33 -0800 Subject: suricata commit 019f85644251fc56ae12122ec0fc6279017d96b9 Change-Id: Ief92b5c3ab87033e0ab3420c3004fcfdfee147d0 Signed-off-by: Ashlee Young --- framework/src/suricata/.travis.yml | 12 + framework/src/suricata/src/detect-base64-data.c | 236 +++++++ framework/src/suricata/src/detect-base64-data.h | 25 + framework/src/suricata/src/detect-base64-decode.c | 778 ++++++++++++++++++++++ framework/src/suricata/src/detect-base64-decode.h | 33 + framework/src/suricata/src/util-lua-ssh.c | 227 +++++++ framework/src/suricata/src/util-lua-ssh.h | 33 + 7 files changed, 1344 insertions(+) create mode 100644 framework/src/suricata/.travis.yml create mode 100644 framework/src/suricata/src/detect-base64-data.c create mode 100644 framework/src/suricata/src/detect-base64-data.h create mode 100644 framework/src/suricata/src/detect-base64-decode.c create mode 100644 framework/src/suricata/src/detect-base64-decode.h create mode 100644 framework/src/suricata/src/util-lua-ssh.c create mode 100644 framework/src/suricata/src/util-lua-ssh.h 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 + * + */ + +#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 +#include +#include + +#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 + */ + +#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__ */ -- cgit 1.2.3-korg