From: Russ Combs (rucombs) Date: Wed, 10 Aug 2016 18:24:29 +0000 (-0400) Subject: Merge pull request #584 in SNORT/snort3 from smtp_auth_overflow to master X-Git-Tag: 3.0.0-233~302 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=a6b74b3;p=thirdparty%2Fsnort3.git Merge pull request #584 in SNORT/snort3 from smtp_auth_overflow to master Squashed commit of the following: commit d0562da0307b36867e78604d8f0065c6b4a5ebb0 Author: Bhagya Tholpady Date: Tue Aug 9 13:51:38 2016 -0400 SMTP AUTH overflow alert added reverting the STARTTLS smtp paf change reverting the STARTTLS smtp paf change adding snort2lua change for smtp max_auth_command_line_len option remove the starttls command processing in SMTP splitter --- diff --git a/src/service_inspectors/smtp/smtp.cc b/src/service_inspectors/smtp/smtp.cc index 3cee5f980..0d2ce7596 100644 --- a/src/service_inspectors/smtp/smtp.cc +++ b/src/service_inspectors/smtp/smtp.cc @@ -447,6 +447,9 @@ static void SMTP_PrintConfig(SMTP_PROTO_CONF *config) else LogMessage("%s%d\n", buf, config->max_header_line_len); + snprintf(buf, sizeof(buf) - 1, " Max Auth Command Line Length: "); + LogMessage("%s%d\n", buf, config->max_auth_command_line_len); + snprintf(buf, sizeof(buf) - 1, " Max Response Line Length: "); if (config->max_response_line_len == 0) @@ -1500,7 +1503,7 @@ public: void clear(Packet*) override; StreamSplitter* get_splitter(bool c2s) override - { return new SmtpSplitter(c2s); } + { return new SmtpSplitter(c2s, config->max_auth_command_line_len); } void ProcessSmtpCmdsList(const SmtpCmd*); diff --git a/src/service_inspectors/smtp/smtp_config.h b/src/service_inspectors/smtp/smtp_config.h index f08d92464..4596e18d9 100644 --- a/src/service_inspectors/smtp/smtp_config.h +++ b/src/service_inspectors/smtp/smtp_config.h @@ -123,9 +123,10 @@ struct SMTP_PROTO_CONF { NORM_TYPES normalize; bool ignore_tls_data; - int max_command_line_len; - int max_header_line_len; - int max_response_line_len; + int max_auth_command_line_len = 1000; + int max_command_line_len = 0; + int max_header_line_len = 0; + int max_response_line_len = 0; int xlink2state; MailLogConfig log_config; DecodeConfig decode_conf; diff --git a/src/service_inspectors/smtp/smtp_module.cc b/src/service_inspectors/smtp/smtp_module.cc index b9d35ba47..4d4bd5448 100644 --- a/src/service_inspectors/smtp/smtp_module.cc +++ b/src/service_inspectors/smtp/smtp_module.cc @@ -46,19 +46,6 @@ SmtpCmd::SmtpCmd(std::string& key, int num) } } -#define SMTP_COMMAND_OVERFLOW_STR "Attempted command buffer overflow" -#define SMTP_DATA_HDR_OVERFLOW_STR "Attempted data header buffer overflow" -#define SMTP_RESPONSE_OVERFLOW_STR "Attempted response buffer overflow" -#define SMTP_SPECIFIC_CMD_OVERFLOW_STR "Attempted specific command buffer overflow" -#define SMTP_UNKNOWN_CMD_STR "Unknown command" -#define SMTP_ILLEGAL_CMD_STR "Illegal command" -#define SMTP_HEADER_NAME_OVERFLOW_STR "Attempted header name buffer overflow" -#define SMTP_XLINK2STATE_OVERFLOW_STR "Attempted X-Link2State command buffer overflow" -#define SMTP_B64_DECODING_FAILED_STR "Base64 Decoding failed." -#define SMTP_QP_DECODING_FAILED_STR "Quoted-Printable Decoding failed." -#define SMTP_UU_DECODING_FAILED_STR "Unix-to-Unix Decoding failed." -#define SMTP_AUTH_ABORT_AUTH_STR "Cyrus SASL authentication attack." - static const Parameter smtp_command_params[] = { { "command", Parameter::PT_STRING, nullptr, nullptr, @@ -114,6 +101,9 @@ static const Parameter s_params[] = { "log_rcptto", Parameter::PT_BOOL, nullptr, "false", "log the recipient's email address extracted from the RCPT TO command" }, + { "max_auth_command_line_len", Parameter::PT_INT, "0:65535", "1000", + "max auth command Line Length" }, + { "max_command_line_len", Parameter::PT_INT, "0:65535", "0", "max Command Line Length" }, @@ -146,18 +136,19 @@ static const Parameter s_params[] = static const RuleMap smtp_rules[] = { - { SMTP_COMMAND_OVERFLOW, SMTP_COMMAND_OVERFLOW_STR }, - { SMTP_DATA_HDR_OVERFLOW, SMTP_DATA_HDR_OVERFLOW_STR }, - { SMTP_RESPONSE_OVERFLOW, SMTP_RESPONSE_OVERFLOW_STR }, - { SMTP_SPECIFIC_CMD_OVERFLOW, SMTP_SPECIFIC_CMD_OVERFLOW_STR }, - { SMTP_UNKNOWN_CMD, SMTP_UNKNOWN_CMD_STR }, - { SMTP_ILLEGAL_CMD, SMTP_ILLEGAL_CMD_STR }, - { SMTP_HEADER_NAME_OVERFLOW, SMTP_HEADER_NAME_OVERFLOW_STR }, - { SMTP_XLINK2STATE_OVERFLOW, SMTP_XLINK2STATE_OVERFLOW_STR }, - { SMTP_B64_DECODING_FAILED, SMTP_B64_DECODING_FAILED_STR }, - { SMTP_QP_DECODING_FAILED, SMTP_QP_DECODING_FAILED_STR }, - { SMTP_UU_DECODING_FAILED, SMTP_UU_DECODING_FAILED_STR }, - { SMTP_AUTH_ABORT_AUTH, SMTP_AUTH_ABORT_AUTH_STR }, + { SMTP_COMMAND_OVERFLOW, "Attempted command buffer overflow" }, + { SMTP_DATA_HDR_OVERFLOW, "Attempted data header buffer overflow" }, + { SMTP_RESPONSE_OVERFLOW, "Attempted response buffer overflow" }, + { SMTP_SPECIFIC_CMD_OVERFLOW, "Attempted specific command buffer overflow" }, + { SMTP_UNKNOWN_CMD, "Unknown command" }, + { SMTP_ILLEGAL_CMD, "Illegal command" }, + { SMTP_HEADER_NAME_OVERFLOW, "Attempted header name buffer overflow" }, + { SMTP_XLINK2STATE_OVERFLOW, "Attempted X-Link2State command buffer overflow" }, + { SMTP_B64_DECODING_FAILED, "Base64 Decoding failed" }, + { SMTP_QP_DECODING_FAILED, "Quoted-Printable Decoding failed" }, + { SMTP_UU_DECODING_FAILED, "Unix-to-Unix Decoding failed" }, + { SMTP_AUTH_ABORT_AUTH, "Cyrus SASL authentication attack" }, + { SMTP_AUTH_COMMAND_OVERFLOW, "Attempted authentication command buffer overflow" }, { 0, nullptr } }; @@ -284,6 +275,9 @@ bool SmtpModule::set(const char*, Value& v, SnortConfig*) else if ( v.is("log_email_hdrs")) config->log_config.log_email_hdrs = v.get_bool(); + else if ( v.is("max_auth_command_line_len") ) + config->max_auth_command_line_len = v.get_long(); + else if ( v.is("max_command_line_len") ) config->max_command_line_len = v.get_long(); @@ -332,9 +326,6 @@ bool SmtpModule::begin(const char*, int, SnortConfig*) if(!config) { config = new SMTP_PROTO_CONF; - config->max_header_line_len = 0; - config->max_response_line_len = 0; - config->max_command_line_len = 0; config->xlink2state = ALERT_XLINK2STATE; config->decode_conf.set_ignore_data(config->ignore_tls_data = false); config->normalize = NORMALIZE_NONE; diff --git a/src/service_inspectors/smtp/smtp_module.h b/src/service_inspectors/smtp/smtp_module.h index fa53db8c0..ebe998cb0 100644 --- a/src/service_inspectors/smtp/smtp_module.h +++ b/src/service_inspectors/smtp/smtp_module.h @@ -45,6 +45,7 @@ //#define SMTP_BITENC_DECODING_FAILED 12 #define SMTP_UU_DECODING_FAILED 13 #define SMTP_AUTH_ABORT_AUTH 14 +#define SMTP_AUTH_COMMAND_OVERFLOW 15 #define SMTP_NAME "smtp" #define SMTP_HELP "smtp inspection" diff --git a/src/service_inspectors/smtp/smtp_paf.cc b/src/service_inspectors/smtp/smtp_paf.cc index ecaa1d707..7d1902b61 100644 --- a/src/service_inspectors/smtp/smtp_paf.cc +++ b/src/service_inspectors/smtp/smtp_paf.cc @@ -22,16 +22,18 @@ #include "main/snort_types.h" #include "main/snort_debug.h" +#include "events/event_queue.h" #include "smtp.h" +#include "smtp_module.h" /* State tracker for MIME PAF */ enum SmtpDataCMD { + SMTP_PAF_AUTH_CMD, SMTP_PAF_BDAT_CMD, SMTP_PAF_DATA_CMD, - SMTP_PAF_XEXCH50_CMD, - SMTP_PAF_STRARTTLS_CMD + SMTP_PAF_XEXCH50_CMD }; struct SmtpPAFToken @@ -44,10 +46,10 @@ struct SmtpPAFToken const SmtpPAFToken smtp_paf_tokens[] = { + { "AUTH", 4, SMTP_PAF_AUTH_CMD, false }, { "BDAT", 4, SMTP_PAF_BDAT_CMD, true }, { "DATA", 4, SMTP_PAF_DATA_CMD, true }, { "XEXCH50", 7, SMTP_PAF_XEXCH50_CMD, true }, - { "STRARTTLS", 9, SMTP_PAF_STRARTTLS_CMD, false }, { NULL, 0, 0, false } }; @@ -101,6 +103,11 @@ static inline char* init_cmd_search(SmtpCmdSearchInfo* search_info, uint8_t ch) /* Use the first byte to choose data command)*/ switch (ch) { + case 'a': + case 'A': + search_info->search_state = &smtp_paf_tokens[SMTP_PAF_AUTH_CMD].name[1]; + search_info->search_id = SMTP_PAF_AUTH_CMD; + break; case 'b': case 'B': search_info->search_state = &smtp_paf_tokens[SMTP_PAF_BDAT_CMD].name[1]; @@ -116,11 +123,6 @@ static inline char* init_cmd_search(SmtpCmdSearchInfo* search_info, uint8_t ch) search_info->search_state = &smtp_paf_tokens[SMTP_PAF_XEXCH50_CMD].name[1]; search_info->search_id = SMTP_PAF_XEXCH50_CMD; break; - case 's': - case 'S': - search_info->search_state = &smtp_paf_tokens[SMTP_PAF_STRARTTLS_CMD].name[1]; - search_info->search_id = SMTP_PAF_STRARTTLS_CMD; - break; default: search_info->search_state = NULL; break; @@ -190,7 +192,7 @@ static SmtpPafDataLenStatus get_length(char c, uint32_t* len) return SMTP_PAF_LENGTH_CONTINUE; } -/* Currently, we support "BDAT", "DATA", "XEXCH50", "STRARTTLS" +/* Currently, we support "BDAT", "DATA", "XEXCH50", "AUTH" * * Each data command should start from offset 0, * * since previous data have been flushed * */ @@ -278,10 +280,11 @@ static inline bool process_data(SmtpPafData* pfdata, uint8_t data) * * For data, flush at boundary * */ static inline StreamSplitter::Status smtp_paf_client(SmtpPafData* pfdata, - const uint8_t* data, uint32_t len, uint32_t* fp) + const uint8_t* data, uint32_t len, uint32_t* fp, int max_auth_command_line_len) { uint32_t i; uint32_t boundary_start = 0; + bool alert_generated = false; DebugFormat(DEBUG_SMTP, "From client: %s \n", data); for (i = 0; i < len; i++) @@ -298,7 +301,25 @@ static inline StreamSplitter::Status smtp_paf_client(SmtpPafData* pfdata, } break; case SMTP_PAF_DATA_STATE: - if (process_data(pfdata, ch)) + if (pfdata->cmd_info.search_id == SMTP_PAF_AUTH_CMD) + { + if ( max_auth_command_line_len && + (((int)i + pfdata->data_info.boundary_len) > max_auth_command_line_len) && + !alert_generated) + { + SnortEventqAdd(GID_SMTP, SMTP_AUTH_COMMAND_OVERFLOW); + alert_generated = true; + } + if (ch == '\n') + { + pfdata->smtp_state = SMTP_PAF_CMD_STATE; + pfdata->end_of_data = true; + reset_data_states(pfdata); + } + if ( (i == len-1) && (pfdata->smtp_state != SMTP_PAF_CMD_STATE) ) + pfdata->data_info.boundary_len += len; + } + else if (process_data(pfdata, ch)) { DebugMessage(DEBUG_SMTP, "Flush data!\n"); *fp = i + 1; @@ -323,10 +344,11 @@ static inline StreamSplitter::Status smtp_paf_client(SmtpPafData* pfdata, // callback for stateful scanning of in-order raw payload //-------------------------------------------------------------------- -SmtpSplitter::SmtpSplitter(bool c2s) : StreamSplitter(c2s) +SmtpSplitter::SmtpSplitter(bool c2s, int len) : StreamSplitter(c2s) { memset(&state, 0, sizeof(state)); reset_data_states(&state); + max_auth_command_line_len = len; } SmtpSplitter::~SmtpSplitter() { } @@ -365,7 +387,7 @@ StreamSplitter::Status SmtpSplitter::scan( else { DebugMessage(DEBUG_SMTP, "PAF: From client.\n"); - return smtp_paf_client(pfdata, data, len, fp); + return smtp_paf_client(pfdata, data, len, fp, max_auth_command_line_len); } } diff --git a/src/service_inspectors/smtp/smtp_paf.h b/src/service_inspectors/smtp/smtp_paf.h index 74824fdba..5ec6dc58f 100644 --- a/src/service_inspectors/smtp/smtp_paf.h +++ b/src/service_inspectors/smtp/smtp_paf.h @@ -65,7 +65,7 @@ struct SmtpPafData class SmtpSplitter : public StreamSplitter { public: - SmtpSplitter(bool c2s); + SmtpSplitter(bool c2s, int max_auth_cmd_line_len); ~SmtpSplitter(); Status scan(Flow*, const uint8_t* data, uint32_t len, @@ -75,6 +75,9 @@ public: public: SmtpPafData state; + +private: + int max_auth_command_line_len; }; // Function: Check if IMAP data end is reached diff --git a/tools/snort2lua/preprocessor_states/pps_smtp.cc b/tools/snort2lua/preprocessor_states/pps_smtp.cc index 04161fe5b..bf3e9a8ca 100644 --- a/tools/snort2lua/preprocessor_states/pps_smtp.cc +++ b/tools/snort2lua/preprocessor_states/pps_smtp.cc @@ -214,6 +214,10 @@ bool Smtp::convert(std::istringstream& data_stream) { tmpval = parse_int_option("email_hdrs_log_depth", data_stream, false); } + else if (!keyword.compare("max_auth_command_line_len")) + { + tmpval = parse_int_option("max_auth_command_line_len", data_stream, false); + } else if (!keyword.compare("max_command_line_len")) { tmpval = parse_int_option("max_command_line_len", data_stream, false);