From e710b06669364e4d174534d60b4af20aaface712 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 15 Dec 2018 21:25:45 +0100 Subject: [PATCH] detect: add file.name sticky buffer --- src/detect-engine-register.h | 1 + src/detect-filename.c | 229 ++++++++++++++++++++++++++++++++++- 2 files changed, 229 insertions(+), 1 deletion(-) diff --git a/src/detect-engine-register.h b/src/detect-engine-register.h index 3fa2e4ad0c..a871ad41e4 100644 --- a/src/detect-engine-register.h +++ b/src/detect-engine-register.h @@ -175,6 +175,7 @@ enum { DETECT_STREAM_EVENT, DETECT_FILENAME, + DETECT_FILE_NAME, DETECT_FILEEXT, DETECT_FILESTORE, DETECT_FILEMAGIC, diff --git a/src/detect-filename.c b/src/detect-filename.c index 9bb6b1c124..1ffb55d5f2 100644 --- a/src/detect-filename.c +++ b/src/detect-filename.c @@ -35,6 +35,8 @@ #include "detect-engine-mpm.h" #include "detect-engine-state.h" #include "detect-engine-file.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-content-inspection.h" #include "flow.h" #include "flow-var.h" @@ -55,9 +57,20 @@ static int DetectFilenameMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, File *, const Signature *, const SigMatchCtx *); static int DetectFilenameSetup (DetectEngineCtx *, Signature *, const char *); +static int DetectFilenameSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str); static void DetectFilenameRegisterTests(void); static void DetectFilenameFree(void *); static int g_file_match_list_id = 0; +static int g_file_name_buffer_id = 0; + +static int PrefilterMpmFilenameRegister(DetectEngineCtx *de_ctx, + SigGroupHead *sgh, MpmCtx *mpm_ctx, + const DetectMpmAppLayerRegistery *mpm_reg, int list_id); +static int DetectEngineInspectFilename( + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const DetectEngineAppInspectionEngine *engine, + const Signature *s, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id); /** * \brief Registration function for keyword: filename @@ -73,6 +86,12 @@ void DetectFilenameRegister(void) sigmatch_table[DETECT_FILENAME].RegisterTests = DetectFilenameRegisterTests; sigmatch_table[DETECT_FILENAME].flags = SIGMATCH_QUOTES_OPTIONAL|SIGMATCH_HANDLE_NEGATION; + sigmatch_table[DETECT_FILE_NAME].name = "file.name"; + sigmatch_table[DETECT_FILE_NAME].desc = "sticky buffer to match on the file name"; + sigmatch_table[DETECT_FILE_NAME].url = DOC_URL DOC_VERSION "/rules/file-keywords.html#filename"; + sigmatch_table[DETECT_FILE_NAME].Setup = DetectFilenameSetupSticky; + sigmatch_table[DETECT_FILE_NAME].flags = SIGMATCH_NOOPT|SIGMATCH_INFO_STICKY_BUFFER; + DetectAppLayerInspectEngineRegister("files", ALPROTO_HTTP, SIG_FLAG_TOSERVER, HTP_REQUEST_BODY, DetectFileInspectGeneric); @@ -94,7 +113,6 @@ void DetectFilenameRegister(void) DetectAppLayerInspectEngineRegister("files", ALPROTO_FTPDATA, SIG_FLAG_TOSERVER, 0, DetectFileInspectGeneric); - DetectAppLayerInspectEngineRegister("files", ALPROTO_FTPDATA, SIG_FLAG_TOCLIENT, 0, DetectFileInspectGeneric); @@ -108,6 +126,34 @@ void DetectFilenameRegister(void) g_file_match_list_id = DetectBufferTypeGetByName("files"); + AppProto protos_ts[] = { + ALPROTO_HTTP, ALPROTO_SMTP, ALPROTO_FTP, ALPROTO_SMB, ALPROTO_NFS, 0 }; + AppProto protos_tc[] = { + ALPROTO_HTTP, ALPROTO_FTP, ALPROTO_SMB, ALPROTO_NFS, 0 }; + + for (int i = 0; protos_ts[i] != 0; i++) { + DetectAppLayerInspectEngineRegister2("file.name", protos_ts[i], + SIG_FLAG_TOSERVER, 0, + DetectEngineInspectFilename, NULL); + + DetectAppLayerMpmRegister2("file.name", SIG_FLAG_TOSERVER, 2, + PrefilterMpmFilenameRegister, NULL, protos_ts[i], + 0); + } + for (int i = 0; protos_tc[i] != 0; i++) { + DetectAppLayerInspectEngineRegister2("file.name", protos_tc[i], + SIG_FLAG_TOCLIENT, 0, + DetectEngineInspectFilename, NULL); + + DetectAppLayerMpmRegister2("file.name", SIG_FLAG_TOCLIENT, 2, + PrefilterMpmFilenameRegister, NULL, protos_tc[i], + 0); + } + + DetectBufferTypeSetDescriptionByName("file.name", + "http user agent"); + + g_file_name_buffer_id = DetectBufferTypeGetByName("file.name"); SCLogDebug("registering filename rule option"); return; } @@ -282,8 +328,187 @@ static void DetectFilenameFree(void *ptr) } } +/* file.name implementation */ + +/** + * \brief this function setup the file.data keyword used in the rule + * + * \param de_ctx Pointer to the Detection Engine Context + * \param s Pointer to the Signature to which the current keyword belongs + * \param str Should hold an empty string always + * + * \retval 0 On success + */ +static int DetectFilenameSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + if (DetectBufferSetActiveList(s, g_file_name_buffer_id) < 0) + return -1; + return 0; +} + +static InspectionBuffer *FilenameGetDataCallback(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, + Flow *f, uint8_t flow_flags, File *cur_file, + int list_id, int local_file_id, bool first) +{ + SCEnter(); + + InspectionBufferMultipleForList *fb = InspectionBufferGetMulti(det_ctx, list_id); + InspectionBuffer *buffer = InspectionBufferMultipleForListGet(fb, local_file_id); + if (buffer == NULL) + return NULL; + if (!first && buffer->inspect != NULL) + return buffer; + + const uint8_t *data = cur_file->name; + uint32_t data_len = cur_file->name_len; + + InspectionBufferSetup(buffer, data, data_len); + InspectionBufferApplyTransforms(buffer, transforms); + + SCReturnPtr(buffer, "InspectionBuffer"); +} + +static int DetectEngineInspectFilename( + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const DetectEngineAppInspectionEngine *engine, + const Signature *s, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) +{ + int r = 0; + + const DetectEngineTransforms *transforms = NULL; + if (!engine->mpm) { + transforms = engine->v2.transforms; + } + + FileContainer *ffc = AppLayerParserGetFiles(f->proto, f->alproto, + f->alstate, flags); + if (ffc == NULL) { + return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; + } + + int local_file_id = 0; + File *file = ffc->head; + for (; file != NULL; file = file->next) { + if (file->txid != tx_id) + continue; + + InspectionBuffer *buffer = FilenameGetDataCallback(det_ctx, + transforms, f, flags, file, engine->sm_list, local_file_id, false); + if (buffer == NULL) + continue; + + det_ctx->buffer_offset = 0; + det_ctx->discontinue_matching = 0; + det_ctx->inspection_recursion_counter = 0; + int match = DetectEngineContentInspection(de_ctx, det_ctx, s, engine->smd, + f, + (uint8_t *)buffer->inspect, + buffer->inspect_len, + buffer->inspect_offset, DETECT_CI_FLAGS_SINGLE, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); + if (match == 1) { + r = 1; + break; + } + local_file_id++; + } + + if (r == 1) + return DETECT_ENGINE_INSPECT_SIG_MATCH; + else + return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; +} + +typedef struct PrefilterMpmFilename { + int list_id; + const MpmCtx *mpm_ctx; + const DetectEngineTransforms *transforms; +} PrefilterMpmFilename; + +/** \brief Filedata Filedata Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxFilename(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) +{ + SCEnter(); + + const PrefilterMpmFilename *ctx = (const PrefilterMpmFilename *)pectx; + const MpmCtx *mpm_ctx = ctx->mpm_ctx; + const int list_id = ctx->list_id; + + FileContainer *ffc = AppLayerParserGetFiles(f->proto, f->alproto, + f->alstate, flags); + int local_file_id = 0; + if (ffc != NULL) { + File *file = ffc->head; + for (; file != NULL; file = file->next) { + if (file->txid != idx) + continue; + + InspectionBuffer *buffer = FilenameGetDataCallback(det_ctx, + ctx->transforms, f, flags, file, list_id, local_file_id, true); + if (buffer == NULL) + continue; + + if (buffer->inspect_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, + buffer->inspect, buffer->inspect_len); + } + } + } +} + +static void PrefilterMpmFilenameFree(void *ptr) +{ + SCFree(ptr); +} + +static int PrefilterMpmFilenameRegister(DetectEngineCtx *de_ctx, + SigGroupHead *sgh, MpmCtx *mpm_ctx, + const DetectMpmAppLayerRegistery *mpm_reg, int list_id) +{ + PrefilterMpmFilename *pectx = SCCalloc(1, sizeof(*pectx)); + if (pectx == NULL) + return -1; + pectx->list_id = list_id; + pectx->mpm_ctx = mpm_ctx; + pectx->transforms = &mpm_reg->v2.transforms; + + return PrefilterAppendTxEngine(de_ctx, sgh, PrefilterTxFilename, + mpm_reg->v2.alproto, mpm_reg->v2.tx_min_progress, + pectx, PrefilterMpmFilenameFree, mpm_reg->pname); +} + #ifdef UNITTESTS /* UNITTESTS */ +/** + * \test Test parser accepting valid rules and rejecting invalid rules + */ +static int DetectFilenameSignatureParseTest01(void) +{ + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_client; file.name; content:\"abc\"; sid:1;)", true)); + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_client; file.name; content:\"abc\"; nocase; sid:1;)", true)); + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_client; file.name; content:\"abc\"; endswith; sid:1;)", true)); + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_client; file.name; content:\"abc\"; startswith; sid:1;)", true)); + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_client; file.name; content:\"abc\"; startswith; endswith; sid:1;)", true)); + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_client; file.name; bsize:10; sid:1;)", true)); + + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_client; file.name; content:\"abc\"; rawbytes; sid:1;)", false)); + FAIL_IF_NOT(UTHParseSignature("alert tcp any any -> any any (flow:to_client; file.name; sid:1;)", false)); + //FAIL_IF_NOT(UTHParseSignature("alert tls any any -> any any (flow:to_client; file.name; content:\"abc\"; sid:1;)", false)); + PASS; +} /** * \test DetectFilenameTestParse01 */ @@ -343,6 +568,8 @@ static int DetectFilenameTestParse03 (void) void DetectFilenameRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ + UtRegisterTest("DetectFilenameSignatureParseTest01", DetectFilenameSignatureParseTest01); + UtRegisterTest("DetectFilenameTestParse01", DetectFilenameTestParse01); UtRegisterTest("DetectFilenameTestParse02", DetectFilenameTestParse02); UtRegisterTest("DetectFilenameTestParse03", DetectFilenameTestParse03); -- 2.47.2