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)
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*);
{
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;
}
}
-#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,
{ "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" },
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 }
};
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();
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;
//#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"
#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
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 }
};
/* 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];
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;
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
* */
* * 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++)
}
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;
// 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() { }
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);
}
}
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,
public:
SmtpPafData state;
+
+private:
+ int max_auth_command_line_len;
};
// Function: Check if IMAP data end is reached
{
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);