📄 snort_smtp.c
字号:
* continuing of command inspection like ftptelnet. */static int SMTP_IsTlsClientHello(const u_int8_t *ptr, const u_int8_t *end){ /* at least 3 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 3 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; int do_flush = 0; int resp_line_len;#ifdef DEBUG const u_int8_t *dash;#endif 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; /* Check for response code */ _smtp_current_search = &_smtp_resp_search[0]; resp_found = _dpd.searchAPI->search_find(SEARCH_RESP, (const char *)ptr, resp_line_len, 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: do_flush = 1; break; default: break; }#ifdef DEBUG 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);); }#endif } else { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "Server response not found - see if it's SSL data\n");); if ((_smtp->session_flags & SMTP_FLAG_CHECK_SSL) && (SMTP_IsSSL(ptr, end - ptr, p->flags))) { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "Server response is an SSL packet\n");); _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; } else if (_smtp->session_flags & SMTP_FLAG_CHECK_SSL) { _smtp->session_flags &= ~SMTP_FLAG_CHECK_SSL; } } 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); } ptr = eol; } return do_flush;}static int SMTP_IsSSL(const u_int8_t *ptr, int len, int pkt_flags){ u_int32_t ssl_flags = SSL_decode(ptr, len, pkt_flags); if ((ssl_flags != SSL_ARG_ERROR_FLAG) && !(ssl_flags & SMTP_SSL_ERROR_FLAGS)) { return 1; } return 0;}/* For Target based * If a protocol for the session is already identified and not one SMTP is * interested in, SMTP should leave it alone and return without processing. * If a protocol for the session is already identified and is one that SMTP is * interested in, decode it. * If the protocol for the session is not already identified and the preprocessor * is configured to detect on one of the packet ports, detect. * Returns 0 if we should not inspect * 1 if we should continue to inspect */static int SMTP_Inspect(SFSnortPacket *p){#ifdef TARGET_BASED /* SMTP could be configured to be stateless. If stream isn't configured, assume app id * will never be set and just base inspection on configuration */ if (p->stream_session_ptr == NULL) { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "SMTP: Target-based: No stream session.\n");); if (SMTP_IsServer(p->src_port) || SMTP_IsServer(p->dst_port)) { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "SMTP: Target-based: Configured for this " "traffic, so let's inspect.\n");); return 1; } } else { int16_t app_id = _dpd.streamAPI->get_application_protocol_id(p->stream_session_ptr); if (app_id != 0) { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "SMTP: Target-based: App id: %u.\n", app_id);); if (app_id == _smtp_proto_id) { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "SMTP: Target-based: App id is " "set to \"%s\".\n", SMTP_PROTO_REF_STR);); return 1; } } else { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "SMTP: Target-based: Unknown protocol for " "this session. See if we're configured.\n");); if (SMTP_IsServer(p->src_port) || SMTP_IsServer(p->dst_port)) { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "SMTP: Target-based: SMTP port is configured.");); return 1; } } } DEBUG_WRAP(DebugMessage(DEBUG_SMTP,"SMTP: Target-based: Not inspecting ...\n"););#else /* Make sure it's traffic we're interested in */ if (SMTP_IsServer(p->src_port) || SMTP_IsServer(p->dst_port)) return 1;#endif /* TARGET_BASED */ return 0;}/* * Entry point to snort preprocessor for each packet * * @param packet standard Packet structure * * @return none */void SnortSMTP(SFSnortPacket *p){ int detected = 0; PROFILE_VARS; if (!SMTP_Inspect(p)) return; /* Ignore if no data */ if (p->payload_size == 0) {#ifdef DEBUG int pkt_dir; int flags = 0; if (p->stream_session_ptr != NULL) flags = _dpd.streamAPI->get_session_flags(p->stream_session_ptr); pkt_dir = SMTP_GetPacketDirection(p, flags); 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); if (_smtp_pkt_direction == SMTP_PKT_FROM_SERVER) { int do_flush = 0; 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 {#ifdef DEBUG if (_smtp_pkt_direction == SMTP_PKT_FROM_CLIENT) { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "SMTP client packet\n");); } else { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "SMTP packet NOT from client or server! " "Processing as a client packet\n");); }#endif /* 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; } else if (_smtp_reassembling && !(p->flags & FLAG_REBUILT_STREAM)) { /* If this isn't a reassembled packet and didn't get * inserted into reassembly buffer, there could be a * problem. If we miss syn or syn-ack that had window * scaling this packet might not have gotten inserted * into reassembly buffer because it fell outside of * window, because we aren't scaling it */ _smtp->session_flags |= SMTP_FLAG_GOT_NON_REBUILT; _smtp->state = STATE_UNKNOWN; } else if (_smtp_reassembling && (_smtp->session_flags & SMTP_FLAG_GOT_NON_REBUILT)) { /* This is a rebuilt packet. If we got previous packets * that were not rebuilt, state is going to be messed up * so set state to unknown. It's likely this was the * beginning of the conversation so reset state */ DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "Got non-rebuilt packets before " "this rebuilt packet\n");); _smtp->state = STATE_UNKNOWN; _smtp->session_flags &= ~SMTP_FLAG_GOT_NON_REBUILT; }#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); } } PREPROC_PRO
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -