📄 snort_smtp.c
字号:
p->normalized_payload_size = 0; p->flags &= ~FLAG_ALT_DECODE; if ((p->stream_session_ptr == NULL) || (_smtp_config.inspection_type == SMTP_STATELESS)) { SMTP_NoSessionFree(); memset(&_smtp_no_session, 0, sizeof(SMTP)); _smtp = &_smtp_no_session; return; } _smtp = _dpd.streamAPI->get_application_data(p->stream_session_ptr, PP_SMTP); if (_smtp == NULL) { _smtp = (SMTP *)calloc(1, sizeof(SMTP)); if (_smtp == NULL) { DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate SMTP session data\n"); } else { _dpd.streamAPI->set_application_data(p->stream_session_ptr, PP_SMTP, _smtp, &SMTP_SessionFree); } }}/* * Determine packet direction * * @param p standard Packet structure * * @return none */static int SMTP_GetPacketDirection(SFSnortPacket *p, char reset_if_midstream){ int flags = 0; int pkt_direction = SMTP_PKT_FROM_UNKNOWN; if (p->stream_session_ptr != NULL) { flags = _dpd.streamAPI->get_session_flags(p->stream_session_ptr); } if (flags & SSNFLAG_MIDSTREAM) { /* We can't be sure what state we are in, in this case. */ if ((_smtp_config.inspection_type == SMTP_STATEFUL) && reset_if_midstream) SMTP_ResetState(); /* Note that source port and destination port can both be 25 * TODO Maybe new function that dynamically determines whether client * or server based on data */ if (SMTP_IsServer(p->src_port) && SMTP_IsServer(p->dst_port)) { pkt_direction = SMTP_PKT_FROM_UNKNOWN; } else if (SMTP_IsServer(p->src_port)) { pkt_direction = SMTP_PKT_FROM_SERVER; } else if (SMTP_IsServer(p->dst_port)) { pkt_direction = SMTP_PKT_FROM_CLIENT; } else { pkt_direction = SMTP_PKT_FROM_UNKNOWN; } } else if (p->flags & FLAG_FROM_SERVER) { pkt_direction = SMTP_PKT_FROM_SERVER; } else if (p->flags & FLAG_FROM_CLIENT) { pkt_direction = SMTP_PKT_FROM_CLIENT; } else { pkt_direction = SMTP_PKT_FROM_UNKNOWN; } return pkt_direction;}/* * Free SMTP-specific related to this session * * @param v pointer to SMTP session structure * * @return none */static void SMTP_SessionFree(void *session_data){ SMTP *smtp = (SMTP *)session_data; if (smtp != NULL) { if (smtp->mime_boundary.boundary_search != NULL) { _dpd.searchAPI->search_instance_free(smtp->mime_boundary.boundary_search); smtp->mime_boundary.boundary_search = NULL; } free(smtp); }}static void SMTP_NoSessionFree(void){ if (_smtp_no_session.mime_boundary.boundary_search != NULL) { _dpd.searchAPI->search_instance_free(_smtp_no_session.mime_boundary.boundary_search); _smtp_no_session.mime_boundary.boundary_search = NULL; }}/* * Free anything that needs it before shutting down preprocessor * * @param none * * @return none */void SMTP_Free(void){ SMTPToken *tmp; _dpd.searchAPI->search_free(); SMTP_NoSessionFree(); for (tmp = _smtp_cmds; tmp->name != NULL; tmp++) { free(tmp->name); } if (_smtp_cmds != NULL) free(_smtp_cmds); if (_smtp_cmd_search != NULL) free(_smtp_cmd_search); if (_smtp_cmd_config != NULL) free(_smtp_cmd_config); if (_mime_boundary_pcre.re ) pcre_free(_mime_boundary_pcre.re); if (_mime_boundary_pcre.pe ) pcre_free(_mime_boundary_pcre.pe);}/* * Callback function for string search * * @param id id in array of search strings from _smtp_config.cmds * @param index index in array of search strings from _smtp_config.cmds * @param data buffer passed in to search function * * @return response * @retval 1 commands caller to stop searching */static int SMTP_SearchStrFound(void *id, int index, void *data){ int search_id = (int)(uintptr_t)id; _smtp_search_info.id = search_id; _smtp_search_info.index = index; _smtp_search_info.length = _smtp_current_search[search_id].name_len; /* Returning non-zero stops search, which is okay since we only look for one at a time */ return 1;}/* * Callback function for boundary search * * @param id id in array of search strings * @param index index in array of search strings * @param data buffer passed in to search function * * @return response * @retval 1 commands caller to stop searching */static int SMTP_BoundaryStrFound(void *id, int index, void *data){ int boundary_id = (int)(uintptr_t)id; _smtp_search_info.id = boundary_id; _smtp_search_info.index = index; _smtp_search_info.length = _smtp->mime_boundary.boundary_len; return 1;}static int SMTP_GetBoundary(const char *data, int data_len){ int result; int ovector[9]; int ovecsize = 9; const char *boundary; int boundary_len; int ret; char *mime_boundary; int *mime_boundary_len; mime_boundary = &_smtp->mime_boundary.boundary[0]; mime_boundary_len = &_smtp->mime_boundary.boundary_len; /* result will be the number of matches (including submatches) */ result = pcre_exec(_mime_boundary_pcre.re, _mime_boundary_pcre.pe, data, data_len, 0, 0, ovector, ovecsize); if (result < 0) return -1; result = pcre_get_substring(data, ovector, result, 1, &boundary); if (result < 0) return -1; boundary_len = strlen(boundary); if (boundary_len > MAX_BOUNDARY_LEN) { /* XXX should we alert? breaking the law of RFC */ boundary_len = MAX_BOUNDARY_LEN; } mime_boundary[0] = '-'; mime_boundary[1] = '-'; ret = SafeMemcpy(mime_boundary + 2, boundary, boundary_len, mime_boundary + 2, mime_boundary + 2 + MAX_BOUNDARY_LEN); pcre_free_substring(boundary); if (ret != SAFEMEM_SUCCESS) { return -1; } *mime_boundary_len = 2 + boundary_len; mime_boundary[*mime_boundary_len] = '\0'; return 0;}/* * Handle COMMAND state * * @param p standard Packet structure * @param ptr pointer into p->payload buffer to start looking at data * @param end points to end of p->payload buffer * * @return pointer into p->payload where we stopped looking at data * will be end of line or end of packet */static const u_int8_t * SMTP_HandleCommand(SFSnortPacket *p, const u_int8_t *ptr, const u_int8_t *end){ const u_int8_t *eol; /* end of line */ const u_int8_t *eolm; /* end of line marker */ int cmd_line_len; int ret; int cmd_found; char alert_long_command_line = 0; /* get end of line and end of line marker */ SMTP_GetEOL(ptr, end, &eol, &eolm); /* calculate length of command line */ cmd_line_len = eol - ptr; /* check for command line exceeding maximum * do this before checking for a command since this could overflow * some server's buffers without the presence of a known command */ if ((_smtp_config.max_command_line_len != 0) && (cmd_line_len > _smtp_config.max_command_line_len)) { alert_long_command_line = 1; } /* TODO If the end of line marker coincides with the end of payload we can't be * sure that we got a command and not a substring which we could tell through * inpsection of the next packet. Maybe a command pending state where the first * char in the next packet is checked for a space and end of line marker */ /* do not confine since there could be space chars before command */ _smtp_current_search = &_smtp_cmd_search[0]; cmd_found = _dpd.searchAPI->search_find(SEARCH_CMD, (const char *)ptr, eolm - ptr, 0, SMTP_SearchStrFound); /* see if we actually found a command and not a substring */ if (cmd_found > 0) { const u_int8_t *tmp = ptr; const u_int8_t *cmd_start = ptr + _smtp_search_info.index; const u_int8_t *cmd_end = cmd_start + _smtp_search_info.length; /* move past spaces up until start of command */ while ((tmp < cmd_start) && isspace((int)*tmp)) tmp++; /* if not all spaces before command, we found a * substring */ if (tmp != cmd_start) cmd_found = 0; /* if we're before the end of line marker and the next * character is not whitespace, we found a substring */ if ((cmd_end < eolm) && !isspace((int)*cmd_end)) cmd_found = 0; /* there is a chance that end of command coincides with the end of payload * in which case, it could be a substring, but for now, we will treat it as found */ } /* if command not found, alert and move on */ if (!cmd_found) { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "No known command found\n");); if (_smtp_config.alert_unknown_cmds) { SMTP_GenerateAlert(SMTP_UNKNOWN_CMD, "%s", SMTP_UNKNOWN_CMD_STR); } if (alert_long_command_line) { SMTP_GenerateAlert(SMTP_COMMAND_OVERFLOW, "%s: more than %d chars", SMTP_COMMAND_OVERFLOW_STR, _smtp_config.max_command_line_len); } /* if normalizing, copy line to alt buffer */ if (_smtp_normalizing) { ret = SMTP_CopyToAltBuffer(p, ptr, eol - ptr); if (ret == -1) return NULL; } return eol; } /* At this point we have definitely found a legitimate command */ DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "%s\n", _smtp_cmds[_smtp_search_info.id].name);); /* check if max command line length for a specific command is exceeded */ if (_smtp_cmd_config[_smtp_search_info.id].max_line_len != 0) { if (cmd_line_len > _smtp_cmd_config[_smtp_search_info.id].max_line_len) { SMTP_GenerateAlert(SMTP_SPECIFIC_CMD_OVERFLOW, "%s: %s, %d chars", SMTP_SPECIFIC_CMD_OVERFLOW_STR, _smtp_cmd_search[_smtp_search_info.id].name, cmd_line_len); } } else if (alert_long_command_line) { SMTP_GenerateAlert(SMTP_COMMAND_OVERFLOW, "%s: more than %d chars", SMTP_COMMAND_OVERFLOW_STR, _smtp_config.max_command_line_len); } /* Are we alerting on this command? */ if (_smtp_cmd_config[_smtp_search_info.id].alert) { SMTP_GenerateAlert(SMTP_ILLEGAL_CMD, "%s: %s", SMTP_ILLEGAL_CMD_STR, _smtp_cmds[_smtp_search_info.id].name); } switch (_smtp_search_info.id) { /* unless we do our own parsing of MAIL and RCTP commands we have to assume they * are ok unless we got a server error in which case we flush and if this is a * reassembled packet, the last command in this packet will be the command that * caused the error */ case CMD_MAIL: _smtp->state_flags |= SMTP_FLAG_GOT_MAIL_CMD; break; case CMD_RCPT: if (_smtp->state_flags & SMTP_FLAG_GOT_MAIL_CMD) { _smtp->state_flags |= SMTP_FLAG_GOT_RCPT_CMD; } break; case CMD_RSET: case CMD_HELO: case CMD_EHLO: case CMD_QUIT: _smtp->state_flags &= ~(SMTP_FLAG_GOT_MAIL_CMD | SMTP_FLAG_GOT_RCPT_CMD); break;#if 0 case CMD_BDAT: { const u_int8_t *begin_chunk; const u_int8_t *end_chunk; const u_int8_t *last; const u_int8_t *tmp; int num_digits; int ten_power; u_int32_t bdat_chunk; begin_chunk = ptr + _smtp_search_info.index + _smtp_search_info.length; while ((begin_chunk < eolm) && isspace((int)*begin_chunk)) begin_chunk++; /* bad BDAT command - needs chunk argument */ if (begin_chunk == eolm) break; end_chunk = begin_chunk; while ((end_chunk < eolm) && isdigit((int)*end_chunk)) end_chunk++; /* didn't get all digits */ if ((end_chunk < eolm) && !isspace((int)*end_chunk)) break; /* get chunk size */ num_digits = end_chunk - begin_chunk; /* more than 9 digits could potentially overflow a 32 bit integer * this allows for one less than a billion bytes which most servers * won't accept */ if (num_digits > 9) break; tmp = end_chunk; for (ten_power = 1, tmp--; tmp >= begin_chunk; ten_power *= 10, tmp--)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -