]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Pull request #3201: mime: Adding the support for vba macro data extraction of MS...
authorPranav Bhalerao (prbhaler) <prbhaler@cisco.com>
Fri, 10 Dec 2021 09:56:02 +0000 (09:56 +0000)
committerPranav Bhalerao (prbhaler) <prbhaler@cisco.com>
Fri, 10 Dec 2021 09:56:02 +0000 (09:56 +0000)
Merge in SNORT/snort3 from ~AMARNAYA/snort3:mime_vba to master

Squashed commit of the following:

commit d185bb6c0c8921949acb7137fc7f0a30a837d4f4
Author: Amarnath Nayak <amarnaya@cisco.com>
Date:   Wed Dec 1 18:57:26 2021 +0000

    mime: adding the support for vba macro data extraction of  MS office files transferred over mime protocols

16 files changed:
src/decompress/file_olefile.cc
src/helpers/CMakeLists.txt
src/helpers/buffer_data.cc [new file with mode: 0644]
src/helpers/buffer_data.h [new file with mode: 0644]
src/mime/file_mime_config.cc
src/mime/file_mime_config.h
src/mime/file_mime_decode.cc
src/mime/file_mime_decode.h
src/mime/file_mime_process.cc
src/mime/file_mime_process.h
src/service_inspectors/imap/imap.cc
src/service_inspectors/imap/imap_module.cc
src/service_inspectors/pop/pop.cc
src/service_inspectors/pop/pop_module.cc
src/service_inspectors/smtp/smtp.cc
src/service_inspectors/smtp/smtp_module.cc

index be3c62188bcb540708f4dada3b346e50aa9d9cb1..28b3209c6ab4e13f682765666727cf16c8f73298 100644 (file)
@@ -307,7 +307,7 @@ void OleFile :: get_file_data(char* file, uint8_t*& file_data, uint32_t& data_le
                                     stream_size, sector_size);
 
                 memcpy(temp_data, (file_buf + byte_offset), bytes_to_copy);
-                temp_data += sector_size;
+                temp_data += bytes_to_copy;
                 data_len += bytes_to_copy;
 
                 int32_t next_sector = get_next_fat_sector(current_sector);
@@ -328,7 +328,7 @@ void OleFile :: get_file_data(char* file, uint8_t*& file_data, uint32_t& data_le
                                     stream_size, mini_sector_size);
 
                 memcpy(temp_data, (file_buf + byte_offset), bytes_to_copy);
-                temp_data += mini_sector_size;
+                temp_data += bytes_to_copy;
                 data_len += bytes_to_copy;
 
                 int32_t next_sector = get_next_mini_fat_sector(mini_sector);
index 49e3f71c1246a6b7c8294eb3d6241dd4fc63bc56..0743bbb7020cd682fb45ce4e671df1840b94790f 100644 (file)
@@ -13,6 +13,7 @@ endif ()
 set (HELPERS_INCLUDES
     ${HYPER_HEADERS}
     base64_encoder.h
+    buffer_data.h
     boyer_moore_search.h
     literal_search.h
     scratch_allocator.h
@@ -25,6 +26,7 @@ add_library (helpers OBJECT
     base64_encoder.cc
     bitop.h
     boyer_moore_search.cc
+    buffer_data.cc
     chunk.cc
     chunk.h
     directory.cc
diff --git a/src/helpers/buffer_data.cc b/src/helpers/buffer_data.cc
new file mode 100644 (file)
index 0000000..1b0186c
--- /dev/null
@@ -0,0 +1,62 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2021 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.
+//--------------------------------------------------------------------------
+// buffer_data.cc author Amarnath Nayak <amarnaya@cisco.com>
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "buffer_data.h"
+
+namespace snort
+{
+BufferData::BufferData(int32_t length, const uint8_t* data_, bool own_the_buffer_ = false) :
+            len(length), data(data_), own_the_buffer(own_the_buffer_){}
+
+BufferData::~BufferData() 
+{ 
+    if (own_the_buffer) 
+        delete[] data; 
+}
+
+int32_t BufferData::length() const
+{ 
+    return len;
+}
+
+const uint8_t* BufferData::data_ptr() const
+{ 
+    return data; 
+}
+
+void BufferData::set(int32_t length, const uint8_t* data_, bool own_the_buffer_)
+{
+    len = length; 
+    data = data_; 
+    own_the_buffer = own_the_buffer_; 
+}
+
+void BufferData::reset()
+{ 
+    if (own_the_buffer) 
+        delete[] data;
+
+    len = 0; 
+    data = nullptr; 
+    own_the_buffer = false; 
+}
+}
diff --git a/src/helpers/buffer_data.h b/src/helpers/buffer_data.h
new file mode 100644 (file)
index 0000000..d8636c5
--- /dev/null
@@ -0,0 +1,51 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2021 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.
+//--------------------------------------------------------------------------
+// buffer_data.h author Amarnath Nayak <amarnaya@cisco.com>
+#ifndef BUFFER_DATA_H
+#define BUFFER_DATA_H
+
+#include <cstdint>
+
+#include "main/snort_types.h"
+
+namespace snort
+{
+class SO_PUBLIC BufferData
+{
+public:
+    BufferData(int32_t length, const uint8_t* data_, bool own_the_buffer_);
+    BufferData() = default;
+
+    ~BufferData();
+
+    int32_t length() const;
+    const uint8_t* data_ptr() const;
+
+    void set(int32_t length, const uint8_t* data_, bool own_the_buffer_);
+
+    void reset();
+
+    static const BufferData buffer_null;
+
+private:
+    int32_t len = 0;
+    const uint8_t* data = nullptr;
+    bool own_the_buffer = false;
+};
+}
+#endif
index 9036cf10ae90b672b5c7ba6b7037eea5716b0ca0..0dface3667708304107fe3808d7afe737b6f8137 100644 (file)
@@ -111,6 +111,16 @@ bool DecodeConfig::is_decompress_zip() const
     return decompress_zip;
 }
 
+void DecodeConfig::set_decompress_vba(bool enabled)
+{
+    decompress_vba = enabled;
+}
+
+bool DecodeConfig::is_decompress_vba() const
+{
+    return decompress_vba;
+}
+
 void DecodeConfig::set_decompress_buffer_size(uint32_t size)
 {
     decompress_buffer_size = size;
@@ -171,6 +181,7 @@ void DecodeConfig::show(bool full) const
     ConfigLogger::log_flag("decompress_pdf", decompress_pdf);
     ConfigLogger::log_flag("decompress_swf", decompress_swf);
     ConfigLogger::log_flag("decompress_zip", decompress_zip);
+    ConfigLogger::log_flag("decompress_vba", decompress_vba);
     ConfigLogger::log_value("decompress_buffer_size", decompress_buffer_size);
 }
 
index 189cc31347795bbc5a224050faf6bec3b1ec983f..4ab94eecbae81a8888015a4db4aff0a1efc87615 100644 (file)
@@ -63,6 +63,9 @@ public:
     void set_decompress_zip(bool);
     bool is_decompress_zip() const;
 
+    void set_decompress_vba(bool);
+    bool is_decompress_vba() const;
+
     void set_decompress_buffer_size(uint32_t);
     uint32_t get_decompress_buffer_size() const;
 
@@ -81,6 +84,7 @@ private:
     bool decompress_pdf = false;
     bool decompress_swf = false;
     bool decompress_zip = false;
+    bool decompress_vba = false;
     uint32_t decompress_buffer_size = DEFAULT_DECOMP;
     int64_t file_depth = MIN_DEPTH;
     bool decode_enabled = true;
index 6efac62482174fd65c5e16fb645962646f95a7f0..8fef717c56e785181a411f92664a8a92480d4d27 100644 (file)
@@ -24,6 +24,7 @@
 
 #include "file_mime_decode.h"
 
+#include "decompress/file_olefile.h"
 #include "utils/util_cstring.h"
 
 #include "decode_b64.h"
@@ -34,6 +35,8 @@
 
 using namespace snort;
 
+const BufferData BufferData::buffer_null;
+
 void MimeDecode::init()
 { MimeDecodeContextData::init(); }
 
@@ -152,6 +155,8 @@ DecodeResult MimeDecode::decompress_data(const uint8_t* buf_in, uint32_t size_in
     if ( (fd_state == nullptr) || (size_in == 0) )
         return result;
 
+    clear_decomp_vba_data();
+
     if ( fd_state->State == STATE_COMPLETE )
         return result;
 
@@ -175,12 +180,58 @@ DecodeResult MimeDecode::decompress_data(const uint8_t* buf_in, uint32_t size_in
     default:
         buf_out = decompress_buf;
         size_out = fd_state->Next_Out - decompress_buf;
+        get_ole_data();
         break;
     }
 
     return result;
 }
 
+void MimeDecode::get_ole_data()
+{
+    uint8_t* ole_data_ptr;
+    uint32_t ole_len;
+
+    fd_state->get_ole_data(ole_data_ptr, ole_len);
+
+    if (ole_data_ptr)
+    {
+        ole_data.set(ole_len, ole_data_ptr, false);
+
+        //Reset the ole data ptr once it is stored in msg body
+        fd_state->ole_data_reset();
+    }
+}
+
+const BufferData& MimeDecode::get_decomp_vba_data()
+{
+    if (decompressed_vba_data.length() > 0)
+        return decompressed_vba_data;
+
+    if (ole_data.length() <= 0)
+        return BufferData::buffer_null;
+
+    uint8_t* buf = nullptr;
+    uint32_t buf_len = 0;
+    
+    VBA_DEBUG(vba_data_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, CURRENT_PACKET,
+               "Found OLE file. Sending %d bytes for the processing.\n",
+                ole_data.length());
+
+    oleprocess(ole_data.data_ptr(), ole_data.length(), buf, buf_len);
+
+    if (buf && buf_len)
+        decompressed_vba_data.set(buf_len, buf, true);
+
+    return decompressed_vba_data;
+}
+
+void MimeDecode::clear_decomp_vba_data()
+{
+    ole_data.reset();
+    decompressed_vba_data.reset();
+}
+
 void MimeDecode::file_decomp_reset()
 {
     if ( fd_state == nullptr )
@@ -200,6 +251,7 @@ void MimeDecode::file_decomp_init()
     bool decompress_pdf = config->is_decompress_pdf();
     bool decompress_swf = config->is_decompress_swf();
     bool decompress_zip = config->is_decompress_zip();
+    bool decompress_vba = config->is_decompress_vba();
 
     if ( !decompress_pdf && !decompress_swf && !decompress_zip )
         return;
@@ -208,7 +260,8 @@ void MimeDecode::file_decomp_init()
     fd_state->Modes =
         (decompress_pdf ? FILE_PDF_DEFL_BIT : 0) |
         (decompress_swf ? (FILE_SWF_ZLIB_BIT | FILE_SWF_LZMA_BIT) : 0) |
-        (decompress_zip ? FILE_ZIP_DEFL_BIT : 0);
+        (decompress_zip ? FILE_ZIP_DEFL_BIT : 0) |
+        (decompress_vba ? FILE_VBA_EXTR_BIT : 0);
     fd_state->Alert_Callback = nullptr;
     fd_state->Alert_Context = nullptr;
     fd_state->Compr_Depth = 0;
index 3cc177c286ad3da2c694388df276595ee8455ab1..df0218e68259a21479f858eeb3352c7759bbdd07 100644 (file)
@@ -24,6 +24,7 @@
 
 #include "decompress/file_decomp.h"
 #include "framework/counts.h"
+#include "helpers/buffer_data.h"
 #include "main/snort_types.h"
 #include "mime/decode_base.h"
 #include "mime/file_mime_config.h"
@@ -81,14 +82,19 @@ public:
 
     DecodeResult decompress_data(const uint8_t* buf_in, uint32_t size_in,
                                  const uint8_t*& buf_out, uint32_t& size_out);
+    const BufferData& get_decomp_vba_data();
+    void clear_decomp_vba_data();
 
     static void init();
 
 private:
+    void get_ole_data();
     DecodeType decode_type = DECODE_NONE;
     snort::DecodeConfig* config;
     DataDecode* decoder = nullptr;
     fd_session_t* fd_state = nullptr;
+    BufferData ole_data;
+    BufferData decompressed_vba_data;
 };
 
 } // namespace snort
index 5db1b712058f8109d6a5b6103d1fa1fff68288ab..e9d24336f7ae08282c0d9426df3577f0b1ef43fd 100644 (file)
@@ -711,6 +711,14 @@ void MimeSession::set_mime_stats(MimeStats* stats)
     mime_stats = stats;
 }
 
+const BufferData& MimeSession::get_vba_inspect_buf()
+{
+    if (!decode_state)
+        return BufferData::buffer_null;
+
+    return decode_state->get_decomp_vba_data();
+}
+
 MailLogState* MimeSession::get_log_state()
 {
     return log_state;
index aecc57d4f256d7f567d38135e35aa315b5f40abb..c3cb527f73e064a61496c997529bf160f65de209 100644 (file)
@@ -73,6 +73,8 @@ public:
     MailLogState* get_log_state();
     void set_mime_stats(MimeStats*);
 
+    const BufferData& get_vba_inspect_buf();
+
 protected:
     MimeDecode* decode_state = nullptr;
 
index 35c6029fb1630ea31715f9dade1b72e519d6475c..c20471523e74b8ee991732606d26ad305e13f7a7 100644 (file)
@@ -724,6 +724,10 @@ public:
     bool can_start_tls() const override
     { return true; }
 
+    bool get_buf(InspectionBuffer::Type, Packet*, InspectionBuffer&) override;
+    bool get_fp_buf(snort::InspectionBuffer::Type ibt, snort::Packet* p,
+        snort::InspectionBuffer& b) override;
+
 private:
     IMAP_PROTO_CONF* config;
 };
@@ -769,6 +773,41 @@ void Imap::eval(Packet* p)
     snort_imap(config, p);
 }
 
+bool Imap::get_buf(InspectionBuffer::Type ibt, Packet* p, InspectionBuffer& b)
+{
+    switch (ibt)
+    {
+        case InspectionBuffer::IBT_VBA:
+        {
+            IMAPData* imap_ssn = get_session_data(p->flow);
+
+            if (!imap_ssn)
+                return false;
+
+            const BufferData& vba_buf = imap_ssn->mime_ssn->get_vba_inspect_buf();
+
+            if (vba_buf.data_ptr() && vba_buf.length())
+            {
+                b.data = vba_buf.data_ptr();
+                b.len = vba_buf.length();
+                return true;
+            }
+            else
+                return false;
+        }
+
+        default:
+            break;
+    }
+    return false;
+
+}
+bool Imap::get_fp_buf(InspectionBuffer::Type ibt, Packet* p, InspectionBuffer& b)
+{
+    // Fast pattern buffers only supplied at specific times
+    return get_buf(ibt, p, b);
+}
+
 //-------------------------------------------------------------------------
 // api stuff
 //-------------------------------------------------------------------------
index 0e889aa72dac40fb45e412417e044618be3ead61..4025e31621696e65b051c3afaf205eb67c30e84c 100644 (file)
@@ -48,6 +48,9 @@ static const Parameter s_params[] =
     { "decompress_zip", Parameter::PT_BOOL, nullptr, "false",
       "decompress zip files in MIME attachments" },
 
+    { "decompress_vba", Parameter::PT_BOOL, nullptr, "false",
+      "decompress MS Office Visual Basic for Applications macro files in MIME attachments" },
+
     { "qp_decode_depth", Parameter::PT_INT, "-1:65535", "-1",
       "quoted Printable decoding depth (-1 no limit)" },
 
@@ -116,6 +119,9 @@ bool ImapModule::set(const char*, Value& v, SnortConfig*)
     else if ( v.is("decompress_zip") )
         config->decode_conf.set_decompress_zip(v.get_bool());
 
+    else if ( v.is("decompress_vba") )
+        config->decode_conf.set_decompress_vba(v.get_bool());
+
     else if ( v.is("qp_decode_depth") )
         config->decode_conf.set_qp_depth(mime_value);
 
index e3e145cba298d0abcebe2b2fbd82d70e7839e72e..152c0438e1a888ef8a41ea9c9878ed5f0bbbd08f 100644 (file)
@@ -663,6 +663,10 @@ public:
     bool can_start_tls() const override
     { return true; }
 
+    bool get_buf(InspectionBuffer::Type, Packet*, InspectionBuffer&) override;
+    bool get_fp_buf(snort::InspectionBuffer::Type ibt, snort::Packet* p,
+        snort::InspectionBuffer& b) override;
+
 private:
     POP_PROTO_CONF* config;
 };
@@ -708,6 +712,41 @@ void Pop::eval(Packet* p)
     snort_pop(config, p);
 }
 
+bool Pop::get_buf(InspectionBuffer::Type ibt, Packet* p, InspectionBuffer& b)
+{
+    // Fast pattern buffers only supplied at specific times
+    switch (ibt)
+    {
+        case InspectionBuffer::IBT_VBA:
+        {
+            POPData* pop_ssn = get_session_data(p->flow);
+
+            if (!pop_ssn)
+                return false;
+
+            const BufferData& vba_buf = pop_ssn->mime_ssn->get_vba_inspect_buf();
+            
+            if (vba_buf.data_ptr() && vba_buf.length())
+            {
+                b.data = vba_buf.data_ptr();
+                b.len = vba_buf.length();
+                return true;
+            }
+            else
+                return false;
+        }
+
+        default:
+            break;
+    }
+    return false;
+}
+
+bool Pop::get_fp_buf(InspectionBuffer::Type ibt, Packet* p, InspectionBuffer& b)
+{
+    return get_buf(ibt, p, b);
+}
+
 //-------------------------------------------------------------------------
 // api stuff
 //-------------------------------------------------------------------------
index 336984a89cbcdbc6a961a7cd5fbc87fd518f48ef..494b1d22aa463a5aaaf49382d2e3fa7e1c5b1b28 100644 (file)
@@ -48,6 +48,9 @@ static const Parameter s_params[] =
     { "decompress_zip", Parameter::PT_BOOL, nullptr, "false",
       "decompress zip files in MIME attachments" },
 
+    { "decompress_vba", Parameter::PT_BOOL, nullptr, "false",
+      "decompress MS Office Visual Basic for Applications macro files in MIME attachments" },
+
     { "qp_decode_depth", Parameter::PT_INT, "-1:65535", "-1",
       "Quoted Printable decoding depth (-1 no limit)" },
 
@@ -115,6 +118,9 @@ bool PopModule::set(const char*, Value& v, SnortConfig*)
     else if ( v.is("decompress_zip") )
         config->decode_conf.set_decompress_zip(v.get_bool());
 
+    else if ( v.is("decompress_vba") )
+        config->decode_conf.set_decompress_vba(v.get_bool());
+
     else if ( v.is("qp_decode_depth") )
         config->decode_conf.set_qp_depth(mime_value);
 
index 10a07a65595495be4e93460cdac6b2cc7ccaf5d8..ce1a8867f3cf0363be72d66adab478ff8e57dd8f 100644 (file)
@@ -1433,6 +1433,9 @@ public:
 
     void ProcessSmtpCmdsList(const SmtpCmd*);
 
+    bool get_fp_buf(snort::InspectionBuffer::Type ibt, snort::Packet* p,
+        snort::InspectionBuffer& b) override;
+
 private:
     SmtpProtoConf* config;
 };
@@ -1485,15 +1488,38 @@ void Smtp::eval(Packet* p)
     snort_smtp(config, p);
 }
 
-bool Smtp::get_buf(
-    InspectionBuffer::Type ibt, Packet* p, InspectionBuffer& b)
+bool Smtp::get_buf(InspectionBuffer::Type ibt, Packet* p, InspectionBuffer& b)
 {
-    if ( ibt != InspectionBuffer::IBT_ALT )
-        return false;
+    // Fast pattern buffers only supplied at specific times
+    switch (ibt)
+    {
+        case InspectionBuffer::IBT_ALT:
+            b.data = SMTP_GetAltBuffer(p, b.len);
+            return (b.data != nullptr);
+
+        case InspectionBuffer::IBT_VBA:
+        {
+            SMTPData* smtp_ssn = get_session_data(p->flow);
 
-    b.data = SMTP_GetAltBuffer(p, b.len);
+            if (!smtp_ssn)
+                return false;
+
+            const BufferData& vba_buf = smtp_ssn->mime_ssn->get_vba_inspect_buf();
+
+            if (vba_buf.data_ptr() && vba_buf.length())
+            {
+                b.data = vba_buf.data_ptr();
+                b.len = vba_buf.length();
+                return true;
+            }
+            else
+                return false;
+        }
+        default:
+            break;
+    }
+    return false;
 
-    return (b.data != nullptr);
 }
 
 void Smtp::clear(Packet* p)
@@ -1534,6 +1560,11 @@ void Smtp::ProcessSmtpCmdsList(const SmtpCmd* sc)
         config->cmd_config[id].max_line_len = sc->number;
 }
 
+bool Smtp::get_fp_buf(InspectionBuffer::Type ibt, Packet* p, InspectionBuffer& b)
+{
+    return get_buf(ibt, p, b);
+}
+
 //-------------------------------------------------------------------------
 // api stuff
 //-------------------------------------------------------------------------
index 49e572af5b5660ecd1b57681ebd1a1ac22c328ee..a764a815bd965a4a86f93ed020d43eff9fe39c07 100644 (file)
@@ -93,6 +93,9 @@ static const Parameter s_params[] =
     { "decompress_zip", Parameter::PT_BOOL, nullptr, "false",
       "decompress zip files in MIME attachments" },
 
+    { "decompress_vba", Parameter::PT_BOOL, nullptr, "false",
+      "decompress MS Office Visual Basic for Applications macro files in MIME attachments" },
+
     { "email_hdrs_log_depth", Parameter::PT_INT, "0:20480", "1464",
       "depth for logging email headers" },
 
@@ -268,6 +271,9 @@ bool SmtpModule::set(const char*, Value& v, SnortConfig*)
     else if ( v.is("decompress_zip") )
         config->decode_conf.set_decompress_zip(v.get_bool());
 
+    else if ( v.is("decompress_vba") )
+        config->decode_conf.set_decompress_vba(v.get_bool());
+
     else if ( v.is("email_hdrs_log_depth") )
         config->log_config.email_hdrs_log_depth = v.get_uint16();