]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #2290 in SNORT/snort3 from ~MDAGON/snort3:packet_inj to master
authorMike Stepanek (mstepane) <mstepane@cisco.com>
Mon, 29 Jun 2020 20:32:01 +0000 (20:32 +0000)
committerMike Stepanek (mstepane) <mstepane@cisco.com>
Mon, 29 Jun 2020 20:32:01 +0000 (20:32 +0000)
Squashed commit of the following:

commit b400fbede446c8e1e817f83763128e38fcd3ddad
Author: mdagon <mdagon@cisco.com>
Date:   Wed May 27 14:48:03 2020 -0400

    payload_injector: add payload injection utility

lua/snort.lua
src/CMakeLists.txt
src/main/modules.cc
src/payload_injector/CMakeLists.txt [new file with mode: 0644]
src/payload_injector/dev_notes.txt [new file with mode: 0644]
src/payload_injector/payload_injector_module.cc [new file with mode: 0644]
src/payload_injector/payload_injector_module.h [new file with mode: 0644]
src/payload_injector/test/CMakeLists.txt [new file with mode: 0644]
src/payload_injector/test/payload_injector_test.cc [new file with mode: 0644]

index f48d1ba4be61bbe7ae91c2075a84d0f5e770f694..e4eb1fa8e1e965fc6e1cd6a01cd9097b100f1d61 100644 (file)
@@ -177,6 +177,9 @@ rewrite = { }
 -- react = { }
 -- reject = { }
 
+-- use this to enable payload injection utility
+-- payload_injector = { }
+
 ---------------------------------------------------------------------------
 -- 6. configure filters
 ---------------------------------------------------------------------------
index 4285aac2734a71c87caa4193004c3440658047c5..c5dc29dc4f0dae2e35d8529b09487ce22754c340 100644 (file)
@@ -103,6 +103,7 @@ add_subdirectory(memory)
 add_subdirectory(mime)
 add_subdirectory(packet_io)
 add_subdirectory(parser)
+add_subdirectory(payload_injector)
 add_subdirectory(ports)
 add_subdirectory(protocols)
 add_subdirectory(sfip)
@@ -160,6 +161,7 @@ add_executable( snort
     $<TARGET_OBJECTS:network_inspectors>
     $<TARGET_OBJECTS:packet_io>
     $<TARGET_OBJECTS:parser>
+    $<TARGET_OBJECTS:payload_injector>
     $<TARGET_OBJECTS:ports>
     $<TARGET_OBJECTS:profiler>
     $<TARGET_OBJECTS:protocols>
index 11a6bf74f5a80eccfb897d146d32baa47b0096b7..714c62ff8d24cdcd44604b53517421c53b42824b 100644 (file)
@@ -51,6 +51,7 @@
 #include "parser/parse_conf.h"
 #include "parser/parse_ip.h"
 #include "parser/parser.h"
+#include "payload_injector/payload_injector_module.h"
 #include "profiler/profiler.h"
 #include "search_engines/pat_stats.h"
 #include "side_channel/side_channel_module.h"
@@ -2024,8 +2025,9 @@ void module_init()
     ModuleManager::add_module(new RuleStateModule);
     ModuleManager::add_module(new SearchEngineModule);
     ModuleManager::add_module(new SFDAQModule);
+    ModuleManager::add_module(new PayloadInjectorModule);
 
-    // these could but prolly shouldn't be policy specific
+    // these could but probably shouldn't be policy specific
     // or should be broken into policy and non-policy parts
     ModuleManager::add_module(new AlertsModule);
     ModuleManager::add_module(new EventQueueModule);
diff --git a/src/payload_injector/CMakeLists.txt b/src/payload_injector/CMakeLists.txt
new file mode 100644 (file)
index 0000000..b3d82db
--- /dev/null
@@ -0,0 +1,14 @@
+set (PAYLOAD_INJECTOR_INCLUDES
+    payload_injector_module.h
+)
+
+add_library ( payload_injector OBJECT
+    ${PAYLOAD_INJECTOR_INCLUDES}
+    payload_injector_module.cc
+)
+
+install(FILES ${PAYLOAD_INJECTOR_INCLUDES}
+    DESTINATION "${INCLUDE_INSTALL_PATH}/payload_injector/"
+)
+
+add_subdirectory(test)
diff --git a/src/payload_injector/dev_notes.txt b/src/payload_injector/dev_notes.txt
new file mode 100644 (file)
index 0000000..cf38ddb
--- /dev/null
@@ -0,0 +1,9 @@
+Payload injector is a utility class intended to help other Snort components with
+application-protocol-level injection. The calling components decide when and
+what to inject. Payload injector is responsible for flow-control concerns such
+as transmitting RST flags to endpoints as well as blocking flows within Snort.
+It coordinates with the Active component of Snort to perform these functions.
+
+Currently it is being used for HTTP/1 injections. HTTP/2 support is in developement.
+
+
diff --git a/src/payload_injector/payload_injector_module.cc b/src/payload_injector/payload_injector_module.cc
new file mode 100644 (file)
index 0000000..37f6f06
--- /dev/null
@@ -0,0 +1,97 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2020 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.
+//--------------------------------------------------------------------------
+
+// payload_injector_module.cc author Maya Dagon <mdagon@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "payload_injector_module.h"
+
+#include "detection/detection_engine.h"
+#include "packet_io/active.h"
+#include "protocols/packet.h"
+
+#ifdef UNIT_TEST
+#include "catch/snort_catch.h"
+#endif
+
+#define s_name "payload_injector"
+#define s_help \
+    "payload injection utility"
+
+using namespace snort;
+
+THREAD_LOCAL PayloadInjectorCounts payload_injector_stats;
+
+const PegInfo payload_injector_pegs[] =
+{
+    { CountType::SUM, "http_injects", "total number of http injections" },
+    { CountType::END, nullptr, nullptr }
+};
+
+bool PayloadInjectorModule::configured = false;
+
+PayloadInjectorModule::PayloadInjectorModule() :
+    Module(s_name, s_help)
+{ }
+
+const PegInfo* PayloadInjectorModule::get_pegs() const
+{ return payload_injector_pegs; }
+
+PegCount* PayloadInjectorModule::get_counts() const
+{ return (PegCount*)&payload_injector_stats; }
+
+bool PayloadInjectorModule::end(const char*, int, SnortConfig*)
+{
+    configured = true;
+    return true;
+}
+
+InjectionReturnStatus PayloadInjectorModule::inject_http_payload(Packet* p, InjectionControl& control)
+{
+    InjectionReturnStatus status = INJECTION_SUCCESS;
+
+    assert(p != nullptr);
+
+    if (configured)
+    {
+        EncodeFlags df = (p->packet_flags & PKT_FROM_SERVER) ? ENC_FLAG_FWD : 0;
+        df |= ENC_FLAG_RST_SRVR; // Send RST to server.
+
+        if (p->packet_flags & PKT_STREAM_EST)
+        {
+            payload_injector_stats.http_injects++;
+            p->active->send_data(p, df, control.http_page, control.http_page_len);
+        }
+        else
+            status = ERR_STREAM_NOT_ESTABLISHED;
+    }
+    else
+        status = ERR_INJECTOR_NOT_CONFIGURED;
+
+    p->active->block_session(p, true);
+
+    DetectionEngine::disable_all(p);
+
+    if ( p->flow )
+        p->flow->set_state(Flow::FlowState::BLOCK);
+
+    return status;
+}
diff --git a/src/payload_injector/payload_injector_module.h b/src/payload_injector/payload_injector_module.h
new file mode 100644 (file)
index 0000000..a196545
--- /dev/null
@@ -0,0 +1,74 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2020 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.
+//--------------------------------------------------------------------------
+
+// payload_injector_module.h author Maya Dagon <mdagon@cisco.com>
+
+#ifndef PAYLOAD_INJECTOR_MODULE_H
+#define PAYLOAD_INJECTOR_MODULE_H
+
+#include "framework/module.h"
+
+namespace snort
+{
+struct Packet;
+}
+
+struct PayloadInjectorCounts
+{
+    PegCount http_injects;
+};
+
+extern THREAD_LOCAL PayloadInjectorCounts payload_injection_stats;
+
+enum InjectionReturnStatus : int8_t
+{
+    INJECTION_SUCCESS = 1,
+    ERR_INJECTOR_NOT_CONFIGURED = -1,
+    ERR_STREAM_NOT_ESTABLISHED = -2,
+};
+
+struct InjectionControl
+{
+    const uint8_t* http_page = nullptr;
+    uint32_t http_page_len = 0;
+};
+
+class SO_PUBLIC PayloadInjectorModule : public snort::Module
+{
+public:
+    PayloadInjectorModule();
+    const PegInfo* get_pegs() const override;
+    PegCount* get_counts() const override;
+
+    Usage get_usage() const override
+    { return GLOBAL; }
+
+    bool end(const char*, int, snort::SnortConfig*) override;
+
+    static InjectionReturnStatus inject_http_payload(snort::Packet* p, InjectionControl& control);
+
+#ifdef UNIT_TEST
+    void set_configured(bool val) { configured = val; }
+#endif
+
+private:
+    static bool configured;
+};
+
+#endif
+
diff --git a/src/payload_injector/test/CMakeLists.txt b/src/payload_injector/test/CMakeLists.txt
new file mode 100644 (file)
index 0000000..693bcc5
--- /dev/null
@@ -0,0 +1,5 @@
+add_cpputest (payload_injector_test
+  SOURCES
+      ../payload_injector_module.cc
+      ../../framework/module.cc
+)
diff --git a/src/payload_injector/test/payload_injector_test.cc b/src/payload_injector/test/payload_injector_test.cc
new file mode 100644 (file)
index 0000000..f072a50
--- /dev/null
@@ -0,0 +1,124 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2020 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.
+//--------------------------------------------------------------------------
+
+// payload_injector_test.cc author Maya Dagon <mdagon@cisco.com>
+// unit test main
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "payload_injector/payload_injector_module.h"
+
+#include "detection/detection_engine.h"
+#include "flow/flow.h"
+#include "packet_io/active.h"
+#include "protocols/packet.h"
+
+#include <CppUTest/CommandLineTestRunner.h>
+#include <CppUTest/TestHarness.h>
+
+using namespace snort;
+
+//--------------------------------------------------------------------------
+// mocks
+//--------------------------------------------------------------------------
+namespace snort
+{
+uint32_t Active::send_data(snort::Packet*, unsigned long, unsigned char const*, unsigned int)
+{
+    return 1;
+}
+void Active::block_session(snort::Packet*, bool) { }
+void DetectionEngine::disable_all(snort::Packet*) { }
+Flow::Flow() { }
+Flow::~Flow() { }
+Packet::Packet(bool) { packet_flags = 0; flow = nullptr; }
+Packet::~Packet() { }
+}
+
+void show_stats(PegCount*, const PegInfo*, unsigned, const char*) { }
+void show_stats(PegCount*, const PegInfo*, const IndexVec&, const char*, FILE*) { }
+
+TEST_GROUP(payload_injector_test)
+{
+    PayloadInjectorModule mod;
+    InjectionControl control;
+    PegCount* counts = mod.get_counts();
+    Flow flow;
+
+    void setup() override
+    {
+        counts[0] = 0;
+        control.http_page = (const uint8_t*)"test";
+        control.http_page_len = 4;
+        flow.set_state(Flow::FlowState::INSPECT);
+    }
+};
+
+TEST(payload_injector_test, not_configured_stream_not_established)
+{
+    mod.set_configured(false);
+    Packet p(false);
+    p.flow = &flow;
+    InjectionReturnStatus status = mod.inject_http_payload(&p, control);
+    CHECK(counts[0] == 0);
+    CHECK(status == ERR_INJECTOR_NOT_CONFIGURED);
+    CHECK(flow.flow_state == Flow::FlowState::BLOCK);
+}
+
+TEST(payload_injector_test, not_configured_stream_established)
+{
+    mod.set_configured(false);
+    Packet p(false);
+    p.packet_flags = PKT_STREAM_EST;
+    p.flow = &flow;
+    InjectionReturnStatus status = mod.inject_http_payload(&p, control);
+    CHECK(counts[0] == 0);
+    CHECK(status == ERR_INJECTOR_NOT_CONFIGURED);
+    CHECK(flow.flow_state == Flow::FlowState::BLOCK);
+}
+
+TEST(payload_injector_test, configured_stream_not_established)
+{
+    mod.set_configured(true);
+    Packet p(false);
+    p.flow = &flow;
+    InjectionReturnStatus status = mod.inject_http_payload(&p, control);
+    CHECK(counts[0] == 0);
+    CHECK(status == ERR_STREAM_NOT_ESTABLISHED);
+    CHECK(flow.flow_state == Flow::FlowState::BLOCK);
+}
+
+TEST(payload_injector_test, configured_stream_established)
+{
+    mod.set_configured(true);
+    Packet p(false);
+    p.packet_flags = PKT_STREAM_EST;
+    p.flow = &flow;
+    InjectionReturnStatus status = mod.inject_http_payload(&p, control);
+    CHECK(counts[0] == 1);
+    CHECK(status == INJECTION_SUCCESS);
+    CHECK(flow.flow_state == Flow::FlowState::BLOCK);
+}
+
+int main(int argc, char** argv)
+{
+    return CommandLineTestRunner::RunAllTests(argc, argv);
+}
+