NUMA: OFF")
endif ()
+if (HAVE_LIBML)
+ message("\
+ LibML: ON")
+else ()
+ message("\
+ LibML: OFF")
+endif ()
+
message("-------------------------------------------------------\n")
--- /dev/null
+find_library(ML_LIBRARIES NAMES ml_static HINTS ${ML_LIBRARIES_DIR_HINT})
+find_path(ML_INCLUDE_DIRS libml.h HINTS ${ML_INCLUDE_DIR_HINT})
+
+include(FindPackageHandleStandardArgs)
+
+find_package_handle_standard_args(ML
+ DEFAULT_MSG
+ ML_LIBRARIES
+ ML_INCLUDE_DIRS
+)
+
+if (ML_FOUND)
+ set(HAVE_LIBML TRUE)
+endif()
find_package(UUID QUIET)
find_package(Libunwind)
find_package(NUMA QUIET)
+find_package(ML QUIET)
/* numa available */
#cmakedefine HAVE_NUMA 1
+/* libml available */
+#cmakedefine HAVE_LIBML 1
+
/* Availability of specific library functions */
/* Define to 1 if you have the `malloc_trim' function. */
libuuid include directory
--with-uuid-libraries=DIR
libuuid library directory
+ --with-libml-includes=DIR
+ libml include directory
+ --with-libml-libraries=DIR
+ libml library directory
Some influential variable definitions:
SIGNAL_SNORT_RELOAD=<int>
--with-toolchain=*)
append_cache_entry CMAKE_TOOLCHAIN_FILE PATH $optarg
;;
+ --with-libml-includes=*)
+ append_cache_entry ML_INCLUDE_DIR_HINT PATH $optarg
+ ;;
+ --with-libml-libraries=*)
+ append_cache_entry ML_LIBRARIES_DIR_HINT PATH $optarg
+ ;;
SIGNAL_SNORT_RELOAD=*)
append_cache_entry SIGNAL_SNORT_RELOAD STRING $optarg
;;
LIST(APPEND EXTERNAL_INCLUDES ${TIRPC_INCLUDE_DIRS})
endif ()
+if ( HAVE_LIBML )
+ LIST(APPEND EXTERNAL_LIBRARIES ${ML_LIBRARIES})
+ LIST(APPEND EXTERNAL_INCLUDES ${ML_INCLUDE_DIRS})
+endif ()
+
include_directories(BEFORE ${LUAJIT_INCLUDE_DIR})
include_directories(AFTER ${EXTERNAL_INCLUDES})
#include <lzma.h>
#endif
+#ifdef HAVE_LIBML
+#include <libml.h>
+#endif
+
extern "C" {
#include <daq.h>
}
#endif
#ifdef HAVE_LZMA
"LZMA",
+#endif
+#ifdef HAVE_LIBML
+ "LIBML",
#endif
nullptr
};
#ifdef HAVE_LZMA
vs.push_back(lzma_version_string());
#endif
+#ifdef HAVE_LIBML
+ vs.push_back(libml_version());
+#endif
lua_createtable(L, 0, vs.size());
for (int i = 0; dep_versions[i + 1];)
add_subdirectory(appid)
add_subdirectory(arp_spoof)
add_subdirectory(binder)
+add_subdirectory(kaizen)
add_subdirectory(normalize)
add_subdirectory(packet_capture)
add_subdirectory(packet_tracer)
set(STATIC_NETWORK_INSPECTOR_PLUGINS
$<TARGET_OBJECTS:appid>
$<TARGET_OBJECTS:binder>
+ $<TARGET_OBJECTS:kaizen>
$<TARGET_OBJECTS:normalize>
$<TARGET_OBJECTS:packet_tracer>
$<TARGET_OBJECTS:port_scan>
packet_capture - A tool for dumping the wire packets that Snort receives.
+kaizen - Machine learning based exploit detector capable of detecting novel
+attacks fitting known vulnerability types. Kaizen uses a neural network
+provided by a model file to detect exploit patterns. The Kaizen Snort module
+subscribes to HTTP events published by the HTTP inspector, performs inference
+on HTTP queries/posts, and generates events if the neural network detects
+an exploit.
+
This entire set of inspectors is instantiated as a group via
network_inspectors.cc
--- /dev/null
+add_library(kaizen OBJECT
+ kaizen_engine.cc
+ kaizen_engine.h
+ kaizen_inspector.cc
+ kaizen_inspector.h
+ kaizen_module.cc
+ kaizen_module.h
+)
--- /dev/null
+Kaizen is a neural network-based exploit detector for the Snort intrusion
+prevention system. It is designed to not only learn to detect known attacks
+from training data, but also learn to detect attacks it has never seen before.
+
+Kaizen uses TensorFlow, included as LibML library.
+
+Global configuration sets the trained network model to use. For example:
+
+ kaizen_engine.http_param_model = { 'model.file' }
+
+While per policy configuration sets data source and inspection depth in
+the selected Inspection policy. The following example enables two sources,
+HTTP URI and HTTP body:
+
+ kaizen.uri_depth = -1
+ kaizen.client_body_depth = 100
+
+Trace messages are available:
+
+* trace.modules.kaizen.classifier turns on messages from Kaizen
+
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2023-2024 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.
+//--------------------------------------------------------------------------
+// kaizen_engine.cc author Vitalii Horbatov <vhorbato@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "kaizen_engine.h"
+
+#include <cassert>
+#include <fstream>
+
+#ifdef HAVE_LIBML
+#include <libml.h>
+#endif
+
+#include "framework/decode_data.h"
+#include "log/messages.h"
+#include "main/reload_tuner.h"
+#include "main/snort.h"
+#include "main/snort_config.h"
+#include "parser/parse_conf.h"
+#include "utils/util.h"
+
+using namespace snort;
+using namespace std;
+
+static THREAD_LOCAL BinaryClassifier* classifier = nullptr;
+
+static bool build_classifier(const string& model, BinaryClassifier*& dst)
+{
+ dst = new BinaryClassifier();
+
+ return dst->build(model);
+}
+
+//--------------------------------------------------------------------------
+// module
+//--------------------------------------------------------------------------
+
+static const Parameter kaizen_engine_params[] =
+{
+ { "http_param_model", Parameter::PT_STRING, nullptr, nullptr, "path to the model file" },
+ { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
+};
+
+KaizenEngineModule::KaizenEngineModule() : Module(KZ_ENGINE_NAME, KZ_ENGINE_HELP, kaizen_engine_params) {}
+
+bool KaizenEngineModule::set(const char*, Value& v, SnortConfig*)
+{
+ if (v.is("http_param_model"))
+ conf.http_param_model_path = v.get_string();
+
+ return true;
+}
+
+//--------------------------------------------------------------------------
+// reload tuner
+//--------------------------------------------------------------------------
+
+class KaizenReloadTuner : public snort::ReloadResourceTuner
+{
+public:
+ explicit KaizenReloadTuner(const string& http_param_model) : http_param_model(http_param_model) {}
+ ~KaizenReloadTuner() override = default;
+
+ bool tinit() override
+ {
+ delete classifier;
+
+ if (!build_classifier(http_param_model, classifier))
+ ErrorMessage("Can't build the classifier model.\n");
+
+ return false;
+ }
+
+ bool tune_packet_context() override
+ { return true; }
+
+ bool tune_idle_context() override
+ { return true; }
+
+private:
+ const string& http_param_model;
+};
+
+//--------------------------------------------------------------------------
+// inspector
+//--------------------------------------------------------------------------
+
+KaizenEngine::KaizenEngine(const KaizenEngineConfig& c) : config(c)
+{
+ http_param_model = read_model();
+
+ if (!validate_model())
+ ParseError("Can't build the classifier model %s.", config.http_param_model_path.c_str());
+}
+
+void KaizenEngine::show(const SnortConfig*) const
+{ ConfigLogger::log_value("http_param_model", config.http_param_model_path.c_str()); }
+
+string KaizenEngine::read_model()
+{
+ const char* hint = config.http_param_model_path.c_str();
+ string path;
+ size_t size = 0;
+
+ if (!get_config_file(hint, path) || !get_file_size(path, size))
+ {
+ ParseError("kaizen_engine: could not read model file: %s", hint);
+ return {};
+ }
+
+ ifstream file(path, ios::binary);
+
+ if (!file.is_open())
+ {
+ ParseError("kaizen_engine: could not read model file: %s", hint);
+ return {};
+ }
+
+ if (size == 0)
+ {
+ ParseError("kaizen_engine: empty model file: %s", hint);
+ return {};
+ }
+
+ string buffer(size, '\0');
+ file.read(&buffer[0], streamsize(size));
+ return buffer;
+}
+
+bool KaizenEngine::validate_model()
+{
+ BinaryClassifier* test_classifier = nullptr;
+ bool res = build_classifier(http_param_model, test_classifier);
+ delete test_classifier;
+
+ return res;
+}
+
+void KaizenEngine::tinit()
+{ build_classifier(http_param_model, classifier); }
+
+void KaizenEngine::tterm()
+{
+ delete classifier;
+ classifier = nullptr;
+}
+
+void KaizenEngine::install_reload_handler(SnortConfig* sc)
+{ sc->register_reload_handler(new KaizenReloadTuner(http_param_model)); }
+
+BinaryClassifier* KaizenEngine::get_classifier()
+{ return classifier; }
+
+//--------------------------------------------------------------------------
+// api stuff
+//--------------------------------------------------------------------------
+
+static Module* mod_ctor()
+{ return new KaizenEngineModule; }
+
+static void mod_dtor(Module* m)
+{ delete m; }
+
+static Inspector* kaizen_engine_ctor(Module* m)
+{
+ KaizenEngineModule* mod = (KaizenEngineModule*)m;
+ return new KaizenEngine(mod->get_config());
+}
+
+static void kaizen_engine_dtor(Inspector* p)
+{
+ assert(p);
+ delete p;
+}
+
+static const InspectApi kaizen_engine_api =
+{
+ {
+#if defined(HAVE_LIBML) || defined(REG_TEST)
+ PT_INSPECTOR,
+#else
+ PT_MAX,
+#endif
+ sizeof(InspectApi),
+ INSAPI_VERSION,
+ 0,
+ API_RESERVED,
+ API_OPTIONS,
+ KZ_ENGINE_NAME,
+ KZ_ENGINE_HELP,
+ mod_ctor,
+ mod_dtor
+ },
+ IT_PASSIVE,
+ PROTO_BIT__NONE, // proto_bits;
+ nullptr, // buffers
+ nullptr, // service
+ nullptr, // pinit
+ nullptr, // pterm
+ nullptr, // tinit
+ nullptr, // tterm
+ kaizen_engine_ctor,
+ kaizen_engine_dtor,
+ nullptr, // ssn
+ nullptr // reset
+};
+
+#ifdef BUILDING_SO
+SO_PUBLIC const BaseApi* snort_plugins[] =
+#else
+const BaseApi* nin_kaizen_engine[] =
+#endif
+{
+ &kaizen_engine_api.base,
+ nullptr
+};
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2023-2024 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.
+//--------------------------------------------------------------------------
+// kaizen_engine.h author Vitalii Horbatov <vhorbato@cisco.com>
+
+#ifndef KAIZEN_ENGINE_H
+#define KAIZEN_ENGINE_H
+
+#include "framework/module.h"
+#include "framework/inspector.h"
+
+
+#define KZ_ENGINE_NAME "kaizen_engine"
+#define KZ_ENGINE_HELP "configure machine learning engine settings"
+
+class BinaryClassifier;
+struct KaizenEngineConfig
+{
+ std::string http_param_model_path;
+};
+
+class KaizenEngineModule : public snort::Module
+{
+public:
+ KaizenEngineModule();
+
+ bool set(const char*, snort::Value&, snort::SnortConfig*) override;
+
+ Usage get_usage() const override
+ { return GLOBAL; }
+
+ const KaizenEngineConfig& get_config()
+ { return conf; }
+
+private:
+ KaizenEngineConfig conf;
+};
+
+
+class KaizenEngine : public snort::Inspector
+{
+public:
+ KaizenEngine(const KaizenEngineConfig&);
+
+ void show(const snort::SnortConfig*) const override;
+ void eval(snort::Packet*) override {}
+
+ void tinit() override;
+ void tterm() override;
+
+ void install_reload_handler(snort::SnortConfig*) override;
+
+ static BinaryClassifier* get_classifier();
+
+private:
+ std::string read_model();
+ bool validate_model();
+
+ KaizenEngineConfig config;
+ std::string http_param_model;
+};
+
+
+// Mock Classifier for tests if LibML absents.
+// However, when REG_TEST is undefined, the entire code below won't be executed.
+// Check the plugin type provided in kaizen_engine_api in the cc file
+#ifndef HAVE_LIBML
+class BinaryClassifier
+{
+public:
+ bool build(const std::string& model)
+ {
+ pattern = model;
+ return pattern != "error";
+ }
+
+ bool run(const char* ptr, size_t len, float& threshold)
+ {
+ std::string data(ptr, len);
+ threshold = std::string::npos == data.find(pattern) ? 0.0f : 1.0f;
+ return pattern != "fail";
+ }
+
+private:
+ std::string pattern;
+};
+#endif
+
+#endif
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2023-2024 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.
+//--------------------------------------------------------------------------
+// kaizen_inspector.cc author Brandon Stultz <brastult@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "kaizen_inspector.h"
+
+#include <cassert>
+
+#ifdef HAVE_LIBML
+#include <libml.h>
+#endif
+
+#include "detection/detection_engine.h"
+#include "log/messages.h"
+#include "managers/inspector_manager.h"
+#include "pub_sub/http_events.h"
+#include "pub_sub/http_request_body_event.h"
+#include "utils/util.h"
+
+#include "kaizen_engine.h"
+
+using namespace snort;
+using namespace std;
+
+THREAD_LOCAL KaizenStats kaizen_stats;
+THREAD_LOCAL ProfileStats kaizen_prof;
+
+//--------------------------------------------------------------------------
+// HTTP body event handler
+//--------------------------------------------------------------------------
+
+class HttpBodyHandler : public DataHandler
+{
+public:
+ HttpBodyHandler(Kaizen& kz)
+ : DataHandler(KZ_NAME), inspector(kz) {}
+
+ void handle(DataEvent& de, Flow*) override;
+
+private:
+ Kaizen& inspector;
+};
+
+void HttpBodyHandler::handle(DataEvent& de, Flow*)
+{
+ // cppcheck-suppress unreadVariable
+ Profile profile(kaizen_prof);
+
+ BinaryClassifier* classifier = KaizenEngine::get_classifier();
+ KaizenConfig config = inspector.get_config();
+ HttpRequestBodyEvent* he = (HttpRequestBodyEvent*)&de;
+
+ if (he->is_mime())
+ return;
+
+ int32_t body_len = 0;
+
+ const char* body = (const char*)he->get_client_body(body_len);
+
+ body_len = std::min(config.client_body_depth, body_len);
+
+ if (!body || body_len <= 0)
+ return;
+
+ assert(classifier);
+
+ float output = 0.0;
+
+ kaizen_stats.libml_calls++;
+
+ if (!classifier->run(body, (size_t)body_len, output))
+ return;
+
+ kaizen_stats.client_body_bytes += body_len;
+
+ debug_logf(kaizen_trace, TRACE_CLASSIFIER, nullptr, "input (body): %.*s\n", body_len, body);
+ debug_logf(kaizen_trace, TRACE_CLASSIFIER, nullptr, "output: %f\n", output);
+
+ if ((double)output > config.http_param_threshold)
+ {
+ kaizen_stats.client_body_alerts++;
+ debug_logf(kaizen_trace, TRACE_CLASSIFIER, nullptr, "<ALERT>\n");
+ DetectionEngine::queue_event(KZ_GID, KZ_SID);
+ }
+}
+
+//--------------------------------------------------------------------------
+// HTTP uri event handler
+//--------------------------------------------------------------------------
+
+class HttpUriHandler : public DataHandler
+{
+public:
+ HttpUriHandler(Kaizen& kz)
+ : DataHandler(KZ_NAME), inspector(kz) {}
+
+ void handle(DataEvent&, Flow*) override;
+
+private:
+ Kaizen& inspector;
+};
+
+void HttpUriHandler::handle(DataEvent& de, Flow*)
+{
+ // cppcheck-suppress unreadVariable
+ Profile profile(kaizen_prof);
+
+ BinaryClassifier* classifier = KaizenEngine::get_classifier();
+ KaizenConfig config = inspector.get_config();
+ HttpEvent* he = (HttpEvent*)&de;
+
+ int32_t query_len = 0;
+ const char* query = (const char*)he->get_uri_query(query_len);
+
+ query_len = std::min(config.uri_depth, query_len);
+
+ if (!query || query_len <= 0)
+ return;
+
+ assert(classifier);
+
+ float output = 0.0;
+
+ kaizen_stats.libml_calls++;
+
+ if (!classifier->run(query, (size_t)query_len, output))
+ return;
+
+ kaizen_stats.uri_bytes += query_len;
+
+ debug_logf(kaizen_trace, TRACE_CLASSIFIER, nullptr, "input (query): %.*s\n", query_len, query);
+ debug_logf(kaizen_trace, TRACE_CLASSIFIER, nullptr, "output: %f\n", output);
+
+ if ((double)output > config.http_param_threshold)
+ {
+ kaizen_stats.uri_alerts++;
+ debug_logf(kaizen_trace, TRACE_CLASSIFIER, nullptr, "<ALERT>\n");
+ DetectionEngine::queue_event(KZ_GID, KZ_SID);
+ }
+}
+
+//--------------------------------------------------------------------------
+// inspector
+//--------------------------------------------------------------------------
+
+void Kaizen::show(const SnortConfig*) const
+{
+ ConfigLogger::log_value("uri_depth", config.uri_depth);
+ ConfigLogger::log_value("client_body_depth", config.client_body_depth);
+ ConfigLogger::log_value("http_param_threshold", config.http_param_threshold);
+}
+
+bool Kaizen::configure(SnortConfig* sc)
+{
+ if (config.uri_depth > 0)
+ DataBus::subscribe(http_pub_key, HttpEventIds::REQUEST_HEADER, new HttpUriHandler(*this));
+
+ if (config.client_body_depth > 0)
+ DataBus::subscribe(http_pub_key, HttpEventIds::REQUEST_BODY, new HttpBodyHandler(*this));
+
+ if(!InspectorManager::get_inspector(KZ_ENGINE_NAME, true, sc))
+ {
+ ParseError("kaizen requires %s to be configured in the global policy.", KZ_ENGINE_NAME);
+ return false;
+ }
+
+ return true;
+}
+
+//--------------------------------------------------------------------------
+// api stuff
+//--------------------------------------------------------------------------
+
+static Module* mod_ctor()
+{ return new KaizenModule; }
+
+static void mod_dtor(Module* m)
+{ delete m; }
+
+static Inspector* kaizen_ctor(Module* m)
+{
+ KaizenModule* km = (KaizenModule*)m;
+ return new Kaizen(km->get_conf());
+}
+
+static void kaizen_dtor(Inspector* p)
+{
+ assert(p);
+ delete p;
+}
+
+static const InspectApi kaizen_api =
+{
+ {
+#if defined(HAVE_LIBML) || defined(REG_TEST)
+ PT_INSPECTOR,
+#else
+ PT_MAX,
+#endif
+ sizeof(InspectApi),
+ INSAPI_VERSION,
+ 0,
+ API_RESERVED,
+ API_OPTIONS,
+ KZ_NAME,
+ KZ_HELP,
+ mod_ctor,
+ mod_dtor
+ },
+ IT_PASSIVE,
+ PROTO_BIT__ANY_IP, // proto_bits;
+ nullptr, // buffers
+ nullptr, // service
+ nullptr, // pinit
+ nullptr, // pterm
+ nullptr, // tinit
+ nullptr, // tterm
+ kaizen_ctor,
+ kaizen_dtor,
+ nullptr, // ssn
+ nullptr // reset
+};
+
+#ifdef BUILDING_SO
+SO_PUBLIC const BaseApi* snort_plugins[] =
+#else
+const BaseApi* nin_kaizen[] =
+#endif
+{
+ &kaizen_api.base,
+ nullptr
+};
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2023-2024 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.
+//--------------------------------------------------------------------------
+// kaizen_inspector.h author Brandon Stultz <brastult@cisco.com>
+
+#ifndef KAIZEN_INSPECTOR_H
+#define KAIZEN_INSPECTOR_H
+
+#include <string>
+#include <utility>
+
+#include "framework/inspector.h"
+
+#include "kaizen_module.h"
+
+class Kaizen : public snort::Inspector
+{
+public:
+ Kaizen(const KaizenConfig& c) : config(c) { };
+
+ void show(const snort::SnortConfig*) const override;
+ void eval(snort::Packet*) override {}
+ bool configure(snort::SnortConfig*) override;
+
+ const KaizenConfig& get_config()
+ { return config; }
+private:
+ KaizenConfig config;
+};
+
+#endif
+
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2023-2024 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.
+//--------------------------------------------------------------------------
+// kaizen_module.cc author Brandon Stultz <brastult@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "kaizen_module.h"
+
+#include "log/messages.h"
+#include "service_inspectors/http_inspect/http_field.h"
+
+using namespace snort;
+
+THREAD_LOCAL const Trace* kaizen_trace = nullptr;
+
+static const Parameter kaizen_params[] =
+{
+ { "uri_depth", Parameter::PT_INT, "-1:max31", "-1",
+ "number of input HTTP URI bytes to scan (-1 unlimited)" },
+
+ { "client_body_depth", Parameter::PT_INT, "-1:max31", "0",
+ "number of input HTTP client body bytes to scan (-1 unlimited)" },
+
+ { "http_param_threshold", Parameter::PT_REAL, "0:1", "0.95",
+ "alert threshold for http_param_model" },
+
+ { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
+};
+
+static const RuleMap kaizen_rules[] =
+{
+ { KZ_SID, "exploit payload detected" },
+ { 0, nullptr }
+};
+
+static const PegInfo peg_names[] =
+{
+ { CountType::SUM, "uri_alerts", "total number of alerts triggered on HTTP URI" },
+ { CountType::SUM, "client_body_alerts", "total number of alerts triggered on HTTP client body" },
+ { CountType::SUM, "uri_bytes", "total number of HTTP URI bytes processed" },
+ { CountType::SUM, "client_body_bytes", "total number of HTTP client body bytes processed" },
+ { CountType::SUM, "libml_calls", "total libml calls" },
+ { CountType::END, nullptr, nullptr }
+};
+
+#ifdef DEBUG_MSGS
+static const TraceOption kaizen_trace_options[] =
+{
+ { "classifier", TRACE_CLASSIFIER, "enable Kaizen classifier trace logging" },
+ { nullptr, 0, nullptr }
+};
+#endif
+
+//--------------------------------------------------------------------------
+// module
+//--------------------------------------------------------------------------
+
+KaizenModule::KaizenModule() : Module(KZ_NAME, KZ_HELP, kaizen_params) {}
+
+bool KaizenModule::set(const char*, Value& v, SnortConfig*)
+{
+ static_assert(std::is_same<decltype((Field().length())), decltype(conf.uri_depth)>::value,
+ "Field::length maximum value should not exceed uri_depth type range");
+ static_assert(std::is_same<decltype((Field().length())), decltype(conf.client_body_depth)>::value,
+ "Field::length maximum value should not exceed client_body_depth type range");
+
+ if (v.is("uri_depth"))
+ {
+ conf.uri_depth = v.get_int32();
+ if (conf.uri_depth == -1)
+ conf.uri_depth = INT32_MAX;
+ }
+ else if (v.is("client_body_depth"))
+ {
+ conf.client_body_depth = v.get_int32();
+ if (conf.client_body_depth == -1)
+ conf.client_body_depth = INT32_MAX;
+ }
+ else if (v.is("http_param_threshold"))
+ conf.http_param_threshold = v.get_real();
+
+ return true;
+}
+
+bool KaizenModule::end(const char*, int, snort::SnortConfig*)
+{
+ if (!conf.uri_depth && !conf.client_body_depth)
+ ParseWarning(WARN_CONF,
+ "Neither of Kaizen source depth is set, Kaizen won't process traffic.");
+
+ return true;
+}
+
+const RuleMap* KaizenModule::get_rules() const
+{ return kaizen_rules; }
+
+const PegInfo* KaizenModule::get_pegs() const
+{ return peg_names; }
+
+PegCount* KaizenModule::get_counts() const
+{ return (PegCount*)&kaizen_stats; }
+
+ProfileStats* KaizenModule::get_profile() const
+{ return &kaizen_prof; }
+
+void KaizenModule::set_trace(const Trace* trace) const
+{ kaizen_trace = trace; }
+
+const TraceOption* KaizenModule::get_trace_options() const
+{
+#ifndef DEBUG_MSGS
+ return nullptr;
+#else
+ return kaizen_trace_options;
+#endif
+}
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2023-2024 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.
+//--------------------------------------------------------------------------
+// kaizen_module.h author Brandon Stultz <brastult@cisco.com>
+
+#ifndef KAIZEN_MODULE_H
+#define KAIZEN_MODULE_H
+
+#include "framework/module.h"
+#include "main/thread.h"
+#include "profiler/profiler.h"
+#include "trace/trace_api.h"
+
+#define KZ_GID 411
+#define KZ_SID 1
+
+#define KZ_NAME "kaizen"
+#define KZ_HELP "machine learning based exploit detector"
+
+enum { TRACE_CLASSIFIER };
+
+struct KaizenStats
+{
+ PegCount uri_alerts;
+ PegCount client_body_alerts;
+ PegCount uri_bytes;
+ PegCount client_body_bytes;
+ PegCount libml_calls;
+};
+
+extern THREAD_LOCAL KaizenStats kaizen_stats;
+extern THREAD_LOCAL snort::ProfileStats kaizen_prof;
+extern THREAD_LOCAL const snort::Trace* kaizen_trace;
+
+struct KaizenConfig
+{
+ std::string http_param_model_path;
+ double http_param_threshold;
+ int32_t uri_depth;
+ int32_t client_body_depth;
+};
+
+class KaizenModule : public snort::Module
+{
+public:
+ KaizenModule();
+
+ bool set(const char*, snort::Value&, snort::SnortConfig*) override;
+ bool end(const char*, int, snort::SnortConfig*) override;
+
+ const KaizenConfig& get_conf() const
+ { return conf; }
+
+ unsigned get_gid() const override
+ { return KZ_GID; }
+
+ const snort::RuleMap* get_rules() const override;
+
+ const PegInfo* get_pegs() const override;
+ PegCount* get_counts() const override;
+
+ Usage get_usage() const override
+ { return INSPECT; }
+
+ snort::ProfileStats* get_profile() const override;
+
+ void set_trace(const snort::Trace*) const override;
+ const snort::TraceOption* get_trace_options() const override;
+
+private:
+ KaizenConfig conf = {};
+};
+
+#endif
+
extern const BaseApi* nin_reputation;
extern const BaseApi* nin_appid[];
+extern const BaseApi* nin_kaizen_engine[];
+extern const BaseApi* nin_kaizen[];
extern const BaseApi* nin_port_scan[];
extern const BaseApi* nin_rna[];
{
PluginManager::load_plugins(network_inspectors);
PluginManager::load_plugins(nin_appid);
+ PluginManager::load_plugins(nin_kaizen_engine);
+ PluginManager::load_plugins(nin_kaizen);
PluginManager::load_plugins(nin_port_scan);
PluginManager::load_plugins(nin_rna);
#include <lzma.h>
#endif
+#ifdef HAVE_LIBML
+#include <libml.h>
+#endif
+
extern "C" {
#include <daq.h>
}
#endif
#ifdef HAVE_LZMA
LogMessage(" Using LZMA version %s\n", lzma_version_string());
+#endif
+#ifdef HAVE_LIBML
+ LogMessage(" Using LibML version %s\n", libml_version());
#endif
LogMessage("\n");