From: Pranav Bhalerao (prbhaler) Date: Fri, 10 Dec 2021 09:56:02 +0000 (+0000) Subject: Pull request #3201: mime: Adding the support for vba macro data extraction of MS... X-Git-Tag: 3.1.19.0~12 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fe3ffc70adc14d45312553a74ec58eed05cc1423;p=thirdparty%2Fsnort3.git Pull request #3201: mime: Adding the support for vba macro data extraction of MS office files transferred over mime protocols Merge in SNORT/snort3 from ~AMARNAYA/snort3:mime_vba to master Squashed commit of the following: commit d185bb6c0c8921949acb7137fc7f0a30a837d4f4 Author: Amarnath Nayak 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 --- diff --git a/src/decompress/file_olefile.cc b/src/decompress/file_olefile.cc index be3c62188..28b3209c6 100644 --- a/src/decompress/file_olefile.cc +++ b/src/decompress/file_olefile.cc @@ -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); diff --git a/src/helpers/CMakeLists.txt b/src/helpers/CMakeLists.txt index 49e3f71c1..0743bbb70 100644 --- a/src/helpers/CMakeLists.txt +++ b/src/helpers/CMakeLists.txt @@ -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 index 000000000..1b0186cff --- /dev/null +++ b/src/helpers/buffer_data.cc @@ -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 +#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 index 000000000..d8636c55d --- /dev/null +++ b/src/helpers/buffer_data.h @@ -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 +#ifndef BUFFER_DATA_H +#define BUFFER_DATA_H + +#include + +#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 diff --git a/src/mime/file_mime_config.cc b/src/mime/file_mime_config.cc index 9036cf10a..0dface366 100644 --- a/src/mime/file_mime_config.cc +++ b/src/mime/file_mime_config.cc @@ -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); } diff --git a/src/mime/file_mime_config.h b/src/mime/file_mime_config.h index 189cc3134..4ab94eecb 100644 --- a/src/mime/file_mime_config.h +++ b/src/mime/file_mime_config.h @@ -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; diff --git a/src/mime/file_mime_decode.cc b/src/mime/file_mime_decode.cc index 6efac6248..8fef717c5 100644 --- a/src/mime/file_mime_decode.cc +++ b/src/mime/file_mime_decode.cc @@ -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; diff --git a/src/mime/file_mime_decode.h b/src/mime/file_mime_decode.h index 3cc177c28..df0218e68 100644 --- a/src/mime/file_mime_decode.h +++ b/src/mime/file_mime_decode.h @@ -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 diff --git a/src/mime/file_mime_process.cc b/src/mime/file_mime_process.cc index 5db1b7120..e9d24336f 100644 --- a/src/mime/file_mime_process.cc +++ b/src/mime/file_mime_process.cc @@ -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; diff --git a/src/mime/file_mime_process.h b/src/mime/file_mime_process.h index aecc57d4f..c3cb527f7 100644 --- a/src/mime/file_mime_process.h +++ b/src/mime/file_mime_process.h @@ -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; diff --git a/src/service_inspectors/imap/imap.cc b/src/service_inspectors/imap/imap.cc index 35c6029fb..c20471523 100644 --- a/src/service_inspectors/imap/imap.cc +++ b/src/service_inspectors/imap/imap.cc @@ -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 //------------------------------------------------------------------------- diff --git a/src/service_inspectors/imap/imap_module.cc b/src/service_inspectors/imap/imap_module.cc index 0e889aa72..4025e3162 100644 --- a/src/service_inspectors/imap/imap_module.cc +++ b/src/service_inspectors/imap/imap_module.cc @@ -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); diff --git a/src/service_inspectors/pop/pop.cc b/src/service_inspectors/pop/pop.cc index e3e145cba..152c0438e 100644 --- a/src/service_inspectors/pop/pop.cc +++ b/src/service_inspectors/pop/pop.cc @@ -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 //------------------------------------------------------------------------- diff --git a/src/service_inspectors/pop/pop_module.cc b/src/service_inspectors/pop/pop_module.cc index 336984a89..494b1d22a 100644 --- a/src/service_inspectors/pop/pop_module.cc +++ b/src/service_inspectors/pop/pop_module.cc @@ -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); diff --git a/src/service_inspectors/smtp/smtp.cc b/src/service_inspectors/smtp/smtp.cc index 10a07a655..ce1a8867f 100644 --- a/src/service_inspectors/smtp/smtp.cc +++ b/src/service_inspectors/smtp/smtp.cc @@ -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 //------------------------------------------------------------------------- diff --git a/src/service_inspectors/smtp/smtp_module.cc b/src/service_inspectors/smtp/smtp_module.cc index 49e572af5..a764a815b 100644 --- a/src/service_inspectors/smtp/smtp_module.cc +++ b/src/service_inspectors/smtp/smtp_module.cc @@ -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();