aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/suricata/src/util-decode-mime.c
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/suricata/src/util-decode-mime.c')
-rw-r--r--framework/src/suricata/src/util-decode-mime.c158
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);