]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #1682 in SNORT/snort3 from ~BRASTULT/snort3:ber to master
authorRuss Combs (rucombs) <rucombs@cisco.com>
Fri, 2 Aug 2019 19:41:18 +0000 (15:41 -0400)
committerRuss Combs (rucombs) <rucombs@cisco.com>
Fri, 2 Aug 2019 19:41:18 +0000 (15:41 -0400)
Squashed commit of the following:

commit 946ac40b14e4d79b740f31ce7589134e6fe77a68
Author: Brandon Stultz <brastult@cisco.com>
Date:   Fri Jul 5 18:43:10 2019 -0400

    ips_options: add ber_data and ber_skip

src/ips_options/CMakeLists.txt
src/ips_options/ips_ber_data.cc [new file with mode: 0644]
src/ips_options/ips_ber_skip.cc [new file with mode: 0644]
src/ips_options/ips_options.cc
src/utils/CMakeLists.txt
src/utils/util_ber.cc [new file with mode: 0644]
src/utils/util_ber.h [new file with mode: 0644]

index 2ee6946be6bca8f8b208dc699f62860b1648c944..d6ff245e7cae85ea8596ff5680c09b2e291f9160 100644 (file)
@@ -7,6 +7,8 @@ SET( PLUGIN_LIST
     ips_ack.cc
     ips_asn1.cc
     ips_base64.cc
+    ips_ber_data.cc
+    ips_ber_skip.cc
     ips_bufferlen.cc
     ips_byte_extract.cc
     ips_byte_jump.cc
@@ -95,6 +97,8 @@ else (STATIC_IPS_OPTIONS)
     add_dynamic_module(ips_ack ips_options ips_ack.cc)
     add_dynamic_module(ips_asn1 ips_options ips_asn1.cc asn1_detect.cc asn1_detect.h asn1_util.h asn1_util.cc)
     add_dynamic_module(ips_base64 ips_options ips_base64.cc)
+    add_dynamic_module(ips_ber_data ips_options ips_ber_data.cc)
+    add_dynamic_module(ips_ber_skip ips_options ips_ber_skip.cc)
     add_dynamic_module(ips_bufferlen ips_options ips_bufferlen.cc)
     add_dynamic_module(ips_byte_test ips_options ips_byte_test.cc)
     add_dynamic_module(ips_byte_jump ips_options ips_byte_jump.cc)
diff --git a/src/ips_options/ips_ber_data.cc b/src/ips_options/ips_ber_data.cc
new file mode 100644 (file)
index 0000000..f483fef
--- /dev/null
@@ -0,0 +1,206 @@
+//--------------------------------------------------------------------------
+// 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.
+//--------------------------------------------------------------------------
+// ips_ber_data.cc author Brandon Stultz <brastult@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "framework/cursor.h"
+#include "framework/ips_option.h"
+#include "framework/module.h"
+#include "hash/hashfcn.h"
+#include "profiler/profiler.h"
+#include "utils/util_ber.h"
+
+using namespace snort;
+
+#define s_name "ber_data"
+
+static THREAD_LOCAL ProfileStats berDataPerfStats;
+
+class BerDataOption : public IpsOption
+{
+public:
+    BerDataOption(uint32_t t) : IpsOption(s_name)
+    { type = t; }
+
+    uint32_t hash() const override;
+    bool operator==(const IpsOption&) const override;
+
+    bool is_relative() override
+    { return true; }
+
+    EvalStatus eval(Cursor&, Packet*) override;
+
+private:
+    uint32_t type;
+};
+
+//-------------------------------------------------------------------------
+// class methods
+//-------------------------------------------------------------------------
+
+uint32_t BerDataOption::hash() const
+{
+    uint32_t a = type, b = 0, c = 0;
+
+    mix_str(a,b,c,s_name);
+    finalize(a,b,c);
+
+    return c;
+}
+
+bool BerDataOption::operator==(const IpsOption& ips) const
+{
+    const BerDataOption& rhs = (const BerDataOption&)ips;
+
+    if ( type != rhs.type )
+        return false;
+
+    return true;
+}
+
+IpsOption::EvalStatus BerDataOption::eval(Cursor& c, Packet*)
+{
+    RuleProfile profile(berDataPerfStats);
+
+    BerReader ber(c);
+    BerElement e;
+
+    if ( !ber.read(c.start(), e) )
+        return NO_MATCH;
+
+    if ( e.type != type )
+        return NO_MATCH;
+
+    if ( !c.add_pos(e.total_length - e.length) )
+        return NO_MATCH;
+
+    return MATCH;
+}
+
+//-------------------------------------------------------------------------
+// module
+//-------------------------------------------------------------------------
+
+static const Parameter s_params[] =
+{
+    { "~type", Parameter::PT_INT, "0:255", nullptr,
+      "move to the data for the specified BER element type" },
+
+    { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
+};
+
+#define s_help \
+    "rule option to move to the data for a specified BER element"
+
+class BerDataModule : public Module
+{
+public:
+    BerDataModule() : Module(s_name, s_help, s_params) { }
+
+    bool begin(const char*, int, SnortConfig*) override;
+    bool set(const char*, Value&, SnortConfig*) override;
+
+    ProfileStats* get_profile() const override
+    { return &berDataPerfStats; }
+
+    Usage get_usage() const override
+    { return DETECT; }
+
+public:
+    uint32_t type;
+};
+
+bool BerDataModule::begin(const char*, int, SnortConfig*)
+{
+    type = 0;
+    return true;
+}
+
+bool BerDataModule::set(const char*, Value& v, SnortConfig*)
+{
+    if ( v.is("~type") )
+        type = v.get_uint32();
+    else
+        return false;
+
+    return true;
+}
+
+//-------------------------------------------------------------------------
+// api methods
+//-------------------------------------------------------------------------
+
+static Module* mod_ctor()
+{
+    return new BerDataModule;
+}
+
+static void mod_dtor(Module* m)
+{
+    delete m;
+}
+
+static IpsOption* ber_data_ctor(Module* p, OptTreeNode*)
+{
+    BerDataModule* m = (BerDataModule*)p;
+    return new BerDataOption(m->type);
+}
+
+static void ber_data_dtor(IpsOption* p)
+{
+    delete p;
+}
+
+static const IpsApi ber_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, 0,
+    nullptr,
+    nullptr,
+    nullptr,
+    nullptr,
+    ber_data_ctor,
+    ber_data_dtor,
+    nullptr
+};
+
+#ifdef BUILDING_SO
+SO_PUBLIC const BaseApi* snort_plugins[] =
+#else
+const BaseApi* ips_ber_data[] =
+#endif
+{
+    &ber_data_api.base,
+    nullptr
+};
+
diff --git a/src/ips_options/ips_ber_skip.cc b/src/ips_options/ips_ber_skip.cc
new file mode 100644 (file)
index 0000000..b95e678
--- /dev/null
@@ -0,0 +1,223 @@
+//--------------------------------------------------------------------------
+// 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.
+//--------------------------------------------------------------------------
+// ips_ber_skip.cc author Brandon Stultz <brastult@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "framework/cursor.h"
+#include "framework/ips_option.h"
+#include "framework/module.h"
+#include "hash/hashfcn.h"
+#include "profiler/profiler.h"
+#include "utils/util_ber.h"
+
+using namespace snort;
+
+#define s_name "ber_skip"
+
+static THREAD_LOCAL ProfileStats berSkipPerfStats;
+
+class BerSkipOption : public IpsOption
+{
+public:
+    BerSkipOption(uint32_t t, bool o) : IpsOption(s_name)
+    { type = t; optional = o; }
+
+    uint32_t hash() const override;
+    bool operator==(const IpsOption&) const override;
+
+    bool is_relative() override
+    { return true; }
+
+    EvalStatus eval(Cursor&, Packet*) override;
+
+private:
+    uint32_t type;
+    bool optional;
+};
+
+//-------------------------------------------------------------------------
+// class methods
+//-------------------------------------------------------------------------
+
+uint32_t BerSkipOption::hash() const
+{
+    uint32_t a = type, b = optional, c = 0;
+
+    mix_str(a,b,c,s_name);
+    finalize(a,b,c);
+
+    return c;
+}
+
+bool BerSkipOption::operator==(const IpsOption& ips) const
+{
+    const BerSkipOption& rhs = (const BerSkipOption&)ips;
+
+    if ( type != rhs.type )
+        return false;
+
+    if ( optional != rhs.optional )
+        return false;
+
+    return true;
+}
+
+IpsOption::EvalStatus BerSkipOption::eval(Cursor& c, Packet*)
+{
+    RuleProfile profile(berSkipPerfStats);
+
+    BerReader ber(c);
+    BerElement e;
+
+    if ( !ber.read(c.start(), e) )
+        return NO_MATCH;
+
+    if ( e.type != type )
+    {
+        if ( optional )
+            return MATCH;
+        else
+            return NO_MATCH;
+    }
+
+    if ( !c.add_pos(e.total_length) )
+        return NO_MATCH;
+
+    return MATCH;
+}
+
+//-------------------------------------------------------------------------
+// module
+//-------------------------------------------------------------------------
+
+static const Parameter s_params[] =
+{
+    { "~type", Parameter::PT_INT, "0:255", nullptr,
+      "BER element type to skip" },
+
+    { "optional", Parameter::PT_IMPLIED, nullptr, nullptr,
+      "match even if the specified BER type is not found" },
+
+    { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
+};
+
+#define s_help "rule option to skip BER element"
+
+class BerSkipModule : public Module
+{
+public:
+    BerSkipModule() : Module(s_name, s_help, s_params) { }
+
+    bool begin(const char*, int, SnortConfig*) override;
+    bool set(const char*, Value&, SnortConfig*) override;
+
+    ProfileStats* get_profile() const override
+    { return &berSkipPerfStats; }
+
+    Usage get_usage() const override
+    { return DETECT; }
+
+public:
+    uint32_t type;
+    bool optional;
+};
+
+bool BerSkipModule::begin(const char*, int, SnortConfig*)
+{
+    type = 0;
+    optional = false;
+    return true;
+}
+
+bool BerSkipModule::set(const char*, Value& v, SnortConfig*)
+{
+    if ( v.is("~type") )
+        type = v.get_uint32();
+
+    else if ( v.is("optional") )
+        optional = true;
+
+    else
+        return false;
+
+    return true;
+}
+
+//-------------------------------------------------------------------------
+// api methods
+//-------------------------------------------------------------------------
+
+static Module* mod_ctor()
+{
+    return new BerSkipModule;
+}
+
+static void mod_dtor(Module* m)
+{
+    delete m;
+}
+
+static IpsOption* ber_skip_ctor(Module* p, OptTreeNode*)
+{
+    BerSkipModule* m = (BerSkipModule*)p;
+    return new BerSkipOption(m->type, m->optional);
+}
+
+static void ber_skip_dtor(IpsOption* p)
+{
+    delete p;
+}
+
+static const IpsApi ber_skip_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, 0,
+    nullptr,
+    nullptr,
+    nullptr,
+    nullptr,
+    ber_skip_ctor,
+    ber_skip_dtor,
+    nullptr
+};
+
+#ifdef BUILDING_SO
+SO_PUBLIC const BaseApi* snort_plugins[] =
+#else
+const BaseApi* ips_ber_skip[] =
+#endif
+{
+    &ber_skip_api.base,
+    nullptr
+};
+
index 1bfd8b9464601bd19d6c39a61e8435c4ae0e63bd..42649cb6d67bbc02b39f10e8ec603bed808f99c0 100644 (file)
@@ -48,6 +48,8 @@ extern const BaseApi* ips_so;
 extern const BaseApi* ips_ack[];
 extern const BaseApi* ips_asn1[];
 extern const BaseApi* ips_base64[];
+extern const BaseApi* ips_ber_data[];
+extern const BaseApi* ips_ber_skip[];
 extern const BaseApi* ips_byte_extract[];
 extern const BaseApi* ips_byte_jump[];
 extern const BaseApi* ips_byte_math[];
@@ -118,6 +120,8 @@ void load_ips_options()
     PluginManager::load_plugins(ips_ack);
     PluginManager::load_plugins(ips_asn1);
     PluginManager::load_plugins(ips_base64);
+    PluginManager::load_plugins(ips_ber_data);
+    PluginManager::load_plugins(ips_ber_skip);
     PluginManager::load_plugins(ips_byte_extract);
     PluginManager::load_plugins(ips_byte_jump);
     PluginManager::load_plugins(ips_byte_math);
index ebe7046f6b7497bd48b892ac717141b51facc7dc..b96f459f909414b86fb91288cf15e4bc253e3617 100644 (file)
@@ -13,6 +13,7 @@ set( UTIL_INCLUDES
     sfmemcap.h
     stats.h
     util.h
+    util_ber.h
     util_cstring.h
     util_jsnorm.h
     util_unfold.h
@@ -38,6 +39,7 @@ add_library ( utils OBJECT
     snort_bounds.h
     stats.cc
     util.cc
+    util_ber.cc
     util_cstring.cc
     util_jsnorm.cc 
     util_net.cc 
diff --git a/src/utils/util_ber.cc b/src/utils/util_ber.cc
new file mode 100644 (file)
index 0000000..0c339e4
--- /dev/null
@@ -0,0 +1,232 @@
+//--------------------------------------------------------------------------
+// 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.
+//--------------------------------------------------------------------------
+// util_ber.cc author Brandon Stultz <brastult@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "util_ber.h"
+
+namespace snort
+{
+
+bool BerReader::read_int(uint32_t size, uint32_t& intval)
+{
+    unsigned bytes = 0;
+
+    intval = 0;
+
+    // check if we can read int data
+    if ( cursor + size > end )
+        return false;
+
+    for ( unsigned i = 0; i < size; i++ )
+    {
+        uint8_t b = *cursor++;
+
+        // handle null padding
+        if ( bytes == 0 && b == 0 )
+            continue;
+
+        intval <<= 8;
+        intval |= b;
+        bytes++;
+
+        // check if int fits into uint32_t
+        if ( bytes > 4 )
+            return false;
+    }
+
+    return true;
+}
+
+bool BerReader::read_type(uint32_t& type)
+{
+    unsigned bytes = 0;
+    uint8_t b;
+
+    type = 0;
+
+    if ( cursor + 1 > end )
+        return false;
+
+    b = *cursor++;
+
+    if ( (b & 0x1F) != 0x1F )
+    {
+        // short-form type
+        type = b;
+        return true;
+    }
+
+    // long-form type
+    while ( true )
+    {
+        if ( cursor + 1 > end )
+            return false;
+
+        b = *cursor++;
+
+        // handle null padding
+        if ( bytes == 0 && b == 0x80 )
+            continue;
+
+        type <<= 7;
+        type |= b & 0x7F;
+        bytes++;
+
+        // check if type fits into uint32_t
+        if ( bytes > 4 )
+            return false;
+
+        // check continuation bit
+        if ( (b & 0x80) == 0 )
+            break;
+    }
+
+    return true;
+}
+
+bool BerReader::read_length(uint32_t& length)
+{
+    unsigned size;
+    uint8_t b;
+
+    length = 0;
+
+    if ( cursor + 1 > end )
+        return false;
+
+    b = *cursor++;
+
+    if ( (b & 0x80) == 0 )
+    {
+        // short-form length
+        length = b;
+        return true;
+    }
+
+    // long-form length
+    size = b & 0x7F;
+
+    if ( size == 0 )
+        return false;
+
+    if ( !read_int(size, length) )
+        return false;
+
+    return true;
+}
+
+bool BerReader::read(const uint8_t* c, BerElement& e)
+{
+    const uint8_t* start = c;
+
+    if ( c < beg || c > end )
+        return false;
+
+    cursor = c;
+
+    if ( !read_type(e.type) )
+        return false;
+
+    if ( !read_length(e.length) )
+        return false;
+
+    // set BER data pointer
+    e.data = cursor;
+
+    // jump BER data
+    cursor += e.length;
+
+    // cursor must be > start
+    if ( cursor <= start )
+        return false;
+
+    // calculate total BER length
+    e.total_length = cursor - start;
+
+    return true;
+}
+
+bool BerReader::convert(BerElement& e, uint32_t& intval)
+{
+    if ( e.type != BerType::INTEGER )
+        return false;
+
+    if ( e.data < beg || e.data > end )
+        return false;
+
+    // set cursor to int data
+    cursor = e.data;
+
+    if ( !read_int(e.length, intval) )
+        return false;
+
+    return true;
+}
+
+bool BerReader::extract(const uint8_t*& c, uint32_t& intval)
+{
+    BerElement e;
+
+    if ( !read(c, e) )
+        return false;
+
+    // save end of element position
+    c = cursor;
+
+    if ( !convert(e, intval) )
+        return false;
+
+    return true;
+}
+
+bool BerReader::skip(const uint8_t*& c, uint32_t type)
+{
+    BerElement e;
+
+    if ( !read(c, e) )
+        return false;
+
+    if ( e.type != type )
+        return false;
+
+    c = cursor;
+
+    return true;
+}
+
+bool BerReader::data(const uint8_t*& c, uint32_t type)
+{
+    BerElement e;
+
+    if ( !read(c, e) )
+        return false;
+
+    if ( e.type != type )
+        return false;
+
+    c = e.data;
+
+    return true;
+}
+
+}
+
diff --git a/src/utils/util_ber.h b/src/utils/util_ber.h
new file mode 100644 (file)
index 0000000..6b77c6b
--- /dev/null
@@ -0,0 +1,75 @@
+//--------------------------------------------------------------------------
+// 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.
+//--------------------------------------------------------------------------
+// util_ber.h author Brandon Stultz <brastult@cisco.com>
+
+#ifndef UTIL_BER_H
+#define UTIL_BER_H
+
+#include "main/snort_types.h"
+#include "framework/cursor.h"
+
+namespace snort
+{
+
+enum BerType
+{
+    BOOLEAN = 1,
+    INTEGER,
+    BIT_STRING,
+    STRING,
+};
+
+struct BerElement
+{
+    uint32_t type;
+    uint32_t length;
+    uint32_t total_length;
+    const uint8_t* data;
+};
+
+class SO_PUBLIC BerReader
+{
+public:
+    BerReader(Cursor& c)
+    {
+        beg = c.buffer();
+        end = c.endo();
+    }
+
+    bool read(const uint8_t* c, BerElement& e);
+
+    bool convert(BerElement& e, uint32_t& intval);
+    bool extract(const uint8_t*& c, uint32_t& intval);
+
+    bool skip(const uint8_t*& c, uint32_t type);
+    bool data(const uint8_t*& c, uint32_t type);
+
+private:
+    bool read_int(uint32_t size, uint32_t& intval);
+
+    bool read_type(uint32_t& type);
+    bool read_length(uint32_t& length);
+
+    const uint8_t* beg;
+    const uint8_t* cursor;
+    const uint8_t* end;
+};
+
+}
+#endif
+