From: Giuseppe Longo Date: Tue, 20 Jan 2015 16:38:06 +0000 (+0100) Subject: Detect engine for smtp file_data file_data: inspecting smtp attachments X-Git-Tag: suricata-2.1beta4~11 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=f0c54d47648bd7e973bd315fc0c2d1351af50d02;p=thirdparty%2Fsuricata.git Detect engine for smtp file_data file_data: inspecting smtp attachments Create a buffer to store reassembled file chunks, and inspect the content. --- diff --git a/src/Makefile.am b/src/Makefile.am index d802d21174..aacf9eccd0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -96,6 +96,7 @@ detect-engine-dns.c detect-engine-dns.h \ detect-engine-modbus.c detect-engine-modbus.h \ detect-engine-event.c detect-engine-event.h \ detect-engine-file.c detect-engine-file.h \ +detect-engine-filedata-smtp.c detect-engine-filedata-smtp.h \ detect-engine-hcbd.c detect-engine-hcbd.h \ detect-engine-hcd.c detect-engine-hcd.h \ detect-engine-hhd.c detect-engine-hhd.h \ diff --git a/src/detect-engine-content-inspection.h b/src/detect-engine-content-inspection.h index ab12c25118..6d3accaaa3 100644 --- a/src/detect-engine-content-inspection.h +++ b/src/detect-engine-content-inspection.h @@ -49,6 +49,7 @@ enum { DETECT_ENGINE_CONTENT_INSPECTION_MODE_HHHD, DETECT_ENGINE_CONTENT_INSPECTION_MODE_HRHHD, DETECT_ENGINE_CONTENT_INSPECTION_MODE_DNSQUERY, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_FD_SMTP, }; int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, diff --git a/src/detect-engine-filedata-smtp.c b/src/detect-engine-filedata-smtp.c new file mode 100644 index 0000000000..6cd1adb868 --- /dev/null +++ b/src/detect-engine-filedata-smtp.c @@ -0,0 +1,217 @@ +/* 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 Giuseppe Longo + * + */ + +#include "suricata-common.h" +#include "suricata.h" +#include "decode.h" + +#include "detect.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-parse.h" +#include "detect-engine-state.h" +#include "detect-engine-content-inspection.h" + +#include "flow-util.h" +#include "util-debug.h" +#include "util-print.h" +#include "flow.h" + +#include "stream-tcp.h" + +#include "app-layer-parser.h" + +#include "util-unittest.h" +#include "util-unittest-helper.h" +#include "app-layer.h" +#include "app-layer-smtp.h" +#include "app-layer-protos.h" + +#include "conf.h" +#include "conf-yaml-loader.h" + +#define BUFFER_STEP 50 + +static inline int SMTPCreateSpace(DetectEngineThreadCtx *det_ctx, uint16_t size) +{ + void *ptmp; + if (size > det_ctx->smtp_buffers_size) { + ptmp = SCRealloc(det_ctx->smtp, + (det_ctx->smtp_buffers_size + BUFFER_STEP) * sizeof(FiledataReassembledBody)); + if (ptmp == NULL) { + SCFree(det_ctx->hsbd); + det_ctx->smtp = NULL; + det_ctx->smtp_buffers_size = 0; + det_ctx->smtp_buffers_list_len = 0; + return -1; + } + det_ctx->smtp = ptmp; + + memset(det_ctx->smtp + det_ctx->smtp_buffers_size, 0, BUFFER_STEP * sizeof(FiledataReassembledBody)); + det_ctx->smtp_buffers_size += BUFFER_STEP; + } + for (int i = det_ctx->smtp_buffers_list_len; i < (size); i++) { + det_ctx->smtp[i].buffer_len = 0; + det_ctx->smtp[i].offset = 0; + } + + return 0; +} + +static uint8_t *DetectEngineSMTPGetBufferForTX(uint64_t tx_id, + DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, + Flow *f, File *curr_file, + uint8_t flags, + uint32_t *buffer_len, + uint32_t *stream_start_offset) +{ + int index = 0; + uint8_t *buffer = NULL; + *buffer_len = 0; + *stream_start_offset = 0; + FileData *curr_chunk = NULL; + + if (det_ctx->smtp_buffers_list_len == 0) { + if (SMTPCreateSpace(det_ctx, 1) < 0) + goto end; + index = 0; + + if (det_ctx->smtp_buffers_list_len == 0) { + det_ctx->smtp_start_tx_id = tx_id; + } + det_ctx->smtp_buffers_list_len++; + } else { + if ((tx_id - det_ctx->smtp_start_tx_id) < det_ctx->smtp_buffers_list_len) { + if (det_ctx->smtp[(tx_id - det_ctx->smtp_start_tx_id)].buffer_len != 0) { + *buffer_len = det_ctx->smtp[(tx_id - det_ctx->smtp_start_tx_id)].buffer_len; + *stream_start_offset = det_ctx->smtp[(tx_id - det_ctx->smtp_start_tx_id)].offset; + return det_ctx->smtp[(tx_id - det_ctx->smtp_start_tx_id)].buffer; + } + } else { + if (SMTPCreateSpace(det_ctx, (tx_id - det_ctx->smtp_start_tx_id) + 1) < 0) + goto end; + + if (det_ctx->smtp_buffers_list_len == 0) { + det_ctx->smtp_start_tx_id = tx_id; + } + det_ctx->smtp_buffers_list_len++; + } + index = (tx_id - det_ctx->smtp_start_tx_id); + } + + if (curr_file != NULL) { + curr_chunk = curr_file->chunks_head; + while (curr_chunk != NULL) { + /* see if we can filter out chunks */ + + /* see if we need to grow the buffer */ + if (det_ctx->smtp[index].buffer == NULL || (det_ctx->smtp[index].buffer_len + curr_chunk->len) > det_ctx->smtp[index].buffer_size) { + void *ptmp; + det_ctx->smtp[index].buffer_size += curr_chunk->len * 2; + + if ((ptmp = SCRealloc(det_ctx->smtp[index].buffer, det_ctx->smtp[index].buffer_size)) == NULL) { + SCFree(det_ctx->smtp[index].buffer); + det_ctx->smtp[index].buffer = NULL; + det_ctx->smtp[index].buffer_size = 0; + det_ctx->smtp[index].buffer_len = 0; + goto end; + } + det_ctx->smtp[index].buffer = ptmp; + } + memcpy(det_ctx->smtp[index].buffer + det_ctx->smtp[index].buffer_len, curr_chunk->data, curr_chunk->len); + det_ctx->smtp[index].buffer_len += curr_chunk->len; + + curr_chunk = curr_chunk->next; + } + } + + buffer = det_ctx->smtp[index].buffer; + *buffer_len = det_ctx->smtp[index].buffer_len; + *stream_start_offset = det_ctx->smtp[index].offset; +end: + return buffer; +} + +int DetectEngineInspectSMTPFiledata(ThreadVars *tv, + DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, + Signature *s, Flow *f, uint8_t flags, + void *alstate, + void *tx, uint64_t tx_id) +{ + SMTPState *smtp_state = (SMTPState *)alstate; + FileContainer *ffc = smtp_state->files_ts; + int r = 0; + int match = 0; + uint32_t buffer_len = 0; + uint32_t stream_start_offset = 0; + uint8_t *buffer = 0; + + if (ffc != NULL) { + File *file = ffc->head; + for (; file != NULL; file = file->next) { + buffer = DetectEngineSMTPGetBufferForTX(tx_id, + de_ctx, det_ctx, + f, file, + flags, + &buffer_len, + &stream_start_offset); + if (buffer_len == 0) + goto end; + + det_ctx->buffer_offset = 0; + det_ctx->discontinue_matching = 0; + det_ctx->inspection_recursion_counter = 0; + match = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_FILEDATA], + f, + buffer, + buffer_len, + stream_start_offset, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_FD_SMTP, NULL); + if (match == 1) + r = 1; + } + } + +end: + if (r == 1) + return DETECT_ENGINE_INSPECT_SIG_MATCH; + else + return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; +} + +void DetectEngineCleanSMTPBuffers(DetectEngineThreadCtx *det_ctx) +{ + if (det_ctx->smtp_buffers_list_len > 0) { + for (int i = 0; i < det_ctx->smtp_buffers_list_len; i++) { + det_ctx->smtp[i].buffer_len = 0; + det_ctx->smtp[i].offset = 0; + } + } + det_ctx->smtp_buffers_list_len = 0; + det_ctx->smtp_start_tx_id = 0; + + return; +} diff --git a/src/detect-engine-filedata-smtp.h b/src/detect-engine-filedata-smtp.h new file mode 100644 index 0000000000..b574b974c2 --- /dev/null +++ b/src/detect-engine-filedata-smtp.h @@ -0,0 +1,34 @@ +/* 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 Giuseppe Longo + */ + +#ifndef __DETECT_ENGINE_FILEDATA_SMTP_H__ +#define __DETECT_ENGINE_FILEDATA_SMTP_H__ + +int DetectEngineInspectSMTPFiledata(ThreadVars *tv, + DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, + Signature *s, Flow *f, uint8_t flags, + void *alstate, + void *tx, uint64_t tx_id); +void DetectEngineCleanSMTPBuffers(DetectEngineThreadCtx *det_ctx); + +#endif /* __DETECT_ENGINE_FILEDATA_SMTP_H__ */ diff --git a/src/detect-engine-state.h b/src/detect-engine-state.h index 464f7180fd..ab30ccffed 100644 --- a/src/detect-engine-state.h +++ b/src/detect-engine-state.h @@ -78,6 +78,7 @@ #define DE_STATE_FLAG_APP_EVENT_INSPECT (1 << 18) #define DE_STATE_FLAG_MODBUS_INSPECT (1 << 19) #define DE_STATE_FLAG_HRL_INSPECT (1 << 20) +#define DE_STATE_FLAG_FD_SMTP_INSPECT (1 << 21) /* state flags */ #define DETECT_ENGINE_STATE_FLAG_FILE_STORE_DISABLED 0x0001 diff --git a/src/detect-engine.c b/src/detect-engine.c index 02c317ea01..742a2560c9 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -61,6 +61,7 @@ #include "detect-engine-file.h" #include "detect-engine-dns.h" #include "detect-engine-modbus.h" +#include "detect-engine-filedata-smtp.h" #include "detect-engine.h" #include "detect-engine-state.h" @@ -274,6 +275,14 @@ void DetectEngineRegisterAppInspectionEngines(void) DE_STATE_FLAG_MODBUS_INSPECT, 0, DetectEngineInspectModbus }, + /* file_data smtp */ + { IPPROTO_TCP, + ALPROTO_SMTP, + DETECT_SM_LIST_FILEDATA, + DE_STATE_FLAG_FD_SMTP_INSPECT, + DE_STATE_FLAG_FD_SMTP_INSPECT, + 0, + DetectEngineInspectSMTPFiledata }, }; struct tmp_t data_toclient[] = { diff --git a/src/detect.h b/src/detect.h index 5cec5aa58e..f34b46c7d0 100644 --- a/src/detect.h +++ b/src/detect.h @@ -767,6 +767,13 @@ typedef struct HttpReassembledBody_ { uint64_t offset; /**< data offset */ } HttpReassembledBody; +typedef struct FiledataReassembledBody_ { + uint8_t *buffer; + uint32_t buffer_size; /**< size of the buffer itself */ + uint32_t buffer_len; /**< data len in the buffer */ + uint64_t offset; /**< data offset */ +} FiledataReassembledBody; + #define DETECT_FILESTORE_MAX 15 /** \todo review how many we actually need here */ #define DETECT_SMSG_PMQ_NUM 256 @@ -812,6 +819,11 @@ typedef struct DetectEngineThreadCtx_ { uint16_t hhd_buffers_list_len; uint64_t hhd_start_tx_id; + FiledataReassembledBody *smtp; + uint64_t smtp_start_tx_id; + uint16_t smtp_buffers_size; + uint16_t smtp_buffers_list_len; + /** id for alert counter */ uint16_t counter_alerts; #ifdef PROFILING