FileProperty* node;
char* file_name;
+ VBA_DEBUG(vba_data_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, CURRENT_PACKET,
+ "Parsing the Directory list.\n");
+
current_sector = header->get_first_dir();
sector_size = header->get_sector_size();
else
current_sector = INVALID_SECTOR;
}
+ VBA_DEBUG(vba_data_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, CURRENT_PACKET,
+ "End of Directory list parsing.\n");
}
FileProperty* DirectoryList :: get_file_node(char* name)
if (fat_list and sec_id > INVALID_SECTOR and sec_id < fat_list_len)
return fat_list[sec_id];
else
+ {
+ VBA_DEBUG(vba_data_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, CURRENT_PACKET,
+ "The next sector ID of fat sector %d is not available in fat list.\n", sec_id);
return INVALID_SECTOR;
+ }
}
// Every index of mini_fat_list array is the minifat sector ID and the value present
if (mini_fat_list and sec_id > INVALID_SECTOR and sec_id < mini_fat_list_len)
return mini_fat_list[sec_id];
else
+ {
+ VBA_DEBUG(vba_data_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, CURRENT_PACKET,
+ "The next sector ID of mini fat sector %d is not available in minifat list.\n",
+ sec_id);
return INVALID_SECTOR;
+ }
}
// The offset of a sector is header_size + (sector_number * size_of_each_sector).
{
memcpy(temp_data, (file_buf + byte_offset), (buf_len - byte_offset));
data_len += buf_len - byte_offset;
+ VBA_DEBUG(vba_data_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL,
+ CURRENT_PACKET, "Returning with partial data of %d bytes for the "
+ "file %s.\n", data_len, file);
return;
}
if ((data_len + sector_size) < stream_size)
{
memcpy(temp_data, (file_buf + byte_offset), (buf_len - byte_offset));
data_len += buf_len - byte_offset;
+ VBA_DEBUG(vba_data_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL,
+ CURRENT_PACKET, "Returning with partial data of %d bytes for "
+ "the file %s.\n", data_len, file);
return;
}
if ((data_len + mini_sector_size) < stream_size)
int32_t max_secchain_cnt = header->get_sector_size()/4;
int32_t count = 0;
+ VBA_DEBUG(vba_data_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, CURRENT_PACKET,
+ "Reading the FAT list array.\n");
fat_list_len = ( header->get_fat_sector_count() * header->get_sector_size() ) / 4;
if (fat_list_len < 1)
+ {
+ VBA_DEBUG(vba_data_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, CURRENT_PACKET,
+ "FAT list array is empty.\n");
return;
+ }
fat_list = new int32_t[fat_list_len];
else
return;
}
+ VBA_DEBUG(vba_data_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, CURRENT_PACKET,
+ "FAT list array is populated.\n");
}
// The function populate_mini_fat_list() reads the contents of mini FAT array sectors to
int32_t max_secchain_cnt = header->get_sector_size()/4;
int32_t count = 0;
+ VBA_DEBUG(vba_data_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, CURRENT_PACKET,
+ "Reading the Mini-FAT list array.\n");
mini_fat_list_len = ( header->get_minifat_count() * header->get_sector_size() ) / 4;
if (mini_fat_list_len < 1)
+ {
+ VBA_DEBUG(vba_data_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, CURRENT_PACKET,
+ "Mini-FAT list array is empty.\n");
return;
+ }
mini_fat_list = new int32_t[mini_fat_list_len];
else
current_sector = INVALID_SECTOR;
}
+ VBA_DEBUG(vba_data_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, CURRENT_PACKET,
+ "Mini-FAT list array is populated..\n");
}
// API to parse the OLE File Header.
// sector (with SecID 0) always starts at file offset 512.
bool OleFile :: parse_ole_header()
{
+ VBA_DEBUG(vba_data_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, CURRENT_PACKET,
+ "Staring the OLE header parsing.\n");
header = new OleHeader;
if (!header->set_byte_order(file_buf + HEADER_BYTE_ORDER_OFFSET))
+ {
+ VBA_DEBUG(vba_data_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, CURRENT_PACKET,
+ "Invalid byte order in the OLE header. Returning.\n");
return false;
+ }
// Header Signature (8 bytes) is Identification signature of the OLE file,
// and must be of the value 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1.
if (!header->match_ole_sig(file_buf))
+ {
+ VBA_DEBUG(vba_data_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, CURRENT_PACKET,
+ "Invalid file signature of OLE file. Returning.\n");
return false;
+ }
// Minor Version field should be set to 0x003E.
header->set_minor_version(file_buf + HEADER_MINOR_VER_OFFSET);
header->set_dir_sector_count(file_buf + HEADER_DIR_SECTR_CNT_OFFSET);
- // DIFAT array of 32-bit integer fields contains the first 109 FAT sector locations of the compound file.
+ // DIFAT array of 32-bit integer fields contains the first 109 FAT sector locations of the
+ // compound file.
header->set_difat_array(file_buf + HEADER_DIFAT_ARRY_OFFSET);
+ VBA_DEBUG(vba_data_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, CURRENT_PACKET,
+ "Parsing of OLE header is done.\n");
+
return true;
}
searcher = snort::LiteralSearch::instantiate(search_handle,
(const uint8_t*)"ATTRIBUT", 8, true);
if (searcher == nullptr)
+ {
+ VBA_DEBUG(vba_data_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, CURRENT_PACKET,
+ "Error in the searcher.\n");
return -1;
+ }
int32_t offset = searcher->search(search_handle, data, data_len);
delete searcher;
return;
if (*data!= SIG_COMP_CONTAINER)
+ {
+ VBA_DEBUG(vba_data_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, CURRENT_PACKET,
+ "Invalid Compressed flag.\n");
return;
+ }
header = LETOHS_UNALIGNED(data + 1);
if (((header >> 12) & 0x07) != 0b011)
{
+ VBA_DEBUG(vba_data_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, CURRENT_PACKET,
+ "Invalid Chunk signature.\n");
}
data += 3;
int32_t offset = get_file_offset(data, data_len);
if (offset <= 0)
{
+ VBA_DEBUG(vba_data_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL,
+ CURRENT_PACKET,
+ "Stream %s of size %ld does not have VBA code within first detected"
+ " %d bytes\n", node->get_name(), node->get_stream_size(), data_len);
delete[] data1;
continue;
}
data += offset - 4;
data_len = data_len - offset + 4;
+ VBA_DEBUG(vba_data_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL,
+ CURRENT_PACKET, "Stream %s of size %ld has vba code starting at "
+ "offset %d bytes. First %d bytes will be processed\n",
+ node->get_name(), node->get_stream_size(), (offset - 4), data_len);
+
decompression(data, &data_len, vba_buf, &vba_buffer_offset);
delete[] data1;
if ( vba_buffer_offset >= MAX_VBA_BUFFER_LEN)
// an ole file and creating a mapping between the storage/stream name and the
// fileproperty object.Afterwards, based on the directory the data is fetched and
// extracted & RLE decompression is done.
-void oleprocess(const uint8_t* const ole_file, const uint32_t ole_length, uint8_t*& vba_buf, uint32_t& vba_buf_len)
+void oleprocess(const uint8_t* const ole_file, const uint32_t ole_length, uint8_t*& vba_buf,
+ uint32_t& vba_buf_len)
{
if (ole_length < OLE_HEADER_LEN)
+ {
+ VBA_DEBUG(vba_data_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, CURRENT_PACKET,
+ "OLE file data is too short for the inspection. Returning\n");
return;
+ }
std::unique_ptr<OleFile> olefile (new OleFile(ole_file,ole_length));
--- /dev/null
+
+//--------------------------------------------------------------------------
+// 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.
+//--------------------------------------------------------------------------
+// ips_vba_data.cc author Amarnath Nayak <amarnaya@cisco.com>
+
+#include "ips_vba_data.h"
+
+#include "framework/module.h"
+
+using namespace snort;
+
+THREAD_LOCAL const Trace* vba_data_trace = nullptr;
+
+CursorActionType VbaDataOption::get_cursor_type() const
+{ return CAT_SET_VBA; }
+
+IpsOption::EvalStatus VbaDataOption::eval(Cursor& c, Packet* p)
+{
+ RuleProfile profile(vbaDataPerfStats);
+
+ InspectionBuffer buf;
+ if (!p->flow->gadget->get_fp_buf(buf.IBT_VBA, p, buf))
+ return NO_MATCH;
+
+ c.set(s_name, buf.data, buf.len);
+ return MATCH;
+}
+
+
+ProfileStats* VbaDataModule::get_profile() const
+{ return &vbaDataPerfStats; }
+
+void VbaDataModule::set_trace(const Trace* trace) const
+{ vba_data_trace = trace; }
+
+
+const TraceOption* VbaDataModule::VbaDataModule::get_trace_options() const
+{
+ #ifndef DEBUG_MSGS
+ return nullptr;
+ #else
+ static const TraceOption vba_data_trace_options(nullptr, 0, nullptr);
+ return &vba_data_trace_options;
+ #endif
+}
+
+//-------------------------------------------------------------------------
+// api methods
+//-------------------------------------------------------------------------
+
+
+static Module* mod_ctor()
+{
+ return new VbaDataModule;
+}
+
+static void mod_dtor(Module* m)
+{
+ delete m;
+}
+
+static IpsOption* vba_data_ctor(Module*, OptTreeNode*)
+{
+ return new VbaDataOption;
+}
+
+static void vba_data_dtor(IpsOption* p)
+{
+ delete p;
+}
+
+static const IpsApi vba_data_api =
+{
+ {
+ PT_IPS_OPTION,
+ sizeof(IpsApi),
+ IPSAPI_VERSION,
+ 0,
+ API_RESERVED,
+ API_OPTIONS,
+ s_name,
+ s_help,
+ mod_ctor,
+ mod_dtor
+ },
+ OPT_TYPE_DETECTION,
+ 0, PROTO_BIT__TCP,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ vba_data_ctor,
+ vba_data_dtor,
+ nullptr
+};
+
+#ifdef BUILDING_SO
+SO_PUBLIC const BaseApi* snort_plugins[] =
+#else
+const BaseApi* ips_vba_data[] =
+#endif
+{
+ &vba_data_api.base,
+ nullptr
+};
+
--- /dev/null
+//--------------------------------------------------------------------------
+// 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.
+//--------------------------------------------------------------------------
+// ips_vba_data.h author Amarnath Nayak <amarnaya@cisco.com>
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "detection/detection_engine.h"
+#include "framework/cursor.h"
+#include "framework/ips_option.h"
+#include "framework/module.h"
+#include "profiler/profiler.h"
+#include "trace/trace.h"
+
+#define s_name "vba_data"
+#define s_help \
+ "rule option to set the detection cursor to the MS Office Visual Basic for Applications macros buffer"
+
+static THREAD_LOCAL snort::ProfileStats vbaDataPerfStats;
+
+extern THREAD_LOCAL const snort::Trace* vba_data_trace;
+
+class VbaDataOption : public snort::IpsOption
+{
+public:
+ VbaDataOption() : IpsOption(s_name, RULE_OPTION_TYPE_BUFFER_SET) { }
+
+ snort::CursorActionType get_cursor_type() const override;
+
+ snort::IpsOption::EvalStatus eval(Cursor&, snort::Packet*) override;
+};
+
+class VbaDataModule : public snort::Module
+{
+public:
+ VbaDataModule() : Module(s_name, s_help) { }
+
+ snort::ProfileStats* get_profile() const override;
+
+ snort::Module::Usage get_usage() const override
+ {return DETECT;}
+
+ void set_trace(const snort::Trace* trace) const override;
+
+ const snort::TraceOption* get_trace_options() const override;
+};
+