mirror of https://github.com/OISF/suricata
base64_decode, base64_data: decode and match base64
parent
9375e8fb3c
commit
6b15686fd1
@ -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 */
|
||||||
|
}
|
||||||
@ -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__ */
|
||||||
@ -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 */
|
||||||
|
}
|
||||||
@ -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__ */
|
||||||
Loading…
Reference in New Issue