-- react = { }
-- reject = { }
+-- use this to enable payload injection utility
+-- payload_injector = { }
+
---------------------------------------------------------------------------
-- 6. configure filters
---------------------------------------------------------------------------
add_subdirectory(mime)
add_subdirectory(packet_io)
add_subdirectory(parser)
+add_subdirectory(payload_injector)
add_subdirectory(ports)
add_subdirectory(protocols)
add_subdirectory(sfip)
$<TARGET_OBJECTS:network_inspectors>
$<TARGET_OBJECTS:packet_io>
$<TARGET_OBJECTS:parser>
+ $<TARGET_OBJECTS:payload_injector>
$<TARGET_OBJECTS:ports>
$<TARGET_OBJECTS:profiler>
$<TARGET_OBJECTS:protocols>
#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"
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);
--- /dev/null
+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)
--- /dev/null
+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.
+
+
--- /dev/null
+//--------------------------------------------------------------------------
+// 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;
+}
--- /dev/null
+//--------------------------------------------------------------------------
+// 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
+
--- /dev/null
+add_cpputest (payload_injector_test
+ SOURCES
+ ../payload_injector_module.cc
+ ../../framework/module.cc
+)
--- /dev/null
+//--------------------------------------------------------------------------
+// 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);
+}
+