From: Russ Combs Date: Fri, 25 Jul 2014 21:36:40 +0000 (-0400) Subject: added optional selector to http_header X-Git-Tag: 3.0.0-233~1436^2~2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=d1d96162e12591ad3a751c15fa2fbd4889a54e0f;p=thirdparty%2Fsnort3.git added optional selector to http_header --- diff --git a/ChangeLog b/ChangeLog index 3298bcefc..c406707d4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,7 @@ -- added --rule "" for easy command line testing -- added --list-plugins to see which plugins don't have modules -- added helpers/markup.{h,cc} +-- added optional header selector to http_header 104 -- changed configure --with-libpcre-* to --with-pcre-* for consistency diff --git a/lua/snort.lua b/lua/snort.lua index 48c717175..b423218cc 100644 --- a/lua/snort.lua +++ b/lua/snort.lua @@ -201,13 +201,13 @@ profile = { rules = { - count = 25, + count = 0, sort = 'avg_ticks', file = { append = true } }, modules = { - --count = 10, + count = 0, sort = 'avg_ticks', file = { append = true } } @@ -498,6 +498,7 @@ stream_udp = --------------------------------------------------------------------------- -- alerts + packets +--[[ unified2 = { file = 'u2.log', @@ -506,16 +507,17 @@ unified2 = mpls_event_types = true, vlan_event_types = true } +--]] -- text --alert_syslog = { mode = 'LOG_AUTH LOG_ALERT' } -alert_fast = { } -alert_full = { } ---alert_test = { file = 'alert.tsv', session = false, msg = true } +--alert_fast = { } +--alert_full = { } +--alert_test = { file = 'alert.tsv' } --alert_csv = { file = 'alert.csv' } -- pcap -log_tcpdump = { file = 'snort++.pcap' } +--log_tcpdump = { file = 'snort++.pcap' } --------------------------------------------------------------------------- -- ips rules and filters @@ -550,6 +552,13 @@ default_rules = #alert http ( sid:1; msg:"1"; content:"HTTP"; ) #alert http any -> 1.2.3.4 ( sid:2; msg:"2"; content:"HTTP"; ) #alert http any any -> 1.2.3.4 80 ( sid:3; msg:"3"; content:"HTTP"; ) + +#alert tcp $HOME_NET any -> $EXTERNAL_NET $HTTP_PORTS (msg:"BLACKLIST User-Agent known malicious user agent - SAH Agent"; flow:to_server,established; content:"User-Agent|3A| SAH Agent"; metadata: policy balanced-ips drop, policy connectivity-ips drop, policy security-ips drop, service http; classtype:misc-activity; sid:5808; rev:9;) + +#alert tcp any any -> any 80 ( msg:"Sample rule for Snort++"; http_uri; content:"attack"; sid:1; ) +#alert tcp any 80 -> any any ( msg:"Sample rule for Snort++"; http_header:Transfer-Encoding; content:"chunk"; sid:2; ) +#alert tcp any 80 -> any any ( msg:"Sample rule for Snort++"; http_header; content:"chunk"; sid:3; ) +#alert tcp any any -> any any ( msg:"Sample rule for Snort++"; content:"trigger"; sid:2; ) ]] network = @@ -560,8 +569,9 @@ network = -- put classic rules and includes in the include file and/or rules string ips = { - --include = '../active.rules', - --rules = default_rules, + --include = '../test.rules', + --include = 'active.rules', + rules = default_rules, enable_builtin_rules = false } diff --git a/src/ips_options/CMakeLists.txt b/src/ips_options/CMakeLists.txt index 3f5c3c0d1..981144ba0 100644 --- a/src/ips_options/CMakeLists.txt +++ b/src/ips_options/CMakeLists.txt @@ -15,6 +15,7 @@ SET( PLUGIN_LIST ips_fragbits.cc ips_fragoffset.cc ips_http.cc + ips_http_header.cc ips_icmp_id.cc ips_icmp_seq.cc ips_icode.cc diff --git a/src/ips_options/Makefile.am b/src/ips_options/Makefile.am index d7b19ed29..bbe1ec23d 100644 --- a/src/ips_options/Makefile.am +++ b/src/ips_options/Makefile.am @@ -16,6 +16,7 @@ ips_flags.cc \ ips_fragbits.cc \ ips_fragoffset.cc \ ips_http.cc \ +ips_http_header.cc \ ips_icmp_id.cc \ ips_icmp_seq.cc \ ips_icode.cc \ diff --git a/src/ips_options/ips_http.cc b/src/ips_options/ips_http.cc index 6b07f330c..5f1a3c176 100644 --- a/src/ips_options/ips_http.cc +++ b/src/ips_options/ips_http.cc @@ -18,6 +18,7 @@ ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +// ips_http.cc author Russ Combs #ifdef HAVE_CONFIG_H #include "config.h" @@ -156,46 +157,6 @@ static const IpsApi uri_api = nullptr }; -//------------------------------------------------------------------------- -// http_header -//------------------------------------------------------------------------- - -#undef IPS_OPT -#define IPS_OPT "http_header" - -static THREAD_LOCAL ProfileStats header_ps; - -static Module* header_mod_ctor() -{ - return new HttpCursorModule(IPS_OPT, header_ps); -} - -static IpsOption* header_opt_ctor(Module*, OptTreeNode*) -{ - return new HttpIpsOption(IPS_OPT, header_ps, CAT_SET_HEADER); -} - -static const IpsApi header_api = -{ - { - PT_IPS_OPTION, - IPS_OPT, - IPSAPI_PLUGIN_V0, - 0, - header_mod_ctor, - mod_dtor - }, - OPT_TYPE_DETECTION, - 1, PROTO_BIT__TCP, - nullptr, - nullptr, - nullptr, - nullptr, - header_opt_ctor, - opt_dtor, - nullptr -}; - //------------------------------------------------------------------------- // http_client_body //------------------------------------------------------------------------- @@ -524,7 +485,6 @@ static const IpsApi raw_cookie_api = SO_PUBLIC const BaseApi* snort_plugins[] = { &uri_api.base, - &header_api.base, &client_body_api.base, &method_api.base, &cookie_api.base, @@ -537,7 +497,6 @@ SO_PUBLIC const BaseApi* snort_plugins[] = }; #else const BaseApi* ips_http_uri = &uri_api.base; -const BaseApi* ips_http_header = &header_api.base; const BaseApi* ips_http_client_body = &client_body_api.base; const BaseApi* ips_http_method = &method_api.base; const BaseApi* ips_http_cookie = &cookie_api.base; diff --git a/src/ips_options/ips_http_header.cc b/src/ips_options/ips_http_header.cc new file mode 100644 index 000000000..33b13ce79 --- /dev/null +++ b/src/ips_options/ips_http_header.cc @@ -0,0 +1,242 @@ +/* +** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. +** Copyright (C) 2002-2013 Sourcefire, Inc. +** Copyright (C) 1998-2002 Martin Roesch +** +** 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_http_header.cc author Russ Combs + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include + +#include +using namespace std; + +#include "snort_types.h" +#include "treenodes.h" +#include "protocols/packet.h" +#include "parser.h" +#include "util.h" +#include "snort_debug.h" +#include "snort.h" +#include "profiler.h" +#include "flow/flow.h" +#include "detection/detection_defines.h" +#include "framework/ips_option.h" +#include "framework/cursor.h" +#include "framework/inspector.h" +#include "framework/module.h" + +static const char* s_name = "http_header"; + +static THREAD_LOCAL ProfileStats httpHeaderPerfStats; + +static const Parameter hh_params[] = +{ + { "*name", Parameter::PT_STRING, nullptr, nullptr, + "restrict to given header" }, + + { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr } +}; + +//------------------------------------------------------------------------- +// module +//------------------------------------------------------------------------- + +class HttpHeaderModule : public Module +{ +public: + HttpHeaderModule() : Module(s_name, hh_params) { }; + + bool begin(const char*, int, SnortConfig*); + bool set(const char*, Value&, SnortConfig*); + + ProfileStats* get_profile() const + { return &httpHeaderPerfStats; }; + +public: + string name; +}; + +bool HttpHeaderModule::begin(const char*, int, SnortConfig*) +{ + name.clear(); + return true; +} + +bool HttpHeaderModule::set(const char*, Value& v, SnortConfig*) +{ + if ( v.is("*name") ) + name = v.get_string(); + + else + return false; + + return true; +} + +//------------------------------------------------------------------------- +// generic header getter +//------------------------------------------------------------------------- + +class HttpHeaderOption : public IpsOption +{ +public: + HttpHeaderOption(string& s) : IpsOption(s_name) + { name = s; }; + + CursorActionType get_cursor_type() const + { return CAT_SET_OTHER; }; + + int eval(Cursor&, Packet*); + +private: + string name; +}; + +static bool find( + const string& s, const InspectionBuffer& b, Cursor& c) +{ + const char* h = s.c_str(); + unsigned k = s.size(); + + const uint8_t* t = b.data; + unsigned n = b.len; + + // find the start of header + do + { + if ( n < k ) + return false; + + if ( !strncasecmp(h, (char*)t, k) ) + break; + + t = (uint8_t*)memchr(t, '\n', n); + + if ( !t ) + return false; + + n = b.len - (++t - b.data); + } + while ( true ); + + // now find the end of header + const uint8_t* z = (uint8_t*)memchr(t, '\n', n); + + if ( z ) + { + while ( isspace(z[-1]) && (z > t) ) + --z; + n = z - t; + } + c.set(h, t, n); + return true; +} + +int HttpHeaderOption::eval(Cursor& c, Packet* p) +{ + PROFILE_VARS; + MODULE_PROFILE_START(httpHeaderPerfStats); + + int rval; + InspectionBuffer hb; + + if ( !p->flow || !p->flow->gadget ) + rval = DETECTION_OPTION_NO_MATCH; + + // FIXIT cache id at parse time for runtime use + else if ( !p->flow->gadget->get_buf(s_name, p, hb) ) + rval = DETECTION_OPTION_NO_MATCH; + + else if ( !name.size() ) + { + c.set(s_name, hb.data, hb.len); + rval = DETECTION_OPTION_MATCH; + } + else if ( find(name, hb, c) ) + rval = DETECTION_OPTION_MATCH; + + else + rval = DETECTION_OPTION_NO_MATCH; + + MODULE_PROFILE_END(httpHeaderPerfStats); + return rval; +} + +//------------------------------------------------------------------------- +// api +//------------------------------------------------------------------------- + +static Module* mod_ctor() +{ + return new HttpHeaderModule; +} + +static void mod_dtor(Module* m) +{ + delete m; +} + +static IpsOption* hh_ctor(Module* m, OptTreeNode*) +{ + HttpHeaderModule* mod = (HttpHeaderModule*)m; + return new HttpHeaderOption(mod->name); +} + +static void hh_dtor(IpsOption* p) +{ + delete p; +} + +static const IpsApi header_api = +{ + { + PT_IPS_OPTION, + s_name, + IPSAPI_PLUGIN_V0, + 0, + mod_ctor, + mod_dtor + }, + OPT_TYPE_DETECTION, + 1, PROTO_BIT__TCP, + nullptr, + nullptr, + nullptr, + nullptr, + hh_ctor, + hh_dtor, + nullptr +}; + +#ifdef BUILDING_SO +SO_PUBLIC const BaseApi* snort_plugins[] = +{ + &header_api.base, + nullptr +}; +#else +const BaseApi* ips_http_header = &header_api.base; +#endif +