]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #1530 in SNORT/snort3 from ~BRASTULT/snort3:file_decomp_zip to...
authorTom Peters (thopeter) <thopeter@cisco.com>
Wed, 6 Mar 2019 15:29:36 +0000 (10:29 -0500)
committerTom Peters (thopeter) <thopeter@cisco.com>
Wed, 6 Mar 2019 15:29:36 +0000 (10:29 -0500)
Squashed commit of the following:

commit 57dc105bf414ec66d623de5cbadc31af7c0fdc4b
Author: Brandon Stultz <brastult@cisco.com>
Date:   Wed Feb 27 19:28:08 2019 -0500

    decompress: add zip file decompression

13 files changed:
src/decompress/CMakeLists.txt
src/decompress/file_decomp.cc
src/decompress/file_decomp.h
src/decompress/file_decomp_zip.cc [new file with mode: 0644]
src/decompress/file_decomp_zip.h [new file with mode: 0644]
src/service_inspectors/http_inspect/http_enum.h
src/service_inspectors/http_inspect/http_module.cc
src/service_inspectors/http_inspect/http_module.h
src/service_inspectors/http_inspect/http_msg_body.cc
src/service_inspectors/http_inspect/http_msg_body.h
src/service_inspectors/http_inspect/http_msg_header.cc
src/service_inspectors/http_inspect/http_msg_header.h
src/service_inspectors/http_inspect/http_tables.cc

index 27b44e5f03a60ad6128b198f88547c1578240c09..21ba69be9558145c95bc6a518d985559e146721c 100644 (file)
@@ -10,6 +10,8 @@ add_library (decompress OBJECT
     file_decomp_pdf.h
     file_decomp_swf.cc
     file_decomp_swf.h
+    file_decomp_zip.cc
+    file_decomp_zip.h
 )
 
 install (FILES ${DECOMPRESS_INCLUDES}
index b076f21eefd1734e18d31c794113c32c27a4ed41..3749b6e7e45b0eba1e525790e37bdbc7ad5c8b1f 100644 (file)
@@ -31,6 +31,7 @@
 
 #include "file_decomp_pdf.h"
 #include "file_decomp_swf.h"
+#include "file_decomp_zip.h"
 
 #ifdef UNIT_TEST
 #include "catch/snort_catch.h"
@@ -44,6 +45,7 @@ static const char SWF_ZLIB_Sig[3] = { 'C', 'W', 'S' };
 static const char SWF_LZMA_Sig[3] = { 'Z', 'W', 'S' };
 #endif
 static const char SWF_Uncomp_Sig[3] = { 'F', 'W', 'S' };
+static const char ZIP_Sig[4] = { 'P', 'K', 0x03, 0x04 };
 
 /* Please assure that the following value correlates with the set of sig's */
 #define MAX_SIG_LENGTH (5)
@@ -64,6 +66,9 @@ static struct sig_map_s
 #ifdef HAVE_LZMA
     { SWF_LZMA_Sig, sizeof(SWF_LZMA_Sig), false, FILE_TYPE_SWF, FILE_COMPRESSION_TYPE_LZMA },
 #endif
+
+    { ZIP_Sig, sizeof(ZIP_Sig), false, FILE_TYPE_ZIP, FILE_COMPRESSION_TYPE_NONE },
+
     { nullptr, 0, false, FILE_TYPE_NONE, FILE_COMPRESSION_TYPE_NONE }
 };
 
@@ -195,6 +200,9 @@ static fd_status_t Initialize_Decompression(fd_session_t* SessionPtr)
         Ret_Code = File_Decomp_Init_PDF(SessionPtr);
         break;
     }
+    case ( FILE_TYPE_ZIP ):
+        Ret_Code = File_Decomp_Init_ZIP(SessionPtr);
+        break;
     default:
         return( File_Decomp_Error );
     }
@@ -221,6 +229,11 @@ static fd_status_t Process_Decompression(fd_session_t* SessionPtr)
         Ret_Code = File_Decomp_PDF(SessionPtr);
         break;
     }
+    case ( FILE_TYPE_ZIP ):
+    {
+        Ret_Code = File_Decomp_ZIP(SessionPtr);
+        break;
+    }
     default:
         return( File_Decomp_Error );
     }
@@ -262,6 +275,10 @@ fd_status_t File_Decomp_Init(fd_session_t* SessionPtr)
             ((SessionPtr->Modes & FILE_SWF_LZMA_BIT) != 0) )
             Signature_Map[Sig].Enabled = true;
 #endif
+
+        if ( (Signature_Map[Sig].File_Type == FILE_TYPE_ZIP ) &&
+            ((SessionPtr->Modes & FILE_ZIP_DEFL_BIT) != 0) )
+            Signature_Map[Sig].Enabled = true;
     }
 
     return( File_Decomp_OK );
@@ -337,6 +354,8 @@ fd_status_t File_Decomp_End(fd_session_t* SessionPtr)
     {
         return( File_Decomp_End_PDF(SessionPtr) );
     }
+    case ( FILE_TYPE_ZIP ):
+        return( File_Decomp_End_ZIP(SessionPtr) );
     }
 
     return( File_Decomp_Error );
@@ -382,6 +401,10 @@ void File_Decomp_Free(fd_session_t* SessionPtr)
         assert(SessionPtr->PDF);
         snort_free(SessionPtr->PDF);
         break;
+    case FILE_TYPE_ZIP:
+        assert(SessionPtr->ZIP);
+        snort_free(SessionPtr->ZIP);
+        break;
     }
 
     delete SessionPtr;
index c55a5d56c4a36e25fb89fb8b1eef9231e7798e8b..4c36c960f90cecf0d22d5230bfffdbf7104fcfba 100644 (file)
@@ -60,9 +60,11 @@ enum file_compression_type_t
 #define FILE_SWF_LZMA_BIT    (0x00000001)
 #define FILE_SWF_ZLIB_BIT    (0x00000002)
 #define FILE_PDF_DEFL_BIT    (0x00000004)
+#define FILE_ZIP_DEFL_BIT    (0x00000008)
 
 #define FILE_PDF_ANY         (FILE_PDF_DEFL_BIT)
 #define FILE_SWF_ANY         (FILE_SWF_LZMA_BIT | FILE_SWF_ZLIB_BIT)
+#define FILE_ZIP_ANY         (FILE_ZIP_DEFL_BIT)
 
 /* Error codes either passed to caller via the session->Error_Alert of
    the File_Decomp_Alert() call-back function. */
@@ -73,7 +75,9 @@ enum FileDecompError
     FILE_DECOMP_ERR_PDF_DEFL_FAILURE,
     FILE_DECOMP_ERR_PDF_UNSUP_COMP_TYPE,
     FILE_DECOMP_ERR_PDF_CASC_COMP,
-    FILE_DECOMP_ERR_PDF_PARSE_FAILURE
+    FILE_DECOMP_ERR_PDF_PARSE_FAILURE,
+    FILE_DECOMP_ERR_ZIP_PARSE_FAILURE,
+    FILE_DECOMP_ERR_ZIP_DEFL_FAILURE
 };
 
 /* Private Types */
@@ -82,6 +86,7 @@ enum file_type_t
     FILE_TYPE_NONE,
     FILE_TYPE_SWF,
     FILE_TYPE_PDF,
+    FILE_TYPE_ZIP,
     FILE_TYPE_MAX
 };
 
@@ -102,6 +107,7 @@ struct fd_session_t
     {
         struct fd_PDF_t* PDF;
         struct fd_SWF_t* SWF;
+        struct fd_ZIP_t* ZIP;
     };
 
     const uint8_t* Next_In;     // next input byte
@@ -257,12 +263,12 @@ inline bool Move_N(fd_session_t* SessionPtr, uint16_t N)
     if ( (SessionPtr->Next_Out != nullptr) && (SessionPtr->Avail_Out >= N) &&
         (SessionPtr->Next_In != nullptr) && (SessionPtr->Avail_In >= N) )
     {
-        strncpy( (char*)SessionPtr->Next_Out, (const char*)SessionPtr->Next_In, N);
+        memcpy( (char*)SessionPtr->Next_Out, (const char*)SessionPtr->Next_In, N);
         SessionPtr->Next_Out += N;
         SessionPtr->Next_In += N;
         SessionPtr->Avail_In -= N;
         SessionPtr->Avail_Out -= N;
-        SessionPtr->Avail_Out -= N;
+        SessionPtr->Total_In += N;
         SessionPtr->Total_Out += N;
         return( true );
     }
diff --git a/src/decompress/file_decomp_zip.cc b/src/decompress/file_decomp_zip.cc
new file mode 100644 (file)
index 0000000..48a6672
--- /dev/null
@@ -0,0 +1,404 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2019-2019 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+
+// file_decomp_zip.cc author Brandon Stultz <brastult@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "file_decomp_zip.h"
+#include "utils/util.h"
+
+using namespace snort;
+
+// initialize zlib decompression
+static fd_status_t Inflate_Init(fd_session_t* SessionPtr)
+{
+    z_stream* z_s = &(SessionPtr->ZIP->Stream);
+
+    memset((char*)z_s, 0, sizeof(z_stream));
+
+    z_s->zalloc = (alloc_func)nullptr;
+    z_s->zfree = (free_func)nullptr;
+
+    SYNC_IN(z_s)
+
+    int z_ret = inflateInit2(z_s, -MAX_WBITS);
+
+    if ( z_ret != Z_OK )
+        return File_Decomp_Error;
+
+    return File_Decomp_OK;
+}
+
+// end zlib decompression
+static fd_status_t Inflate_End(fd_session_t* SessionPtr)
+{
+    z_stream* z_s = &(SessionPtr->ZIP->Stream);
+
+    inflateEnd(z_s);
+
+    return File_Decomp_OK;
+}
+
+// perform zlib decompression
+static fd_status_t Inflate(fd_session_t* SessionPtr)
+{
+    const uint8_t *zlib_start, *zlib_end;
+
+    z_stream* z_s = &(SessionPtr->ZIP->Stream);
+
+    zlib_start = SessionPtr->Next_In;
+
+    SYNC_IN(z_s)
+
+    int z_ret = inflate(z_s, Z_SYNC_FLUSH);
+
+    SYNC_OUT(z_s)
+
+    zlib_end = SessionPtr->Next_In;
+
+    // keep track of decompression progress
+    SessionPtr->ZIP->progress += zlib_end - zlib_start;
+
+    if ( z_ret == Z_STREAM_END )
+        return File_Decomp_Complete;
+
+    if ( z_ret != Z_OK )
+        return File_Decomp_Error;
+
+    if ( SessionPtr->Avail_Out == 0 )
+        return File_Decomp_BlockOut;
+
+    return File_Decomp_OK;
+}
+
+// allocate and set initial ZIP state
+fd_status_t File_Decomp_Init_ZIP(fd_session_t* SessionPtr)
+{
+    if ( SessionPtr == nullptr )
+        return File_Decomp_Error;
+
+    SessionPtr->ZIP = (fd_ZIP_t*)snort_calloc(sizeof(fd_ZIP_t));
+
+    // file_decomp.cc already matched the local header
+    // skip the version and bitflag (4 bytes)
+    SessionPtr->ZIP->State = ZIP_STATE_SKIP;
+    SessionPtr->ZIP->Length = 4;
+
+    // land on compression method
+    SessionPtr->ZIP->Next = ZIP_STATE_METHOD;
+    SessionPtr->ZIP->Next_Length = 2;
+
+    return File_Decomp_OK;
+}
+
+// end ZIP processing
+fd_status_t File_Decomp_End_ZIP(fd_session_t* SessionPtr)
+{
+    if ( SessionPtr == nullptr )
+        return File_Decomp_Error;
+
+    // end zlib decompression if we are processing a stream
+    if ( SessionPtr->ZIP->State == ZIP_STATE_INFLATE )
+        Inflate_End(SessionPtr);
+
+    // File_Decomp_Free() will free SessionPtr->ZIP
+    return File_Decomp_OK;
+}
+
+// run the ZIP state machine
+fd_status_t File_Decomp_ZIP(fd_session_t* SessionPtr)
+{
+    uint8_t byte;
+
+    if ( SessionPtr == nullptr )
+        return File_Decomp_Error;
+
+    fd_ZIP_t* parser = SessionPtr->ZIP;
+
+    // while we have data to read in the stream
+    while ( SessionPtr->Avail_In > 0 )
+    {
+        if ( SessionPtr->Next_In == nullptr )
+            return File_Decomp_Error;
+
+        switch ( parser->State )
+        {
+        // local header
+        case ZIP_STATE_LH:
+            // check if we are done with the local_header
+            if ( parser->Index == parser->Length )
+            {
+                // check if we read a local_header
+                if ( parser->local_header != ZIP_LOCAL_HEADER )
+                    return File_Decomp_Complete;
+
+                // read a local_header, reset the index
+                parser->Index = 0;
+
+                // reset ZIP fields
+                parser->local_header = 0;
+                parser->method = 0;
+                parser->compressed_size = 0;
+                parser->filename_length = 0;
+                parser->extra_length = 0;
+
+                // reset decompression progress
+                parser->progress = 0;
+
+                // skip the version and bitflag (4 bytes)
+                parser->State = ZIP_STATE_SKIP;
+                parser->Length = 4;
+
+                // land on compression method
+                parser->Next = ZIP_STATE_METHOD;
+                parser->Next_Length = 2;
+                continue;
+            }
+            // read the local header
+            byte = *SessionPtr->Next_In;
+            parser->local_header |= byte << parser->Index*8;
+            break;
+        // compression method
+        case ZIP_STATE_METHOD:
+            // check if we are done with the method
+            if ( parser->Index == parser->Length )
+            {
+                // read the method, reset the index
+                parser->Index = 0;
+
+                // skip:
+                //  modtime(2), moddate(2), crc(4) = 8 bytes
+                parser->State = ZIP_STATE_SKIP;
+                parser->Length = 8;
+
+                // land on compressed size
+                parser->Next = ZIP_STATE_COMPSIZE;
+                parser->Next_Length = 4;
+                continue;
+            }
+            // read the method
+            byte = *SessionPtr->Next_In;
+            parser->method |= byte << parser->Index*8;
+            break;
+        // compressed size
+        case ZIP_STATE_COMPSIZE:
+            // check if we are done with the compressed size
+            if ( parser->Index == parser->Length )
+            {
+                // read the compressed size, reset the index
+                parser->Index = 0;
+
+                // skip the uncompressed size (4 bytes)
+                parser->State = ZIP_STATE_SKIP;
+                parser->Length = 4;
+
+                // land on filename length
+                parser->Next = ZIP_STATE_FILENAMELEN;
+                parser->Next_Length = 2;
+                continue;
+            }
+            // read the compressed size
+            byte = *SessionPtr->Next_In;
+            parser->compressed_size |= byte << parser->Index*8;
+            break;
+        // filename length
+        case ZIP_STATE_FILENAMELEN:
+            // check if we are done with the filename length
+            if ( parser->Index == parser->Length )
+            {
+                // read the filename length, reset the index
+                parser->Index = 0;
+
+                // read the extra field length next
+                parser->State = ZIP_STATE_EXTRALEN;
+                parser->Length = 2;
+                continue;
+            }
+            // read the filename length
+            byte = *SessionPtr->Next_In;
+            parser->filename_length |= byte << parser->Index*8;
+            break;
+        // extra length
+        case ZIP_STATE_EXTRALEN:
+            // check if we are done with the extra length
+            if ( parser->Index == parser->Length )
+            {
+                // read the extra length, reset the index
+                parser->Index = 0;
+
+                // skip the filename and extra fields
+                parser->State = ZIP_STATE_SKIP;
+                parser->Length = parser->filename_length + parser->extra_length;
+
+                if ( (SessionPtr->Avail_Out > 0) && (parser->method == 8) )
+                {
+                    // we have available output space and
+                    // the compression type is deflate (8),
+                    // land on the compressed stream, init zlib
+                    parser->Next = ZIP_STATE_INFLATE_INIT;
+                    parser->Next_Length = parser->compressed_size;
+                    continue;
+                }
+
+                // no output space or compression type isn't deflate, skip the stream
+                parser->Length += parser->compressed_size;
+
+                // land on another local header
+                parser->Next = ZIP_STATE_LH;
+                parser->Next_Length = 4;
+                continue;
+            }
+            // read the extra length
+            byte = *SessionPtr->Next_In;
+            parser->extra_length |= byte << parser->Index*8;
+            break;
+        // initialize zlib inflate
+        case ZIP_STATE_INFLATE_INIT:
+            parser->State = ZIP_STATE_INFLATE;
+
+            if ( Inflate_Init(SessionPtr) == File_Decomp_Error )
+                return File_Decomp_Error;
+
+            // fallthrough
+        // perform zlib inflate
+        case ZIP_STATE_INFLATE:
+        {
+            // run inflate
+            fd_status_t status = Inflate(SessionPtr);
+
+            if ( status == File_Decomp_Error )
+            {
+                // error inflating the stream
+                // File_Decomp_End_ZIP() will
+                // close the inflate stream
+                return File_Decomp_Error;
+            }
+
+            if ( status == File_Decomp_BlockOut )
+            {
+                // ran out of output space
+                // progress should be < compressed_size
+                if ( parser->progress >= parser->compressed_size )
+                    return File_Decomp_Error;
+
+                // close the inflate stream
+                Inflate_End(SessionPtr);
+
+                // skip the rest of the stream
+                parser->State = ZIP_STATE_SKIP;
+                parser->Length = parser->compressed_size - parser->progress;
+
+                // land on another local header
+                parser->Next = ZIP_STATE_LH;
+                parser->Next_Length = 4;
+                continue;
+            }
+
+            if ( status == File_Decomp_Complete )
+            {
+                // done decompressing the stream
+                // close the inflate stream
+                Inflate_End(SessionPtr);
+
+                // parse next local header
+                parser->State = ZIP_STATE_LH;
+                parser->Length = 4;
+                continue;
+            }
+
+            // keep the inflate stream open
+            // circle back for more input
+            return File_Decomp_OK;
+        }
+        // skip state
+        case ZIP_STATE_SKIP:
+            // check if we need to skip
+            if ( parser->Index < parser->Length )
+            {
+                unsigned skip = parser->Length - parser->Index;
+
+                // check if we can skip within this flush
+                if ( SessionPtr->Avail_In < skip )
+                {
+                    // the available input is < skip
+                    parser->Index += SessionPtr->Avail_In;
+
+                    unsigned min = SessionPtr->Avail_In < SessionPtr->Avail_Out ?
+                                   SessionPtr->Avail_In : SessionPtr->Avail_Out;
+
+                    // copy what we can
+                    Move_N(SessionPtr, min);
+
+                    // get more input
+                    return File_Decomp_BlockIn;
+                }
+
+                if ( SessionPtr->Avail_Out < skip )
+                {
+                    // the available input is >= skip
+                    // the available output is < skip <= available input
+                    skip -= SessionPtr->Avail_Out;
+                    // copy what we can
+                    Move_N(SessionPtr, SessionPtr->Avail_Out);
+                    // available output is now 0
+                    // skip the rest
+                    SessionPtr->Next_In += skip;
+                    SessionPtr->Avail_In -= skip;
+                    SessionPtr->Total_In += skip;
+                    // done skipping, index should be 0
+                }
+                else
+                {
+                    // the available input is >= skip
+                    // the available output is >= skip
+                    // copy skip bytes from input to output
+                    Move_N(SessionPtr, skip);
+                    // done skipping, index should be 0
+                }
+            }
+            // done skipping, reset the index
+            parser->Index = 0;
+
+            // switch to the next state
+            parser->State = parser->Next;
+            parser->Length = parser->Next_Length;
+            continue;
+        }
+
+        // make sure we can write a byte
+        if ( SessionPtr->Avail_Out > 0 )
+        {
+            // advance and copy the stream
+            Move_1(SessionPtr);
+        }
+        else
+        {
+            // advance the stream
+            SessionPtr->Next_In += 1;
+            SessionPtr->Avail_In -= 1;
+            SessionPtr->Total_In += 1;
+        }
+
+        parser->Index++;
+    }
+
+    return File_Decomp_BlockIn;
+}
diff --git a/src/decompress/file_decomp_zip.h b/src/decompress/file_decomp_zip.h
new file mode 100644 (file)
index 0000000..fe82f97
--- /dev/null
@@ -0,0 +1,99 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2019-2019 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+
+// file_decomp_zip.h author Brandon Stultz <brastult@cisco.com>
+
+#ifndef FILE_DECOMP_ZIP_H
+#define FILE_DECOMP_ZIP_H
+
+#include "file_decomp.h"
+
+#include <zlib.h>
+
+static const uint32_t ZIP_LOCAL_HEADER = 0x04034B50;
+
+enum fd_ZIP_states
+{
+    ZIP_STATE_LH,             // local header (4 bytes)
+
+    // skipped:
+    // ZIP_STATE_VER,         // version (2 bytes)
+    // ZIP_STATE_BITFLAG,     // bitflag (2 bytes)
+
+    ZIP_STATE_METHOD,         // compression method (2 bytes)
+
+    // skipped:
+    // ZIP_STATE_MODTIME,     // modification time (2 bytes)
+    // ZIP_STATE_MODDATE,     // modification date (2 bytes)
+    // ZIP_STATE_CRC,         // CRC-32 (4 bytes)
+
+    ZIP_STATE_COMPSIZE,       // compressed size (4 bytes)
+
+    // skipped:
+    // ZIP_STATE_UNCOMPSIZE,  // uncompressed size (4 bytes)
+
+    ZIP_STATE_FILENAMELEN,    // filename length (2 bytes)
+    ZIP_STATE_EXTRALEN,       // extra field length (2 bytes)
+
+    // skipped:
+    // ZIP_STATE_FILENAME,    // filename field (filenamelen bytes)
+    // ZIP_STATE_EXTRA,       // extra field (extralen bytes)
+    // ZIP_STATE_STREAM,      // compressed stream (compsize bytes)
+
+    ZIP_STATE_INFLATE_INIT,   // initialize zlib inflate
+    ZIP_STATE_INFLATE,        // perform zlib inflate
+    ZIP_STATE_SKIP            // skip state
+};
+
+struct fd_ZIP_t
+{
+    // zlib stream
+    z_stream Stream;
+
+    // decompression progress
+    unsigned progress;
+
+    // ZIP fields
+    uint32_t local_header;
+    uint16_t method;
+    uint32_t compressed_size;
+    uint16_t filename_length;
+    uint16_t extra_length;
+
+    // field index
+    unsigned Index;
+
+    // current parser state
+    fd_ZIP_states State;
+    unsigned Length;
+
+    // next parser state
+    fd_ZIP_states Next;
+    unsigned Next_Length;
+};
+
+// allocate and set initial ZIP state
+fd_status_t File_Decomp_Init_ZIP(fd_session_t*);
+
+// end ZIP processing
+fd_status_t File_Decomp_End_ZIP(fd_session_t*);
+
+// run the ZIP state machine
+fd_status_t File_Decomp_ZIP(fd_session_t*);
+
+#endif
index 1bb26d78ba29c1f6189f8b7f9c12b86a3717656c..d4b18683346d07992c7b3fdf4d939072cb4d3194 100644 (file)
@@ -215,7 +215,7 @@ enum Infraction
     INF_PDF_UNSUP_COMP_TYPE,
     INF_PDF_CASC_COMP,
     INF_PDF_PARSE_FAILURE,
-    INF_PDF_SWF_OVERRUN,
+    INF_FILE_DECOMPR_OVERRUN,
     INF_BAD_CHAR_IN_HEADER_NAME,
     INF_HEADER_WRAPPING,
     INF_CHUNK_BAD_SEP,
@@ -330,7 +330,7 @@ enum EventSid
     EVENT_UNKNOWN_ENCODING,
     EVENT_STACKED_ENCODINGS,
     EVENT_RESPONSE_WO_REQUEST,
-    EVENT_PDF_SWF_OVERRUN,
+    EVENT_FILE_DECOMPR_OVERRUN,
     EVENT_BAD_CHAR_IN_HEADER_NAME,         // 230
     EVENT_BAD_CONTENT_LENGTH,
     EVENT_HEADER_WRAPPING,
index c5f3101136ffae386084db2cc7c4be87ac1046c2..4f3c902073a233dd8a1e25e0191a56060ff6be6b 100644 (file)
@@ -51,6 +51,9 @@ const Parameter HttpModule::http_params[] =
     { "decompress_swf", Parameter::PT_BOOL, nullptr, "false",
       "decompress swf files in response bodies" },
 
+    { "decompress_zip", Parameter::PT_BOOL, nullptr, "false",
+      "decompress zip files in response bodies" },
+
     { "normalize_javascript", Parameter::PT_BOOL, nullptr, "false",
       "normalize javascript in response bodies" },
 
@@ -160,6 +163,10 @@ bool HttpModule::set(const char*, Value& val, SnortConfig*)
     {
         params->decompress_swf = val.get_bool();
     }
+    else if (val.is("decompress_zip"))
+    {
+        params->decompress_zip = val.get_bool();
+    }
     else if (val.is("normalize_javascript"))
     {
         params->js_norm_param.normalize_javascript = val.get_bool();
index 5ddcbaa31c536b157ffab1735b4a4bc5b08a1f62..cfec45b2353ac6f91a3143358fb177e6e9332f10 100644 (file)
@@ -41,6 +41,7 @@ public:
     bool normalize_utf = true;
     bool decompress_pdf = false;
     bool decompress_swf = false;
+    bool decompress_zip = false;
 
     struct JsNormParam
     {
index 24e372d8055eb7a4ee3c32a6cb45051bb01f0d07..7f5429ccf1e41d2c166762da337cffc0f0efdb0d 100644 (file)
@@ -49,8 +49,8 @@ void HttpMsgBody::analyze()
 
     if (session_data->detect_depth_remaining[source_id] > 0)
     {
-        do_pdf_swf_decompression(decoded_body, decompressed_pdf_swf_body);
-        do_js_normalization(decompressed_pdf_swf_body, js_norm_body);
+        do_file_decompression(decoded_body, decompressed_file_body);
+        do_js_normalization(decompressed_file_body, js_norm_body);
         const int32_t detect_length =
             (js_norm_body.length() <= session_data->detect_depth_remaining[source_id]) ?
             js_norm_body.length() : session_data->detect_depth_remaining[source_id];
@@ -111,7 +111,7 @@ void HttpMsgBody::do_utf_decoding(const Field& input, Field& output)
         output.set(input);
 }
 
-void HttpMsgBody::do_pdf_swf_decompression(const Field& input, Field& output)
+void HttpMsgBody::do_file_decompression(const Field& input, Field& output)
 {
     if ((source_id == SRC_CLIENT) || (session_data->fd_state == nullptr))
     {
@@ -141,8 +141,8 @@ void HttpMsgBody::do_pdf_swf_decompression(const Field& input, Field& output)
         session_data->fd_state = nullptr;
         break;
     case File_Decomp_BlockOut:
-        add_infraction(INF_PDF_SWF_OVERRUN);
-        create_event(EVENT_PDF_SWF_OVERRUN);
+        add_infraction(INF_FILE_DECOMPR_OVERRUN);
+        create_event(EVENT_FILE_DECOMPR_OVERRUN);
         // Fall through
     default:
         output.set(session_data->fd_state->Next_Out - buffer, buffer, true);
index 320010e29ccf70dc18e94e7f1c494bfef453833e..d49beb3ecccde8e521a2e93596c16151151773c6 100644 (file)
@@ -53,13 +53,13 @@ protected:
 private:
     void do_file_processing(Field& file_data);
     void do_utf_decoding(const Field& input, Field& output);
-    void do_pdf_swf_decompression(const Field& input, Field& output);
+    void do_file_decompression(const Field& input, Field& output);
     void do_js_normalization(const Field& input, Field& output);
 
     Field detect_data;
     Field classic_client_body;   // URI normalization applied
     Field decoded_body;
-    Field decompressed_pdf_swf_body;
+    Field decompressed_file_body;
     Field js_norm_body;
     const bool detection_section;
 };
index 1424663510beb31e31c0a1d1178b6266f37ee711..8c1e75b7f5c84cf30adf3ca2e79debb90baa7b2a 100644 (file)
@@ -303,7 +303,7 @@ void HttpMsgHeader::prepare_body()
     setup_file_processing();
     setup_encoding_decompression();
     setup_utf_decoding();
-    setup_pdf_swf_decompression();
+    setup_file_decompression();
     update_depth();
     if (source_id == SRC_CLIENT)
     {
@@ -481,15 +481,17 @@ void HttpMsgHeader::setup_utf_decoding()
     session_data->utf_state->set_decode_utf_state_charset(charset_code);
 }
 
-void HttpMsgHeader::setup_pdf_swf_decompression()
+void HttpMsgHeader::setup_file_decompression()
 {
-    if (source_id == SRC_CLIENT || (!params->decompress_pdf && !params->decompress_swf))
+    if (source_id == SRC_CLIENT ||
+       (!params->decompress_pdf && !params->decompress_swf && !params->decompress_zip))
         return;
 
     session_data->fd_state = File_Decomp_New();
     session_data->fd_state->Modes =
         (params->decompress_pdf ? FILE_PDF_DEFL_BIT : 0) |
-        (params->decompress_swf ? (FILE_SWF_ZLIB_BIT | FILE_SWF_LZMA_BIT) : 0);
+        (params->decompress_swf ? (FILE_SWF_ZLIB_BIT | FILE_SWF_LZMA_BIT) : 0) |
+        (params->decompress_zip ? FILE_ZIP_DEFL_BIT : 0);
     session_data->fd_state->Alert_Callback = HttpMsgBody::fd_event_callback;
     session_data->fd_state->Alert_Context = &session_data->fd_alert_context;
     session_data->fd_state->Compr_Depth = 0;
index 3ba0f1c3238c4511612185c4c4cefa9375ccaf2a..2c00c1ab44d574baceec206416b51823d133700a 100644 (file)
@@ -49,7 +49,7 @@ private:
     void setup_file_processing();
     void setup_encoding_decompression();
     void setup_utf_decoding();
-    void setup_pdf_swf_decompression();
+    void setup_file_decompression();
 
     // Dummy configurations to support MIME processing
     MailLogConfig mime_conf;
index 54c2c91dfc0fa72bed2ceccea1a5fb2e61649fdd..fb5f9ea30a07ed093a4e3458f4020cbde0b1f6fb 100644 (file)
@@ -355,7 +355,7 @@ const snort::RuleMap HttpModule::http_events[] =
     { EVENT_UNKNOWN_ENCODING,           "unknown Content-Encoding used" },
     { EVENT_STACKED_ENCODINGS,          "multiple Content-Encodings applied" },
     { EVENT_RESPONSE_WO_REQUEST,        "server response before client request" },
-    { EVENT_PDF_SWF_OVERRUN,            "PDF/SWF decompression of server response too big" },
+    { EVENT_FILE_DECOMPR_OVERRUN,       "PDF/SWF/ZIP decompression of server response too big" },
     { EVENT_BAD_CHAR_IN_HEADER_NAME,    "nonprinting character in HTTP message header name" },
     { EVENT_BAD_CONTENT_LENGTH,         "bad Content-Length value in HTTP header" },
     { EVENT_HEADER_WRAPPING,            "HTTP header line wrapped" },