📄 snort_smtp.c
字号:
/* * Handle DATA_BODY state * * @param packet standard Packet structure * * @param i index into p->payload buffer to start looking at data * * @return i index into p->payload where we stopped looking at data */static const u_int8_t * SMTP_HandleDataBody(SFSnortPacket *p, const u_int8_t *ptr, const u_int8_t *data_end_marker){ int boundary_found = 0; const u_int8_t *boundary_ptr = NULL; /* look for boundary */ if (_smtp->state_flags & SMTP_FLAG_GOT_BOUNDARY) { boundary_found = _dpd.searchAPI->search_instance_find(_smtp->mime_boundary.boundary_search, (const char *)ptr, data_end_marker - ptr, 0, SMTP_BoundaryStrFound); if (boundary_found > 0) { boundary_ptr = ptr + _smtp_search_info.index; /* should start at beginning of line */ if ((boundary_ptr == ptr) || (*(boundary_ptr - 1) == '\n')) { const u_int8_t *eol; const u_int8_t *eolm; const u_int8_t *tmp; /* Check for end boundary */ tmp = boundary_ptr + _smtp_search_info.length; if (((tmp + 1) < data_end_marker) && (tmp[0] == '-') && (tmp[1] == '-')) { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "Mime boundary end found: %s--\n", (char *)_smtp->mime_boundary.boundary);); /* no more MIME */ _smtp->state_flags &= ~SMTP_FLAG_GOT_BOUNDARY; /* free boundary search */ _dpd.searchAPI->search_instance_free(_smtp->mime_boundary.boundary_search); _smtp->mime_boundary.boundary_search = NULL; } else { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "Mime boundary found: %s\n", (char *)_smtp->mime_boundary.boundary);); _smtp->data_state = STATE_MIME_HEADER; } /* get end of line - there could be spaces after boundary before eol */ SMTP_GetEOL(boundary_ptr + _smtp_search_info.length, data_end_marker, &eol, &eolm); return eol; } } } return data_end_marker;}/* * Process client packet * * @param packet standard Packet structure * * @return none */static void SMTP_ProcessClientPacket(SFSnortPacket *p){ const u_int8_t *ptr = NULL; const u_int8_t *end = NULL; if (_smtp->state == STATE_CONNECT) { _smtp->state = STATE_COMMAND; } ptr = p->payload; end = p->payload + p->payload_size; while ((ptr != NULL) && (ptr < end)) { switch (_smtp->state) { case STATE_COMMAND: DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "COMMAND STATE ~~~~~~~~~~~~~~~~~~~~~~~~~~\n");); ptr = SMTP_HandleCommand(p, ptr, end); break; case STATE_DATA: DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "DATA STATE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");); ptr = SMTP_HandleData(p, ptr, end); break; case STATE_DATA_PEND: DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "DATA PEND STATE ~~~~~~~~~~~~~~~~~~~~~~~~\n");); ptr = SMTP_HandleData(p, ptr, end); break; default: DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "Unknown SMTP state\n");); return; } }#ifdef DEBUG if (_smtp_normalizing) { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "Normalized payload\n%s\n", SMTP_PrintBuffer(p));); }#endif return;}/* very simplistic - just enough to say this is binary data - the rules will make a final * judgement. Should maybe add an option to the smtp configuration to enable the * continuing of command inspection like ftptelnet. */static int SMTP_IsTlsClientHello(const u_int8_t *ptr, const u_int8_t *end){ /* at least 7 bytes of data - see below */ if ((end - ptr) < 3) return 0; if ((ptr[0] == 0x16) && (ptr[1] == 0x03)) { /* TLS v1 or SSLv3 */ return 1; } else if ((ptr[2] == 0x01) || (ptr[3] == 0x01)) { /* SSLv2 */ return 1; } return 0;}/* this may at least tell us whether the server accepted the client hello by the presence * of binary data */static int SMTP_IsTlsServerHello(const u_int8_t *ptr, const u_int8_t *end){ /* at least 7 bytes of data - see below */ if ((end - ptr) < 3) return 0; if ((ptr[0] == 0x16) && (ptr[1] == 0x03)) { /* TLS v1 or SSLv3 */ return 1; } else if (ptr[2] == 0x04) { /* SSLv2 */ return 1; } return 0;}/* * Process server packet * * @param packet standard Packet structure * * @return do_flush * @retval 1 flush queued packets on client side * @retval 0 do not flush queued packets on client side */static int SMTP_ProcessServerPacket(SFSnortPacket *p){ int resp_found; const u_int8_t *ptr; const u_int8_t *end; const u_int8_t *eolm; const u_int8_t *eol; const u_int8_t *dash; int do_flush = 0; int resp_line_len; ptr = p->payload; end = p->payload + p->payload_size; if (_smtp->state == STATE_TLS_SERVER_PEND) { if (SMTP_IsTlsServerHello(ptr, end)) { _smtp->state = STATE_TLS_DATA; } else { /* revert back to command state - assume server didn't accept STARTTLS */ _smtp->state = STATE_COMMAND; } } if (_smtp->state == STATE_TLS_DATA) { /* Ignore data */ if (_smtp_config.ignore_tls_data) { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "Ignoring Server TLS encrypted data\n");); p->normalized_payload_size = 0; p->flags |= FLAG_ALT_DECODE; } return 0; } while (ptr < end) { SMTP_GetEOL(ptr, end, &eol, &eolm); resp_line_len = eol - ptr; if ((_smtp_config.max_response_line_len != 0) && (resp_line_len > _smtp_config.max_response_line_len)) { SMTP_GenerateAlert(SMTP_RESPONSE_OVERFLOW, "%s: %d chars", SMTP_RESPONSE_OVERFLOW_STR, resp_line_len); } /* Check for response code */ _smtp_current_search = &_smtp_resp_search[0]; resp_found = _dpd.searchAPI->search_find(SEARCH_RESP, (const char *)ptr, eol - ptr, 1, SMTP_SearchStrFound); if (resp_found > 0) { switch (_smtp_search_info.id) { case RESP_220: /* This is either an initial server response or a STARTTLS response * flush the client side. if we've already seen STARTTLS, no need * to flush */ if (_smtp->state == STATE_CONNECT) { _smtp->state = STATE_COMMAND; } else if (_smtp->state != STATE_TLS_CLIENT_PEND) { do_flush = 1; } break; case RESP_354: /* we may have processed a complete message before receiving data response and * moved back to command state. if we're pending response, move to data state * otherwise recognize the response, but set got data command to zero. * this is to ensure that we don't flush when we don't need to. */ if (_smtp->state_flags & SMTP_FLAG_GOT_DATA_CMD) { if (_smtp->state == STATE_DATA_PEND) { _smtp->state = STATE_DATA; } _smtp->state_flags &= ~SMTP_FLAG_GOT_DATA_CMD; } else { _smtp->state_flags |= SMTP_FLAG_GOT_DATA_RESP; do_flush = 1; } break; default: break; } dash = ptr + _smtp_search_info.index + _smtp_search_info.length; /* only add response if not a dash after response code */ if ((dash == eolm) || ((dash < eolm) && (*dash != '-'))) { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "Server sent %s response\n", _smtp_resps[_smtp_search_info.id].name);); } } ptr = eol; } return do_flush;}/* * Entry point to snort preprocessor for each packet * * @param packet standard Packet structure * * @return none */void SnortSMTP(SFSnortPacket *p){ int detected = 0; int do_flush = 0; PROFILE_VARS; /* Ignore if no data */ if (p->payload_size == 0) {#ifdef DEBUG int pkt_dir = SMTP_GetPacketDirection(p, 0); DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "SMTP %s packet\n", pkt_dir == SMTP_PKT_FROM_SERVER ? "server" : (pkt_dir == SMTP_PKT_FROM_CLIENT ? "client" : "unknown"));); DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "No payload to inspect\n"););#endif return; } SMTP_Setup(p); /* Figure out direction of packet */ _smtp_pkt_direction = SMTP_GetPacketDirection(p, 1); if (_smtp_pkt_direction == SMTP_PKT_FROM_SERVER) { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "SMTP server packet\n");); /* Process as a server packet */ do_flush = SMTP_ProcessServerPacket(p); if (do_flush) { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "Flushing stream\n");); _dpd.streamAPI->response_flush_stream(p); } } else if (_smtp_pkt_direction == SMTP_PKT_FROM_CLIENT) { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "SMTP client packet\n");); /* This packet should be a tls client hello */ if (_smtp->state == STATE_TLS_CLIENT_PEND) { if (SMTP_IsTlsClientHello(p->payload, p->payload + p->payload_size)) { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "TLS DATA STATE ~~~~~~~~~~~~~~~~~~~~~~~~~\n");); _smtp->state = STATE_TLS_SERVER_PEND; } else { /* reset state - server may have rejected STARTTLS command */ _smtp->state = STATE_COMMAND; } } if ((_smtp->state == STATE_TLS_DATA) || (_smtp->state == STATE_TLS_SERVER_PEND)) { /* if we're ignoring tls data, set a zero length alt buffer */ if (_smtp_config.ignore_tls_data) { p->normalized_payload_size = 0; p->flags |= FLAG_ALT_DECODE; } } else { if (p->flags & FLAG_STREAM_INSERT) { /* Packet will be rebuilt, so wait for it */ DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "Client packet will be reassembled\n")); /* Turn off detection until we get the rebuilt packet. */ SMTP_DisableDetect(p); return; }#ifdef DEBUG /* Interesting to see how often packets are rebuilt */ DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "Payload: %s\n%s\n", (p->flags & FLAG_REBUILT_STREAM) ? "reassembled" : "not reassembled", SMTP_PrintBuffer(p)););#endif SMTP_ProcessClientPacket(p); } } else { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "SMTP packet NOT from client or server! " "Processing as a client packet\n");); SMTP_ProcessClientPacket(p); } PREPROC_PROFILE_START(smtpDetectPerfStats); detected = _dpd.detect(p);#ifdef PERF_PROFILING smtpDetectCalled = 1;#endif PREPROC_PROFILE_END(smtpDetectPerfStats); /* Turn off detection since we've already done it. */ SMTP_DisableDetect(p); if ( detected ) { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "SMTP vulnerability detected\n");); }}static void SMTP_DisableDetect(SFSnortPacket *p){ _dpd.disableAllDetect(p); _dpd.setPreprocBit(p, PP_SFPORTSCAN); _dpd.setPreprocBit(p, PP_PERFMONITOR); _dpd.setPreprocBit(p, PP_STREAM4); _dpd.setPreprocBit(p, PP_STREAM5);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -