diff options
Diffstat (limited to 'framework/src/suricata/src/util-decode-mime.c')
-rw-r--r-- | framework/src/suricata/src/util-decode-mime.c | 158 |
1 files changed, 137 insertions, 21 deletions
diff --git a/framework/src/suricata/src/util-decode-mime.c b/framework/src/suricata/src/util-decode-mime.c index 3f4affcc..51d1468e 100644 --- a/framework/src/suricata/src/util-decode-mime.c +++ b/framework/src/suricata/src/util-decode-mime.c @@ -79,9 +79,8 @@ #define MAX_IP6_CHARS 39 /* Globally hold configuration data */ -static MimeDecConfig mime_dec_config = { 1, 1, 1, MAX_HEADER_VALUE }; +static MimeDecConfig mime_dec_config = { 1, 1, 1, 0, MAX_HEADER_VALUE }; -#ifdef DEBUG /* Mime Parser String translation */ static const char *StateFlags[] = { "NONE", "HEADER_READY", @@ -93,7 +92,6 @@ static const char *StateFlags[] = { "NONE", "PARSE_DONE", "PARSE_ERROR", NULL }; -#endif /* URL executable file extensions */ static const char *UrlExeExts[] = { ".exe", @@ -299,6 +297,35 @@ MimeDecField * MimeDecAddField(MimeDecEntity *entity) return node; } + +/** + * \brief Searches for header fields with the specified name + * + * \param entity The entity to search + * \param name The header name (lowercase) + * + * \return number of items found + * + */ +int MimeDecFindFieldsForEach(const MimeDecEntity *entity, const char *name, int (*DataCallback)(const uint8_t *val, const size_t, void *data), void *data) +{ + MimeDecField *curr = entity->field_list; + int found = 0; + + while (curr != NULL) { + /* name is stored lowercase */ + if (strlen(name) == curr->name_len) { + if (SCMemcmp(curr->name, name, curr->name_len) == 0) { + if (DataCallback(curr->value, curr->value_len, data)) + found++; + } + } + curr = curr->next; + } + + return found; +} + /** * \brief Searches for a header field with the specified name * @@ -915,7 +942,7 @@ static int IsIpv4Host(const uint8_t *urlhost, uint32_t len) */ static int IsIpv6Host(const uint8_t *urlhost, uint32_t len) { - struct sockaddr_in sa; + struct in6_addr in6; char tempIp[MAX_IP6_CHARS + 1]; /* Cut off at '/' */ @@ -936,7 +963,7 @@ static int IsIpv6Host(const uint8_t *urlhost, uint32_t len) memcpy(tempIp, urlhost, i); tempIp[i] = '\0'; - return inet_pton(AF_INET6, tempIp, &(sa.sin_addr)); + return inet_pton(AF_INET6, tempIp, &in6); } /** @@ -1992,6 +2019,7 @@ static int ProcessMimeHeaders(const uint8_t *buf, uint32_t len, * * \return MIME_DEC_OK on success, otherwise < 0 on failure */ + static int ProcessBodyComplete(MimeDecParseState *state) { int ret = MIME_DEC_OK; @@ -2012,6 +2040,13 @@ static int ProcessBodyComplete(MimeDecParseState *state) } } +#ifdef HAVE_NSS + if (state->md5_ctx) { + unsigned int len = 0; + HASH_End(state->md5_ctx, state->md5, &len, sizeof(state->md5)); + } +#endif + /* Invoke pre-processor and callback with remaining data */ ret = ProcessDecodedDataChunk(state->data_chunk, state->data_chunk_len, state); if (ret != MIME_DEC_OK) { @@ -2180,6 +2215,18 @@ static int ProcessMimeBody(const uint8_t *buf, uint32_t len, int body_found = 0; uint32_t tlen; +#ifdef HAVE_NSS + if (MimeDecGetConfig()->body_md5) { + if (state->body_begin == 1) { + if (state->md5_ctx == NULL) { + state->md5_ctx = HASH_Create(HASH_AlgMD5); + HASH_Begin(state->md5_ctx); + } + } + HASH_Update(state->md5_ctx, buf, len + state->current_line_delimiter_len); + } +#endif + /* Ignore empty lines */ if (len == 0) { return ret; @@ -2254,6 +2301,11 @@ static int ProcessMimeBody(const uint8_t *buf, uint32_t len, return ret; } +const char *MimeDecParseStateGetStatus(MimeDecParseState *state) +{ + return StateFlags[state->state_flag]; +} + /** * \brief Processes the MIME Entity based on the input line and current state of * the parser @@ -2394,6 +2446,10 @@ void MimeDecDeInitParser(MimeDecParseState *state) SCFree(state->hname); FreeDataValue(state->hvalue); FreeMimeDecStack(state->stack); +#ifdef HAVE_NSS + if (state->md5_ctx) + HASH_Destroy(state->md5_ctx); +#endif SCFree(state); } @@ -2459,12 +2515,13 @@ int MimeDecParseComplete(MimeDecParseState *state) * * \param line A string representing the line (w/out CRLF) * \param len The length of the line + * \param delim_len The length of the line end delimiter * \param state The parser state * * \return MIME_DEC_OK on success, otherwise < 0 on failure */ int MimeDecParseLine(const uint8_t *line, const uint32_t len, - MimeDecParseState *state) + const uint8_t delim_len, MimeDecParseState *state) { int ret = MIME_DEC_OK; @@ -2475,6 +2532,7 @@ int MimeDecParseLine(const uint8_t *line, const uint32_t len, SCLogDebug("SMTP LINE - EMPTY"); } + state->current_line_delimiter_len = delim_len; /* Process the entity */ ret = ProcessMimeEntity(line, len, state); if (ret != MIME_DEC_OK) { @@ -2522,8 +2580,10 @@ MimeDecEntity * MimeDecParseFullMsg(const uint8_t *buf, uint32_t blen, void *dat line = tok; + state->current_line_delimiter_len = (remainPtr - tok) - tokLen; /* Parse the line */ - ret = MimeDecParseLine(line, tokLen, state); + ret = MimeDecParseLine(line, tokLen, + (remainPtr - tok) - tokLen, state); if (ret != MIME_DEC_OK) { SCLogDebug("Error: MimeDecParseLine() function failed: %d", ret); @@ -2610,25 +2670,25 @@ static int MimeDecParseLineTest01(void) TestDataChunkCallback); char *str = "From: Sender1"; - ret |= MimeDecParseLine((uint8_t *)str, strlen(str), state); + ret |= MimeDecParseLine((uint8_t *)str, strlen(str), 1, state); str = "To: Recipient1"; - ret |= MimeDecParseLine((uint8_t *)str, strlen(str), state); + ret |= MimeDecParseLine((uint8_t *)str, strlen(str), 1, state); str = "Content-Type: text/plain"; - ret |= MimeDecParseLine((uint8_t *)str, strlen(str), state); + ret |= MimeDecParseLine((uint8_t *)str, strlen(str), 1, state); str = ""; - ret |= MimeDecParseLine((uint8_t *)str, strlen(str), state); + ret |= MimeDecParseLine((uint8_t *)str, strlen(str), 1, state); str = "A simple message line 1"; - ret |= MimeDecParseLine((uint8_t *)str, strlen(str), state); + ret |= MimeDecParseLine((uint8_t *)str, strlen(str), 1, state); str = "A simple message line 2"; - ret |= MimeDecParseLine((uint8_t *)str, strlen(str), state); + ret |= MimeDecParseLine((uint8_t *)str, strlen(str), 1, state); str = "A simple message line 3"; - ret |= MimeDecParseLine((uint8_t *)str, strlen(str), state); + ret |= MimeDecParseLine((uint8_t *)str, strlen(str), 1, state); if (ret != MIME_DEC_OK) { return ret; @@ -2678,23 +2738,23 @@ static int MimeDecParseLineTest02(void) TestDataChunkCallback); char *str = "From: Sender1"; - ret |= MimeDecParseLine((uint8_t *)str, strlen(str), state); + ret |= MimeDecParseLine((uint8_t *)str, strlen(str), 1, state); str = "To: Recipient1"; - ret |= MimeDecParseLine((uint8_t *)str, strlen(str), state); + ret |= MimeDecParseLine((uint8_t *)str, strlen(str), 1, state); str = "Content-Type: text/plain"; - ret |= MimeDecParseLine((uint8_t *)str, strlen(str), state); + ret |= MimeDecParseLine((uint8_t *)str, strlen(str), 1, state); str = ""; - ret |= MimeDecParseLine((uint8_t *)str, strlen(str), state); + ret |= MimeDecParseLine((uint8_t *)str, strlen(str), 1, state); str = "A simple message line 1"; - ret |= MimeDecParseLine((uint8_t *)str, strlen(str), state); + ret |= MimeDecParseLine((uint8_t *)str, strlen(str), 1, state); str = "A simple message line 2 click on http://www.test.com/malware.exe?" "hahah hopefully you click this link"; - ret |= MimeDecParseLine((uint8_t *)str, strlen(str), state); + ret |= MimeDecParseLine((uint8_t *)str, strlen(str), 1, state); if (ret != MIME_DEC_OK) { return ret; @@ -2762,6 +2822,59 @@ static int MimeDecParseFullMsgTest01(void) return ret; } +/* Test full message with linebreaks */ +static int MimeDecParseFullMsgTest02(void) +{ + int ret = MIME_DEC_OK; + + uint32_t expected_count = 3; + uint32_t line_count = 0; + + char msg[] = "From: Sender2\r\n" + "To: Recipient2\r\n" + "Subject: subject2\r\n" + "Content-Type: text/plain\r\n" + "\r\n" + "Line 1\r\n" + "Line 2\r\n" + "Line 3\r\n"; + + MimeDecEntity *entity = MimeDecParseFullMsg((uint8_t *)msg, strlen(msg), &line_count, + TestDataChunkCallback); + + if (entity == NULL) { + SCLogInfo("Warning: Message failed to parse"); + return -1; + } + + MimeDecField *field = MimeDecFindField(entity, "subject"); + if (field == NULL) { + SCLogInfo("Warning: Message failed to parse"); + return -1; + } + + if (field->value_len != sizeof("subject2") - 1) { + SCLogInfo("Warning: failed to get subject"); + return -1; + } + + if (memcmp(field->value, "subject2", field->value_len) != 0) { + SCLogInfo("Warning: failed to get subject"); + return -1; + } + + + MimeDecFreeEntity(entity); + + if (expected_count != line_count) { + SCLogInfo("Warning: Line count is invalid: expected - %d actual - %d", + expected_count, line_count); + return -1; + } + + return ret; +} + static int MimeBase64DecodeTest01(void) { int ret = -1; @@ -2771,7 +2884,7 @@ static int MimeBase64DecodeTest01(void) char *base64msg = "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QU" "VJTVFVWV1hZWjEyMzQ1Njc4OTBAIyQlXiYqKCktPV8rLC4vOydbXTw+Pzo="; - uint8_t *dst = SCMalloc(strlen(msg)-1); + uint8_t *dst = SCMalloc(strlen(msg) + 1); if (dst == NULL) return 0; @@ -2781,6 +2894,8 @@ static int MimeBase64DecodeTest01(void) ret = 0; } + SCFree(dst); + return ret; } @@ -2879,6 +2994,7 @@ void MimeDecRegisterTests(void) UtRegisterTest("MimeDecParseLineTest01", MimeDecParseLineTest01, 0); UtRegisterTest("MimeDecParseLineTest02", MimeDecParseLineTest02, 0); UtRegisterTest("MimeDecParseFullMsgTest01", MimeDecParseFullMsgTest01, 0); + UtRegisterTest("MimeDecParseFullMsgTest02", MimeDecParseFullMsgTest02, 0); UtRegisterTest("MimeBase64DecodeTest01", MimeBase64DecodeTest01, 0); UtRegisterTest("MimeIsExeURLTest01", MimeIsExeURLTest01, 0); UtRegisterTest("MimeIsIpv4HostTest01", MimeIsIpv4HostTest01, 0); |