📄 snort_smtp.c
字号:
/* XXX A line starting with a '.' that isn't followed by a '.' is * deleted (RFC 821 - 4.5.2. TRANSPARENCY). If data starts with * '. text', i.e a dot followed by white space then text, some * servers consider it data header and some data body. * Postfix and Qmail will consider the start of data: * . text\r\n * . text\r\n * to be part of the header and the effect will be that of a * folded line with the '.' deleted. Exchange will put the same * in the body which seems more reasonable. */ } /* get end of data body * TODO check last bytes of previous packet to see if we had a partial * end of data */ _smtp_current_search = &_smtp_data_end_search[0]; data_end_found = _dpd.searchAPI->search_find(SEARCH_DATA_END, (const char *)ptr, end - ptr, 0, SMTP_SearchStrFound); if (data_end_found > 0) { data_end_marker = ptr + _smtp_search_info.index; data_end = data_end_marker + _smtp_search_info.length; } else { data_end_marker = data_end = end; } if ((_smtp->data_state == STATE_DATA_HEADER) || (_smtp->data_state == STATE_DATA_UNKNOWN)) {#ifdef DEBUG if (_smtp->data_state == STATE_DATA_HEADER) { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "DATA HEADER STATE ~~~~~~~~~~~~~~~~~~~~~~\n");); } else { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "DATA UNKNOWN STATE ~~~~~~~~~~~~~~~~~~~~~\n");); }#endif ptr = SMTP_HandleHeader(p, ptr, data_end_marker); if (ptr == NULL) return NULL; } /* if we're ignoring data and not already normalizing, copy everything * up to here into alt buffer so detection engine doesn't have * to look at the data; otherwise, if we're normalizing and not * ignoring data, copy all of the data into the alt buffer */ if (_smtp_config.ignore_data && !_smtp_normalizing) { ret = SMTP_CopyToAltBuffer(p, p->payload, ptr - p->payload); if (ret == -1) return NULL; } else if (!_smtp_config.ignore_data && _smtp_normalizing) { ret = SMTP_CopyToAltBuffer(p, ptr, data_end - ptr); if (ret == -1) return NULL; } /* now we shouldn't have to worry about copying any data to the alt buffer * only mime headers if we find them and only if we're ignoring data */ while ((ptr != NULL) && (ptr < data_end_marker)) { switch (_smtp->data_state) { case STATE_MIME_HEADER: DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "MIME HEADER STATE ~~~~~~~~~~~~~~~~~~~~~~\n");); ptr = SMTP_HandleHeader(p, ptr, data_end_marker); break; case STATE_DATA_BODY: DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "DATA BODY STATE ~~~~~~~~~~~~~~~~~~~~~~~~\n");); ptr = SMTP_HandleDataBody(p, ptr, data_end_marker); break; } } /* if we got the data end reset state, otherwise we're probably still in the data * to expect more data in next packet */ if (data_end_marker != end) { SMTP_ResetState(); } return data_end;}/* * Handle Headers - Data or Mime * * @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_HandleHeader(SFSnortPacket *p, const u_int8_t *ptr, const u_int8_t *data_end_marker){ const u_int8_t *eol; const u_int8_t *eolm; const u_int8_t *colon; const u_int8_t *content_type_ptr = NULL; int header_line_len; int header_found; int ret; const u_int8_t *start_hdr; int header_name_len; start_hdr = ptr; /* if we got a content-type in a previous packet and are * folding, the boundary still needs to be checked for */ if (_smtp->state_flags & SMTP_FLAG_IN_CONTENT_TYPE) content_type_ptr = ptr; while (ptr < data_end_marker) { SMTP_GetEOL(ptr, data_end_marker, &eol, &eolm); /* got a line with only end of line marker should signify end of header */ if (eolm == ptr) { /* reset global header state values */ _smtp->state_flags &= ~(SMTP_FLAG_FOLDING | SMTP_FLAG_IN_CONTENT_TYPE | SMTP_FLAG_DATA_HEADER_CONT); _smtp->data_state = STATE_DATA_BODY; /* if no headers, treat as data */ if (ptr == start_hdr) return eolm; else return eol; } /* if we're not folding, see if we should interpret line as a data line * instead of a header line */ if (!(_smtp->state_flags & (SMTP_FLAG_FOLDING | SMTP_FLAG_DATA_HEADER_CONT))) { char got_non_printable_in_header_name = 0; /* if we're not folding and the first char is a space or * colon, it's not a header */ if (isspace((int)*ptr) || *ptr == ':') { _smtp->data_state = STATE_DATA_BODY; return ptr; } /* look for header field colon - if we're not folding then we need * to find a header which will be all printables (except colon) * followed by a colon */ colon = ptr; while ((colon < eolm) && (*colon != ':')) { if (((int)*colon < 33) || ((int)*colon > 126)) got_non_printable_in_header_name = 1; colon++; } /* Check for Exim 4.32 exploit where number of chars before colon is greater than 64 */ header_name_len = colon - ptr; if ((_smtp->data_state != STATE_DATA_UNKNOWN) && (colon < eolm) && (header_name_len > MAX_HEADER_NAME_LEN)) { SMTP_GenerateAlert(SMTP_HEADER_NAME_OVERFLOW, "%s: %d chars before colon", SMTP_HEADER_NAME_OVERFLOW_STR, header_name_len); } /* If the end on line marker and end of line are the same, assume * header was truncated, so stay in data header state */ if ((eolm != eol) && ((colon == eolm) || got_non_printable_in_header_name)) { /* no colon or got spaces in header name (won't be interpreted as a header) * assume we're in the body */ _smtp->state_flags &= ~(SMTP_FLAG_FOLDING | SMTP_FLAG_IN_CONTENT_TYPE | SMTP_FLAG_DATA_HEADER_CONT); _smtp->data_state = STATE_DATA_BODY; return ptr; } _smtp_current_search = &_smtp_hdr_search[0]; header_found = _dpd.searchAPI->search_find(SEARCH_HDR, (const char *)ptr, eolm - ptr, 1, SMTP_SearchStrFound); /* Headers must start at beginning of line */ if ((header_found > 0) && (_smtp_search_info.index == 0)) { switch (_smtp_search_info.id) { case HDR_CONTENT_TYPE: /* for now we're just looking for the boundary in the data * header section */ if (_smtp->data_state != STATE_MIME_HEADER) { content_type_ptr = ptr + _smtp_search_info.length; _smtp->state_flags |= SMTP_FLAG_IN_CONTENT_TYPE; } break; default: break; } } } else { _smtp->state_flags &= ~SMTP_FLAG_DATA_HEADER_CONT; } /* get length of header line */ header_line_len = eol - ptr; if ((_smtp_config.max_header_line_len != 0) && (header_line_len > _smtp_config.max_header_line_len)) { if (_smtp->data_state != STATE_DATA_UNKNOWN) { SMTP_GenerateAlert(SMTP_DATA_HDR_OVERFLOW, "%s: %d chars", SMTP_DATA_HDR_OVERFLOW_STR, header_line_len); } else { /* assume we guessed wrong and are in the body */ _smtp->data_state = STATE_DATA_BODY; _smtp->state_flags &= ~(SMTP_FLAG_FOLDING | SMTP_FLAG_IN_CONTENT_TYPE | SMTP_FLAG_DATA_HEADER_CONT); return ptr; } } /* XXX Does VRT want data headers normalized? * currently the code does not normalize headers */ if (_smtp_normalizing) { ret = SMTP_CopyToAltBuffer(p, ptr, eol - ptr); if (ret == -1) return NULL; } /* check for folding * if char on next line is a space and not \n or \r\n, we are folding */ if ((eol < data_end_marker) && isspace((int)eol[0]) && (eol[0] != '\n')) { if ((eol < (data_end_marker - 1)) && (eol[0] != '\r') && (eol[1] != '\n')) { _smtp->state_flags |= SMTP_FLAG_FOLDING; } else { _smtp->state_flags &= ~SMTP_FLAG_FOLDING; } } else if (eol != eolm) { _smtp->state_flags &= ~SMTP_FLAG_FOLDING; } /* check if we're in a content-type header and not folding. if so we have the whole * header line/lines for content-type - see if we got a multipart with boundary * we don't check each folded line, but wait until we have the complete header * because boundary=BOUNDARY can be split across mulitple folded lines before * or after the '=' */ if ((_smtp->state_flags & (SMTP_FLAG_IN_CONTENT_TYPE | SMTP_FLAG_FOLDING)) == SMTP_FLAG_IN_CONTENT_TYPE) { /* we got the full content-type header - look for boundary string */ ret = SMTP_GetBoundary((const char *)content_type_ptr, eolm - content_type_ptr); if (ret != -1) { ret = SMTP_BoundarySearchInit(); if (ret != -1) { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "Got mime boundary: %s\n", _smtp->mime_boundary.boundary);); _smtp->state_flags |= SMTP_FLAG_GOT_BOUNDARY; } } _smtp->state_flags &= ~SMTP_FLAG_IN_CONTENT_TYPE; content_type_ptr = NULL; } /* if state was unknown, at this point assume we know */ if (_smtp->data_state == STATE_DATA_UNKNOWN) _smtp->data_state = STATE_DATA_HEADER; ptr = eol; if (ptr == data_end_marker) _smtp->state_flags |= SMTP_FLAG_DATA_HEADER_CONT; } return ptr;}/* * 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 = p->payload; const u_int8_t *end = p->payload + p->payload_size; if (_smtp->state == STATE_CONNECT) _smtp->state = STATE_COMMAND; while ((ptr != NULL) && (ptr < end)) { switch (_smtp->state) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -