?? snort_smtp.c
字號:
/**************************************************************************** * * Copyright (C) 2005-2007 Sourcefire Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * 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 * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ****************************************************************************//************************************************************************** * snort_smtp.c * * Author: Andy Mullican * Author: Todd Wease * * Description: * * This file handles SMTP protocol checking and normalization. * * Entry point functions: * * SnortSMTP() * SMTP_Init() * SMTP_Free() * **************************************************************************//* Includes ***************************************************************/#ifdef HAVE_CONFIG_H#include "config.h"#endif#include <sys/types.h>#include "sf_types.h"#include <stdlib.h>#include <string.h>#include <ctype.h>#include <pcre.h>#include "snort_smtp.h"#include "smtp_config.h"#include "smtp_normalize.h"#include "smtp_util.h"#include "smtp_log.h"#include "smtp_xlink2state.h"#include "sf_snort_packet.h"#include "stream_api.h"#include "debug.h"#include "profiler.h"#include "bounds.h"#include "sf_dynamic_preprocessor.h"/**************************************************************************//* Externs ****************************************************************/#ifdef PERF_PROFILINGextern PreprocStats smtpDetectPerfStats;extern int smtpDetectCalled;#endifextern SMTPConfig _smtp_config;extern SMTPCmdConfig *_smtp_cmd_config;extern DynamicPreprocessorData _dpd;#ifdef DEBUGextern char smtp_print_buffer[];#endif/**************************************************************************//* Globals ****************************************************************/SMTP *_smtp = NULL;SMTP _smtp_no_session;SMTPPcre _mime_boundary_pcre;char _smtp_pkt_direction;char _smtp_normalizing;SMTPSearchInfo _smtp_search_info;const SMTPToken _smtp_known_cmds[] ={ {"ATRN", 4, CMD_ATRN}, {"AUTH", 4, CMD_AUTH}, {"BDAT", 4, CMD_BDAT}, {"DATA", 4, CMD_DATA}, {"DEBUG", 5, CMD_DEBUG}, {"EHLO", 4, CMD_EHLO}, {"EMAL", 4, CMD_EMAL}, {"ESAM", 4, CMD_ESAM}, {"ESND", 4, CMD_ESND}, {"ESOM", 4, CMD_ESOM}, {"ETRN", 4, CMD_ETRN}, {"EVFY", 4, CMD_EVFY}, {"EXPN", 4, CMD_EXPN}, {"HELO", 4, CMD_HELO}, {"HELP", 4, CMD_HELP}, {"IDENT", 5, CMD_IDENT}, {"MAIL", 4, CMD_MAIL}, {"NOOP", 4, CMD_NOOP}, {"ONEX", 4, CMD_ONEX}, {"QUEU", 4, CMD_QUEU}, {"QUIT", 4, CMD_QUIT}, {"RCPT", 4, CMD_RCPT}, {"RSET", 4, CMD_RSET}, {"SAML", 4, CMD_SAML}, {"SEND", 4, CMD_SEND}, {"SIZE", 4, CMD_SIZE}, {"STARTTLS", 8, CMD_STARTTLS}, {"SOML", 4, CMD_SOML}, {"TICK", 4, CMD_TICK}, {"TIME", 4, CMD_TIME}, {"TURN", 4, CMD_TURN}, {"TURNME", 6, CMD_TURNME}, {"VERB", 4, CMD_VERB}, {"VRFY", 4, CMD_VRFY}, {"X-EXPS", 6, CMD_X_EXPS}, {"XADR", 4, CMD_XADR}, {"XAUTH", 5, CMD_XAUTH}, {"XCIR", 4, CMD_XCIR}, {"XEXCH50", 7, CMD_XEXCH50}, {"XGEN", 4, CMD_XGEN}, {"XLICENSE", 8, CMD_XLICENSE}, {"X-LINK2STATE", 12, CMD_X_LINK2STATE}, {"XQUE", 4, CMD_XQUE}, {"XSTA", 4, CMD_XSTA}, {"XTRN", 4, CMD_XTRN}, {"XUSR", 4, CMD_XUSR}, {NULL, 0, 0}};/* new commands can be allocated via the smtp configuration */SMTPToken *_smtp_cmds;SMTPSearch *_smtp_cmd_search;const SMTPToken _smtp_resps[] ={ {"220", 3, RESP_220}, /* Service ready - initial response and STARTTLS response */ {"250", 3, RESP_250}, /* Requested mail action okay, completed */ {"354", 3, RESP_354}, /* Start mail input - data response */ {"421", 3, RESP_421}, /* Service not availiable - closes connection */ {"450", 3, RESP_450}, /* Mailbox unavailable */ {"451", 3, RESP_451}, /* Local error in processing */ {"452", 3, RESP_452}, /* Insufficient system storage */ {"500", 3, RESP_500}, /* Command unrecognized */ {"501", 3, RESP_501}, /* Syntax error in parameters or arguments */ {"502", 3, RESP_502}, /* Command not implemented */ {"503", 3, RESP_503}, /* Bad sequence of commands */ {"504", 3, RESP_504}, /* Command parameter not implemented */ {"550", 3, RESP_550}, /* Action not taken - mailbox unavailable */ {"551", 3, RESP_551}, /* User not local; please try <forward-path> */ {"552", 3, RESP_552}, /* Mail action aborted: exceeded storage allocation */ {"553", 3, RESP_553}, /* Action not taken: mailbox name not allowed */ {"554", 3, RESP_554}, /* Transaction failed */ {NULL, 0, 0}};SMTPSearch _smtp_resp_search[RESP_LAST];const SMTPToken _smtp_hdrs[] ={ {"Content-type:", 13, HDR_CONTENT_TYPE}, {NULL, 0, 0}};SMTPSearch _smtp_hdr_search[HDR_LAST];const SMTPToken _smtp_data_end[] ={ {"\r\n.\r\n", 5, DATA_END_1}, {"\n.\r\n", 4, DATA_END_2}, {"\r\n.\n", 4, DATA_END_3}, {"\n.\n", 3, DATA_END_4}, {NULL, 0, 0}};SMTPSearch _smtp_data_end_search[DATA_END_LAST];SMTPSearch *_smtp_current_search;/**************************************************************************//* Private functions ******************************************************/static void SMTP_Setup(SFSnortPacket *);static void SMTP_ResetState(void);static void SMTP_SessionFree(void *);static void SMTP_NoSessionFree(void);static int SMTP_GetPacketDirection(SFSnortPacket *, char);static void SMTP_ProcessClientPacket(SFSnortPacket *);static int SMTP_ProcessServerPacket(SFSnortPacket *);static void SMTP_DisableDetect(SFSnortPacket *);static const u_int8_t * SMTP_HandleCommand(SFSnortPacket *, const u_int8_t *, const u_int8_t *);static const u_int8_t * SMTP_HandleData(SFSnortPacket *, const u_int8_t *, const u_int8_t *);static const u_int8_t * SMTP_HandleHeader(SFSnortPacket *, const u_int8_t *, const u_int8_t *);static const u_int8_t * SMTP_HandleDataBody(SFSnortPacket *, const u_int8_t *, const u_int8_t *);static int SMTP_SearchStrFound(void *, int, void *);static int SMTP_BoundaryStrFound(void *, int, void *);static int SMTP_GetBoundary(const char *, int);static int SMTP_IsTlsClientHello(const u_int8_t *, const u_int8_t *);static int SMTP_IsTlsServerHello(const u_int8_t *, const u_int8_t *);/**************************************************************************/void SMTP_InitCmds(void){ const SMTPToken *tmp; /* add one to CMD_LAST for NULL entry */ _smtp_cmds = (SMTPToken *)calloc(CMD_LAST + 1, sizeof(SMTPToken)); if (_smtp_cmds == NULL) { DynamicPreprocessorFatalMessage("%s(%d) => failed to allocate memory for smtp " "command structure\n", *(_dpd.config_file), *(_dpd.config_line)); } for (tmp = &_smtp_known_cmds[0]; tmp->name != NULL; tmp++) { _smtp_cmds[tmp->search_id].name_len = tmp->name_len; _smtp_cmds[tmp->search_id].search_id = tmp->search_id; _smtp_cmds[tmp->search_id].name = strdup(tmp->name); if (_smtp_cmds[tmp->search_id].name == NULL) { DynamicPreprocessorFatalMessage("%s(%d) => failed to allocate memory for smtp " "command structure\n", *(_dpd.config_file), *(_dpd.config_line)); } } /* initialize memory for command searches */ _smtp_cmd_search = (SMTPSearch *)calloc(CMD_LAST, sizeof(SMTPSearch)); if (_smtp_cmd_search == NULL) { DynamicPreprocessorFatalMessage("%s(%d) => failed to allocate memory for smtp " "command structure\n", *(_dpd.config_file), *(_dpd.config_line)); }}/* * Initialize SMTP searches * * @param none * * @return none */void SMTP_SearchInit(void){ const char *error; int erroffset; const SMTPToken *tmp; /* Initialize searches */ _dpd.searchAPI->search_init(NUM_SEARCHES); /* Command search */ for (tmp = _smtp_cmds; tmp->name != NULL; tmp++) { _smtp_cmd_search[tmp->search_id].name = tmp->name; _smtp_cmd_search[tmp->search_id].name_len = tmp->name_len; _dpd.searchAPI->search_add(SEARCH_CMD, tmp->name, tmp->name_len, tmp->search_id); } _dpd.searchAPI->search_prep(SEARCH_CMD); /* Response search */ for (tmp = &_smtp_resps[0]; tmp->name != NULL; tmp++) { _smtp_resp_search[tmp->search_id].name = tmp->name; _smtp_resp_search[tmp->search_id].name_len = tmp->name_len; _dpd.searchAPI->search_add(SEARCH_RESP, tmp->name, tmp->name_len, tmp->search_id); } _dpd.searchAPI->search_prep(SEARCH_RESP); /* Header search */ for (tmp = &_smtp_hdrs[0]; tmp->name != NULL; tmp++) { _smtp_hdr_search[tmp->search_id].name = tmp->name; _smtp_hdr_search[tmp->search_id].name_len = tmp->name_len; _dpd.searchAPI->search_add(SEARCH_HDR, tmp->name, tmp->name_len, tmp->search_id); } _dpd.searchAPI->search_prep(SEARCH_HDR); /* Data end search */ for (tmp = &_smtp_data_end[0]; tmp->name != NULL; tmp++) { _smtp_data_end_search[tmp->search_id].name = tmp->name; _smtp_data_end_search[tmp->search_id].name_len = tmp->name_len; _dpd.searchAPI->search_add(SEARCH_DATA_END, tmp->name, tmp->name_len, tmp->search_id); } _dpd.searchAPI->search_prep(SEARCH_DATA_END); /* create regex for finding boundary string - since it can be cut across multiple * lines, a straight search won't do. Shouldn't be too slow since it will most * likely only be acting on a small portion of data */ //"^content-type:\\s*multipart.*boundary\\s*=\\s*\"?([^\\s]+)\"?" //"^\\s*multipart.*boundary\\s*=\\s*\"?([^\\s]+)\"?" //_mime_boundary_pcre.re = pcre_compile("^.*boundary\\s*=\\s*\"?([^\\s\"]+)\"?", //_mime_boundary_pcre.re = pcre_compile("boundary(?:\n|\r\n)?=(?:\n|\r\n)?\"?([^\\s\"]+)\"?", _mime_boundary_pcre.re = pcre_compile("boundary\\s*=\\s*\"?([^\\s\"]+)\"?", PCRE_CASELESS | PCRE_DOTALL, &error, &erroffset, NULL); if (_mime_boundary_pcre.re == NULL) { DynamicPreprocessorFatalMessage("Failed to compile pcre regex for getting boundary " "in a multipart SMTP message: %s\n", error); } _mime_boundary_pcre.pe = pcre_study(_mime_boundary_pcre.re, 0, &error); if (error != NULL) { DynamicPreprocessorFatalMessage("Failed to study pcre regex for getting boundary " "in a multipart SMTP message: %s\n", error); }}/* * Initialize run-time boundary search */static int SMTP_BoundarySearchInit(void){ _smtp->mime_boundary.boundary_search = _dpd.searchAPI->search_instance_new(); if (_smtp->mime_boundary.boundary_search == NULL) return -1; _dpd.searchAPI->search_instance_add(_smtp->mime_boundary.boundary_search, _smtp->mime_boundary.boundary, _smtp->mime_boundary.boundary_len, BOUNDARY); _dpd.searchAPI->search_instance_prep(_smtp->mime_boundary.boundary_search); return 0;}/* * Reset SMTP session state * * @param none * * @return none */static void SMTP_ResetState(void){ /* save this so we know whether or not to flush when we get 354 data response */ int save_state_flags = _smtp->state_flags & (SMTP_FLAG_GOT_DATA_CMD | SMTP_FLAG_GOT_DATA_RESP); if (_smtp->mime_boundary.boundary_search != NULL) { _dpd.searchAPI->search_instance_free(_smtp->mime_boundary.boundary_search); _smtp->mime_boundary.boundary_search = NULL; } _smtp->state = STATE_COMMAND; _smtp->data_state = STATE_DATA_INIT; _smtp->state_flags = save_state_flags; memset(&_smtp->mime_boundary, 0, sizeof(SMTPMimeBoundary));}/* * Given a server configuration and a port number, we decide if the port is * in the SMTP server port list. * * @param port the port number to compare with the configuration * * @return integer * @retval 0 means that the port is not a server port * @retval !0 means that the port is a server port */int SMTP_IsServer(u_int16_t port){ if (_smtp_config.ports[port / 8] & (1 << (port % 8))) { return 1; } return 0;}/* * Do first-packet setup * * @param p standard Packet structure * * @return none */static void SMTP_Setup(SFSnortPacket *p){ /* reset normalization stuff */ _smtp_normalizing = 0;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -