diff --git a/CHANGES b/CHANGES index b2f54d682e..a8e7a4083d 100644 --- a/CHANGES +++ b/CHANGES @@ -1,8 +1,14 @@ +2.4-14 | 2015-06-28 12:30:12 -0700 + + * BIT-1400: Allow '<' and '>' in MIME multipart boundaries. The spec + doesn't actually seem to permit these, but they seem to occur in + the wild. (Jon Siwek) + 2.4-12 | 2015-06-28 12:21:11 -0700 - * Trying to decompress deflated HTTP content even when zlib headers - are missing. (Seth Hall) + * BIT-1399: Trying to decompress deflated HTTP content even when + zlib headers are missing. (Seth Hall) 2.4-10 | 2015-06-25 07:11:17 -0700 diff --git a/VERSION b/VERSION index 377a280fdc..9329bc912d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.4-12 +2.4-14 diff --git a/src/analyzer/protocol/http/HTTP.cc b/src/analyzer/protocol/http/HTTP.cc index f60d1372ac..ff72c6f350 100644 --- a/src/analyzer/protocol/http/HTTP.cc +++ b/src/analyzer/protocol/http/HTTP.cc @@ -1025,8 +1025,11 @@ void HTTP_Analyzer::DeliverStream(int len, const u_char* data, bool is_orig) } else { - ProtocolViolation("not a http reply line"); - reply_state = EXPECT_REPLY_NOTHING; + if ( line != end_of_line ) + { + ProtocolViolation("not a http reply line"); + reply_state = EXPECT_REPLY_NOTHING; + } } break; diff --git a/src/analyzer/protocol/mime/MIME.cc b/src/analyzer/protocol/mime/MIME.cc index f9ddb7cd3d..cbc1abd17d 100644 --- a/src/analyzer/protocol/mime/MIME.cc +++ b/src/analyzer/protocol/mime/MIME.cc @@ -245,11 +245,16 @@ int MIME_get_field_name(int len, const char* data, data_chunk_t* name) } // See RFC 2045, page 12. -int MIME_is_tspecial (char ch) +int MIME_is_tspecial (char ch, bool is_boundary = false) { - return ch == '(' || ch == ')' || ch == '<' || ch == '>' || ch == '@' || - ch == ',' || ch == ';' || ch == ':' || ch == '\\' || ch == '"' || - ch == '/' || ch == '[' || ch == ']' || ch == '?' || ch == '='; + if ( is_boundary ) + return ch == '(' || ch == ')' || ch == '@' || + ch == ',' || ch == ';' || ch == ':' || ch == '\\' || ch == '"' || + ch == '/' || ch == '[' || ch == ']' || ch == '?' || ch == '='; + else + return ch == '(' || ch == ')' || ch == '<' || ch == '>' || ch == '@' || + ch == ',' || ch == ';' || ch == ':' || ch == '\\' || ch == '"' || + ch == '/' || ch == '[' || ch == ']' || ch == '?' || ch == '='; } int MIME_is_field_name_char (char ch) @@ -257,26 +262,27 @@ int MIME_is_field_name_char (char ch) return ch >= 33 && ch <= 126 && ch != ':'; } -int MIME_is_token_char (char ch) +int MIME_is_token_char (char ch, bool is_boundary = false) { - return ch >= 33 && ch <= 126 && ! MIME_is_tspecial(ch); + return ch >= 33 && ch <= 126 && ! MIME_is_tspecial(ch, is_boundary); } // See RFC 2045, page 12. // A token is composed of characters that are not SPACE, CTLs or tspecials -int MIME_get_token(int len, const char* data, data_chunk_t* token) +int MIME_get_token(int len, const char* data, data_chunk_t* token, + bool is_boundary) { int i = MIME_skip_lws_comments(len, data); while ( i < len ) { int j; - if ( MIME_is_token_char(data[i]) ) + if ( MIME_is_token_char(data[i], is_boundary) ) { token->data = (data + i); for ( j = i; j < len; ++j ) { - if ( ! MIME_is_token_char(data[j]) ) + if ( ! MIME_is_token_char(data[j], is_boundary) ) break; } @@ -358,7 +364,7 @@ int MIME_get_quoted_string(int len, const char* data, data_chunk_t* str) return -1; } -int MIME_get_value(int len, const char* data, BroString*& buf) +int MIME_get_value(int len, const char* data, BroString*& buf, bool is_boundary) { int offset = MIME_skip_lws_comments(len, data); @@ -379,7 +385,7 @@ int MIME_get_value(int len, const char* data, BroString*& buf) else { data_chunk_t str; - int end = MIME_get_token(len, data, &str); + int end = MIME_get_token(len, data, &str, is_boundary); if ( end < 0 ) return -1; @@ -862,8 +868,22 @@ int MIME_Entity::ParseFieldParameters(int len, const char* data) len -= offset; BroString* val = 0; - // token or quoted-string - offset = MIME_get_value(len, data, val); + + if ( current_field_type == MIME_CONTENT_TYPE && + content_type == CONTENT_TYPE_MULTIPART && + strcasecmp_n(attr, "boundary") == 0 ) + { + // token or quoted-string (and some lenience for characters + // not explicitly allowed by the RFC, but encountered in the wild) + offset = MIME_get_value(len, data, val, true); + data_chunk_t vd = get_data_chunk(val); + multipart_boundary = new BroString((const u_char*)vd.data, + vd.length, 1); + } + else + // token or quoted-string + offset = MIME_get_value(len, data, val); + if ( offset < 0 ) { IllegalFormat("value not found in parameter specification"); @@ -873,8 +893,6 @@ int MIME_Entity::ParseFieldParameters(int len, const char* data) data += offset; len -= offset; - - ParseParameter(attr, get_data_chunk(val)); delete val; } @@ -919,24 +937,6 @@ void MIME_Entity::ParseContentEncoding(data_chunk_t encoding_mechanism) content_encoding = i; } -void MIME_Entity::ParseParameter(data_chunk_t attr, data_chunk_t val) - { - switch ( current_field_type ) { - case MIME_CONTENT_TYPE: - if ( content_type == CONTENT_TYPE_MULTIPART && - strcasecmp_n(attr, "boundary") == 0 ) - multipart_boundary = new BroString((const u_char*)val.data, val.length, 1); - break; - - case MIME_CONTENT_TRANSFER_ENCODING: - break; - - default: - break; - } - } - - int MIME_Entity::CheckBoundaryDelimiter(int len, const char* data) { if ( ! multipart_boundary ) diff --git a/src/analyzer/protocol/mime/MIME.h b/src/analyzer/protocol/mime/MIME.h index a33779557c..8c7fdd4326 100644 --- a/src/analyzer/protocol/mime/MIME.h +++ b/src/analyzer/protocol/mime/MIME.h @@ -117,7 +117,6 @@ protected: void ParseContentType(data_chunk_t type, data_chunk_t sub_type); void ParseContentEncoding(data_chunk_t encoding_mechanism); - void ParseParameter(data_chunk_t attr, data_chunk_t val); void BeginBody(); void NewDataLine(int len, const char* data, int trailing_CRLF); @@ -276,9 +275,11 @@ extern int MIME_count_leading_lws(int len, const char* data); extern int MIME_count_trailing_lws(int len, const char* data); extern int MIME_skip_comments(int len, const char* data); extern int MIME_skip_lws_comments(int len, const char* data); -extern int MIME_get_token(int len, const char* data, data_chunk_t* token); +extern int MIME_get_token(int len, const char* data, data_chunk_t* token, + bool is_boundary = false); extern int MIME_get_slash_token_pair(int len, const char* data, data_chunk_t* first, data_chunk_t* second); -extern int MIME_get_value(int len, const char* data, BroString*& buf); +extern int MIME_get_value(int len, const char* data, BroString*& buf, + bool is_boundary = false); extern int MIME_get_field_name(int len, const char* data, data_chunk_t* name); extern BroString* MIME_decode_quoted_pairs(data_chunk_t buf);