===== normalize_javascript
-normalize_javascript = true will enable normalization of JavaScript within
+normalize_javascript = true will enable legacy normalizer of JavaScript within
the HTTP response body. http_inspect looks for JavaScript by searching for
the <script> tag without a type. Obfuscated data within the JavaScript
functions such as unescape, String.fromCharCode, decodeURI, and
decodeURIComponent are normalized. The different encodings handled within
the unescape, decodeURI, or decodeURIComponent are %XX, %uXXXX, XX and
uXXXXi. http_inspect also replaces consecutive whitespaces with a single
-space and normalizes the plus by concatenating the strings.
-Such normalizations refer to basic JavaScript normalization.
-
-===== normalization_depth
-
-normalization_depth = N {-1 : 65535} will set a number of input JavaScript
-bytes to normalize and enable the whitespace normalizer instead of the
-basic one. Meanwhile, normalize_javascript = true must be configured as
-well. When the depth is reached, normalization will be stopped. It's
-implemented per-script. normalization_depth = -1 will configure max depth
-value. By default, the value is set to 0. Configure this option to enable
-more precise whitespace normalization of JavaScript, that removes all
-redundant whitespaces and line terminators from the JavaScript syntax point
-of view (between identifier and punctuator, between identifier and operator,
-etc.) according to ECMAScript 5.1 standard.
+space and normalizes the plus by concatenating the strings. Such normalizations
+refer to basic JavaScript normalization. Сannot be used together with
+js_normalization_depth (doing so will cause Snort to fail to load). This is
+planned to be deprecated at some point.
+
+===== js_normalization_depth
+
+js_normalization_depth = N {-1 : 2ˆ53} will set a number of input
+JavaScript bytes to normalize and enable the enhanced normalizer. The enhanced
+and legacy normalizers have mutual exclusion behaviour, so you cannot enable
+both at the same time (doing so will cause Snort to fail to load). When the
+depth is reached, normalization will be stopped. It's implemented per-script.
+js_normalization_depth = -1, will set the max allowed depth value. By default,
+the value is set to 0 which means that normalizer is disabled. The enhanced
+normalizer provides more precise whitespace normalization of JavaScript, that
+removes all redundant whitespaces and line terminators from the JavaScript
+syntax point of view (between identifier and punctuator, between identifier and
+operator, etc.) according to ECMAScript 5.1 standard. This is currently
+experimental and still under development.
===== xff_headers
===== file_data
-file_data contains the normalized message body. This is the normalization
-described above under gzip, normalize_utf, decompress_pdf, decompress_swf,
-and normalize_javascript.
+The file_data contains the normalized message body. This is the normalization
+described above under gzip, normalize_utf, decompress_pdf, decompress_swf, and
+normalize_javascript.
+
+===== script_data
+
+The script_data ips option is used as sticky buffer and contains only the
+normalized JavaScript HTTP response body without 'script' tags. In scope of
+rules the script_data option takes place with enabled new enhanced normalizer,
+so it is used in combination with http_inspect = { js_normalization_depth = N }.
+The js_normalization_depth option is described above. In rules the script_data
+can be used with file_data option where file_data would contain the whole HTTP
+response body for content matching.
==== Timing issues and combining rule options
DetectionEngine::DetectionEngine()
{
context = Analyzer::get_switcher()->interrupt();
- context->file_data = { nullptr, 0 };
+
+ context->file_data = DataPointer(nullptr, 0);
+ context->script_data = DataPointer(nullptr, 0);
+
reset();
}
DataPointer& DetectionEngine::get_file_data(IpsContext* c)
{ return c->file_data; }
+void DetectionEngine::set_script_data(const DataPointer& dp)
+{ Analyzer::get_switcher()->get_context()->script_data = dp; }
+
+DataPointer& DetectionEngine::get_script_data(IpsContext* c)
+{ return c->script_data; }
+
void DetectionEngine::set_data(unsigned id, IpsContextData* p)
{ Analyzer::get_switcher()->get_context()->set_context_data(id, p); }
static void set_file_data(const DataPointer& dp);
static DataPointer& get_file_data(IpsContext*);
+ static void set_script_data(const DataPointer& dp);
+ static DataPointer& get_script_data(IpsContext*);
+
static uint8_t* get_buffer(unsigned& max);
static struct DataBuffer& get_alt_buffer(Packet*);
static inline void clear_file_data()
{ set_file_data(nullptr, 0); }
+static inline void set_script_data(const uint8_t* data, unsigned len)
+{
+ DataPointer dp { data, len };
+ DetectionEngine::set_script_data(dp);
+}
+
+static inline void clear_script_data()
+{ set_script_data(nullptr, 0); }
+
} // namespace snort
#endif
struct DataPointer
{
+ DataPointer(const uint8_t* d, unsigned l) :
+ data(d), len(l) {}
const uint8_t* data;
unsigned len;
};
search_buffer(
gadget, buf, buf.IBT_COOKIE, p, port_group, PM_TYPE_COOKIE, pc.cookie_searches);
}
+
+ if ( MpseGroup* so = port_group->mpsegrp[PM_TYPE_SCRIPT] )
{
- // file searches file only
- if ( MpseGroup* so = port_group->mpsegrp[PM_TYPE_FILE] )
+ // FIXIT-M script data should be obtained from
+ // inspector gadget as is done with search_buffer
+ DataPointer script_data = p->context->script_data;
+
+ if ( script_data.len )
{
- // FIXIT-M file data should be obtained from
- // inspector gadget as is done with search_buffer
- DataPointer file_data = p->context->file_data;
+ debug_logf(detection_trace, TRACE_FP_SEARCH, p,
+ "%" PRIu64 " fp search %s[%d]\n", p->context->packet_number,
+ pm_type_strings[PM_TYPE_SCRIPT], script_data.len);
- if ( file_data.len )
- {
- debug_logf(detection_trace, TRACE_FP_SEARCH, p,
- "%" PRIu64 " fp search %s[%d]\n", p->context->packet_number,
- pm_type_strings[PM_TYPE_FILE], file_data.len);
+ batch_search(so, p, script_data.data, script_data.len, pc.script_searches);
+ }
+ }
- batch_search(so, p, file_data.data, file_data.len, pc.file_searches);
- }
+ // file searches file only
+ if ( MpseGroup* so = port_group->mpsegrp[PM_TYPE_FILE] )
+ {
+ // FIXIT-M file data should be obtained from
+ // inspector gadget as is done with search_buffer
+ DataPointer file_data = p->context->file_data;
+
+ if ( file_data.len )
+ {
+ debug_logf(detection_trace, TRACE_FP_SEARCH, p,
+ "%" PRIu64 " fp search %s[%d]\n", p->context->packet_number,
+ pm_type_strings[PM_TYPE_FILE], file_data.len);
+
+ batch_search(so, p, file_data.data, file_data.len, pc.file_searches);
}
}
+
return 0;
}
case CAT_SET_COOKIE:
return PM_TYPE_COOKIE;
+ case CAT_SET_SCRIPT:
+ return PM_TYPE_SCRIPT;
+
case CAT_SET_STAT_MSG:
return PM_TYPE_STAT_MSG;
{
std::string svc;
bool file = false;
+ bool script = false;
for (OptFpList* ofl = otn->opt_func; ofl; ofl = ofl->next)
{
continue;
}
+ if ( !strcmp(s, "script_data") )
+ {
+ script = true;
+ continue;
+ }
+
s = get_service(s);
if ( !s )
{
ParseWarning(WARN_RULES, "%u:%u:%u has no service with file_data",
otn->sigInfo.gid, otn->sigInfo.sid, otn->sigInfo.rev);
-
add_service_to_otn(sc, otn, "file");
}
+ if ( otn->sigInfo.services.empty() and script )
+ {
+ ParseWarning(WARN_RULES, "%u:%u:%u has no service with script_data",
+ otn->sigInfo.gid, otn->sigInfo.sid, otn->sigInfo.rev);
+ add_service_to_otn(sc, otn, "http");
+ }
}
PatternMatchVector get_fp_content(
std::list<RegexRequest*>::iterator regex_req_it;
SF_EVENTQ* equeue;
- DataPointer file_data = {};
+ DataPointer file_data = DataPointer(nullptr, 0);
+ DataPointer script_data = DataPointer(nullptr, 0);
DataBuffer alt_data = {};
uint64_t context_num;
CAT_SET_OTHER,
CAT_SET_RAW,
CAT_SET_COOKIE,
+ CAT_SET_SCRIPT,
CAT_SET_STAT_MSG,
CAT_SET_STAT_CODE,
CAT_SET_METHOD,
ips_rem.cc
ips_rev.cc
ips_rpc.cc
+ ips_script_data.cc
ips_seq.cc
ips_sid.cc
ips_soid.cc
ips_pkt_data.cc
ips_reference.cc
ips_replace.cc
+ ips_script_data.cc
ips_service.cc
ips_so.cc
)
extern const BaseApi* ips_pkt_data;
extern const BaseApi* ips_reference;
extern const BaseApi* ips_replace;
+extern const BaseApi* ips_script_data;
extern const BaseApi* ips_service;
extern const BaseApi* ips_sha256;
extern const BaseApi* ips_sha512;
ips_pkt_data,
ips_reference,
ips_replace,
+ ips_script_data,
ips_service,
ips_sha256,
ips_sha512,
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2021-2021 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_script_data.cc author Serhii Vlasiuk <svlasiuk@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "detection/detection_engine.h"
+#include "framework/cursor.h"
+#include "framework/ips_option.h"
+#include "framework/module.h"
+#include "profiler/profiler.h"
+
+using namespace snort;
+
+#define s_name "script_data"
+#define s_help \
+ "rule option to set detection cursor to normalized script data"
+
+static THREAD_LOCAL ProfileStats scriptDataPerfStats;
+
+class ScriptDataOption : public IpsOption
+{
+public:
+ ScriptDataOption() : IpsOption(s_name, RULE_OPTION_TYPE_BUFFER_SET) { }
+
+ CursorActionType get_cursor_type() const override
+ { return CAT_SET_SCRIPT; }
+
+ EvalStatus eval(Cursor&, Packet*) override;
+};
+
+IpsOption::EvalStatus ScriptDataOption::eval(Cursor& c, Packet* p)
+{
+ RuleProfile profile(scriptDataPerfStats);
+
+ DataPointer dp = DetectionEngine::get_script_data(p->context);
+
+ if ( !dp.data or !dp.len )
+ return NO_MATCH;
+
+ c.set(s_name, dp.data, dp.len);
+
+ return MATCH;
+}
+
+//-------------------------------------------------------------------------
+// module
+//-------------------------------------------------------------------------
+
+class ScriptDataModule : public Module
+{
+public:
+ ScriptDataModule() : Module(s_name, s_help) { }
+
+ ProfileStats* get_profile() const override
+ { return &scriptDataPerfStats; }
+
+ Usage get_usage() const override
+ { return DETECT; }
+};
+
+//-------------------------------------------------------------------------
+// api methods
+//-------------------------------------------------------------------------
+
+static Module* mod_ctor()
+{
+ return new ScriptDataModule;
+}
+
+static void mod_dtor(Module* m)
+{
+ delete m;
+}
+
+static IpsOption* script_data_ctor(Module*, OptTreeNode*)
+{
+ return new ScriptDataOption;
+}
+
+static void script_data_dtor(IpsOption* p)
+{
+ delete p;
+}
+
+static const IpsApi script_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,
+ script_data_ctor,
+ script_data_dtor,
+ nullptr
+};
+
+#ifdef BUILDING_SO
+SO_PUBLIC const BaseApi* snort_plugins[] =
+#else
+const BaseApi* ips_script_data[] =
+#endif
+{
+ &script_data_api.base,
+ nullptr
+};
+
if ( !(p->packet_flags & PKT_IGNORE) )
{
clear_file_data();
+ clear_script_data();
// return incomplete status if the main hook indicates not all work was done
if (!main_hook(p))
return false;
void DetectionEngine::reset() { }
void DetectionEngine::wait_for_context() { }
void DetectionEngine::set_file_data(const DataPointer&) { }
+void DetectionEngine::set_script_data(const DataPointer&) { }
void DetectionEngine::clear_replacement() { }
void DetectionEngine::disable_all(Packet*) { }
unsigned get_instance_id() { return 0; }
PM_TYPE_RAW_KEY,
PM_TYPE_RAW_HEADER,
PM_TYPE_METHOD,
+ PM_TYPE_SCRIPT,
PM_TYPE_STAT_CODE,
PM_TYPE_STAT_MSG,
PM_TYPE_COOKIE,
const char* const pm_type_strings[PM_TYPE_MAX] =
{
"packet", "alt", "key", "header", "body", "file", "raw_key", "raw_header",
- "method", "stat_code", "stat_msg", "cookie"
+ "method", "script", "stat_code", "stat_msg", "cookie"
};
struct RULE_NODE
bool HttpInspect::configure(SnortConfig* )
{
- if (params->js_norm_param.normalize_javascript)
+ if ( params->js_norm_param.js_norm )
params->js_norm_param.js_norm->configure();
return true;
ConfigLogger::log_flag("normalize_javascript", params->js_norm_param.normalize_javascript);
ConfigLogger::log_value("max_javascript_whitespaces",
params->js_norm_param.max_javascript_whitespaces);
+ ConfigLogger::log_value("js_normalization_depth",
+ params->js_norm_param.js_normalization_depth);
ConfigLogger::log_value("bad_characters", bad_chars.c_str());
ConfigLogger::log_value("ignore_unreserved", unreserved_chars.c_str());
ConfigLogger::log_flag("percent_u", params->uri_param.percent_u);
using namespace HttpEnums;
using namespace snort;
-class JsNormBase
-{
-public:
- virtual ~JsNormBase() = default;
-
- virtual int normalize(const char*, uint16_t, char*, uint16_t, const char**, int*, JSState*,
- uint8_t*) = 0;
-
-};
-
-class UtilJsNorm : public JsNormBase
-{
-public:
- UtilJsNorm() : JsNormBase() {}
-
-protected:
- virtual int normalize(const char* src, uint16_t srclen, char* dst, uint16_t destlen,
- const char** ptr, int* bytes_copied, JSState* js, uint8_t* iis_unicode_map) override
- {
- return JSNormalizeDecode(src, srclen, dst, destlen, ptr, bytes_copied, js, iis_unicode_map);
- }
-
-};
-
-class JsNorm : public JsNormBase
-{
-public:
- JsNorm(int normalization_depth)
- : JsNormBase(),
- norm_depth(normalization_depth)
- {}
-
-protected:
- virtual int normalize(const char* src, uint16_t srclen, char* dst, uint16_t destlen,
- const char** ptr, int* bytes_copied, JSState*, uint8_t*) override
- {
- return JSNormalizer::normalize(src, srclen, dst, destlen, ptr, bytes_copied, norm_depth);
- }
-
-private:
- int norm_depth;
-
-};
-
-HttpJsNorm::HttpJsNorm(int max_javascript_whitespaces_, const HttpParaList::UriParam& uri_param_,
- int normalization_depth) :
- normalizer(nullptr), max_javascript_whitespaces(max_javascript_whitespaces_),
- uri_param(uri_param_), normalization_depth(normalization_depth),
- javascript_search_mpse(nullptr), htmltype_search_mpse(nullptr)
+HttpJsNorm::HttpJsNorm(const HttpParaList::UriParam& uri_param_) :
+ uri_param(uri_param_), javascript_search_mpse(nullptr),
+ htmltype_search_mpse(nullptr)
{}
HttpJsNorm::~HttpJsNorm()
{
- delete normalizer;
delete javascript_search_mpse;
delete htmltype_search_mpse;
}
if ( configure_once )
return;
- // Based on this option configuration, default or whitespace normalizer will be initialized
- // normalization_depth = 0 means to initialize default normalizer
- // normalization_depth != 0 means to initialize whitespace normalizer with specified depth
- if ( normalization_depth != 0 )
- normalizer = new JsNorm(normalization_depth);
- else
- normalizer = new UtilJsNorm;
-
javascript_search_mpse = new SearchTool;
htmltype_search_mpse = new SearchTool;
configure_once = true;
}
-void HttpJsNorm::normalize(const Field& input, Field& output, HttpInfractions* infractions,
- HttpEventGen* events) const
+void HttpJsNorm::enhanced_normalize(const Field& input, Field& output,
+ int64_t js_normalization_depth) const
+{
+ bool js_present = false;
+ int index = 0;
+ const char* ptr = (const char*)input.start();
+ const char* const end = ptr + input.length();
+
+ uint8_t* buffer = new uint8_t[input.length()];
+
+ while (ptr < end)
+ {
+ int bytes_copied = 0;
+ int mindex;
+
+ // Search for beginning of a javascript
+ if (javascript_search_mpse->find(ptr, end-ptr, search_js_found, false, &mindex) > 0)
+ {
+ const char* js_start = ptr + mindex;
+ const char* const angle_bracket =
+ (const char*)SnortStrnStr(js_start, end - js_start, ">");
+ if (angle_bracket == nullptr || (end - angle_bracket) == 0)
+ break;
+
+ bool type_js = false;
+ if (angle_bracket > js_start)
+ {
+ int mid;
+ const int script_found = htmltype_search_mpse->find(
+ js_start, (angle_bracket-js_start), search_html_found, false, &mid);
+
+ js_start = angle_bracket + 1;
+ if (script_found > 0)
+ {
+ switch (mid)
+ {
+ case HTML_JS:
+ js_present = true;
+ type_js = true;
+ break;
+ default:
+ type_js = false;
+ break;
+ }
+ }
+ else
+ {
+ // if no type or language is found we assume it is a javascript
+ js_present = true;
+ type_js = true;
+ }
+ }
+ // Save before the <script> begins
+ if (js_start > ptr)
+ {
+ if ((js_start - ptr) > (input.length() - index))
+ break;
+ }
+
+ ptr = js_start;
+ if (!type_js)
+ continue;
+
+ JSNormalizer::normalize(js_start, (uint16_t)(end-js_start), (char*)buffer+index,
+ (uint16_t)(input.length() - index), &ptr, &bytes_copied, js_normalization_depth);
+
+ index += bytes_copied;
+ }
+ else
+ break;
+ }
+
+ if (js_present)
+ output.set(index, buffer, true);
+ else
+ delete[] buffer;
+}
+
+void HttpJsNorm::legacy_normalize(const Field& input, Field& output, HttpInfractions* infractions,
+ HttpEventGen* events, int max_javascript_whitespaces) const
{
bool js_present = false;
int index = 0;
if (!type_js)
continue;
- normalizer->normalize(js_start, (uint16_t)(end-js_start), (char*)buffer+index,
+ JSNormalizeDecode(js_start, (uint16_t)(end-js_start), (char*)buffer+index,
(uint16_t)(input.length() - index), &ptr, &bytes_copied, &js,
uri_param.iis_unicode ? uri_param.unicode_map : nullptr);
// HttpJsNorm class
//-------------------------------------------------------------------------
-class JsNormBase;
-
class HttpJsNorm
{
public:
- HttpJsNorm(int max_javascript_whitespaces_, const HttpParaList::UriParam& uri_param_,
- int normalization_depth);
+ HttpJsNorm(const HttpParaList::UriParam& uri_param_);
~HttpJsNorm();
- void normalize(const Field& input, Field& output, HttpInfractions* infractions,
- HttpEventGen* events) const;
+ void legacy_normalize(const Field& input, Field& output, HttpInfractions* infractions,
+ HttpEventGen* events, int max_javascript_whitespaces) const;
+ void enhanced_normalize(const Field& input, Field& output,
+ int64_t js_normalization_depth) const;
+
void configure();
private:
bool configure_once = false;
- JsNormBase* normalizer;
-
enum JsSearchId { JS_JAVASCRIPT };
enum HtmlSearchId { HTML_JS, HTML_EMA, HTML_VB };
static constexpr const char* script_start = "<SCRIPT";
static constexpr int script_start_length = sizeof("<SCRIPT") - 1;
- const int max_javascript_whitespaces;
const HttpParaList::UriParam& uri_param;
- const int normalization_depth;
snort::SearchTool* javascript_search_mpse;
snort::SearchTool* htmltype_search_mpse;
"inspect JavaScript immediately upon script end" },
{ "normalize_javascript", Parameter::PT_BOOL, nullptr, "false",
- "normalize JavaScript in response bodies" },
+ "use legacy normalizer to normalize JavaScript in response bodies" },
- { "normalization_depth", Parameter::PT_INT, "-1:65535", "0",
- "number of input JavaScript bytes to normalize" },
+ { "js_normalization_depth", Parameter::PT_INT, "-1:max53", "0",
+ "number of input JavaScript bytes to normalize with enhanced normalizer "
+ "(-1 max allowed value) (experimental)" },
{ "max_javascript_whitespaces", Parameter::PT_INT, "1:65535", "200",
"maximum consecutive whitespaces allowed within the JavaScript obfuscated data" },
else if (val.is("normalize_javascript"))
{
params->js_norm_param.normalize_javascript = val.get_bool();
+
+ if ( !params->js_norm_param.is_javascript_normalization )
+ params->js_norm_param.is_javascript_normalization =
+ params->js_norm_param.normalize_javascript;
}
- else if (val.is("normalization_depth"))
+ else if (val.is("js_normalization_depth"))
{
- int v = val.get_int32();
- params->js_norm_param.normalization_depth = (v == -1) ? 65535 : v;
+ int64_t v = val.get_int64();
+ params->js_norm_param.js_normalization_depth = (v == -1) ?
+ Parameter::get_int("max53") : v;
+
+ if ( !params->js_norm_param.is_javascript_normalization )
+ params->js_norm_param.is_javascript_normalization =
+ (params->js_norm_param.js_normalization_depth > 0);
}
else if (val.is("max_javascript_whitespaces"))
{
params->uri_param.iis_unicode_map_file.c_str(),
params->uri_param.iis_unicode_code_page);
}
- if (params->js_norm_param.normalize_javascript)
- {
- params->js_norm_param.js_norm =
- new HttpJsNorm(params->js_norm_param.max_javascript_whitespaces, params->uri_param,
- params->js_norm_param.normalization_depth);
- }
+
+ if ( params->js_norm_param.normalize_javascript and
+ params->js_norm_param.js_normalization_depth )
+ ParseError("Cannot use normalize_javascript and js_normalization_depth together.");
+
+ if ( params->js_norm_param.is_javascript_normalization )
+ params->js_norm_param.js_norm = new HttpJsNorm(params->uri_param);
prepare_http_header_list(params);
public:
~JsNormParam();
bool normalize_javascript = false;
- int normalization_depth = 0;
+ bool is_javascript_normalization = false;
+ int64_t js_normalization_depth = 0;
int max_javascript_whitespaces = 200;
class HttpJsNorm* js_norm = nullptr;
};
const int32_t detect_length =
(js_norm_body.length() <= session_data->detect_depth_remaining[source_id]) ?
js_norm_body.length() : session_data->detect_depth_remaining[source_id];
+
detect_data.set(detect_length, js_norm_body.start());
delete[] partial_detect_buffer;
void HttpMsgBody::do_js_normalization(const Field& input, Field& output)
{
- if (!params->js_norm_param.normalize_javascript || source_id == SRC_CLIENT)
+ if ( !params->js_norm_param.is_javascript_normalization or source_id == SRC_CLIENT )
+ output.set(input);
+ else if ( params->js_norm_param.normalize_javascript )
+ params->js_norm_param.js_norm->legacy_normalize(input, output,
+ transaction->get_infractions(source_id), session_data->events[source_id],
+ params->js_norm_param.max_javascript_whitespaces);
+ else if ( params->js_norm_param.js_normalization_depth )
{
output.set(input);
- return;
- }
- params->js_norm_param.js_norm->normalize(input, output,
- transaction->get_infractions(source_id), session_data->events[source_id]);
+ params->js_norm_param.js_norm->enhanced_normalize(input, enhanced_js_norm_body,
+ params->js_norm_param.js_normalization_depth);
+
+ const int32_t norm_length =
+ (enhanced_js_norm_body.length() <= session_data->detect_depth_remaining[source_id]) ?
+ enhanced_js_norm_body.length() : session_data->detect_depth_remaining[source_id];
+
+ if ( norm_length > 0 )
+ set_script_data(enhanced_js_norm_body.start(), (unsigned int)norm_length);
+ }
}
void HttpMsgBody::do_file_processing(const Field& file_data)
Field cumulative_data;
Field js_norm_body;
Field detect_data;
+ Field enhanced_js_norm_body;
Field classic_client_body; // URI normalization applied
};
long HttpTestManager::print_amount {};
bool HttpTestManager::print_hex {};
-HttpJsNorm::HttpJsNorm(int, const HttpParaList::UriParam& uri_param_, int) :
- normalizer(nullptr), max_javascript_whitespaces(0), uri_param(uri_param_),
- normalization_depth(0), javascript_search_mpse(nullptr), htmltype_search_mpse(nullptr) {}
+HttpJsNorm::HttpJsNorm(const HttpParaList::UriParam& uri_param_) :
+ uri_param(uri_param_), javascript_search_mpse(nullptr), htmltype_search_mpse(nullptr) {}
HttpJsNorm::~HttpJsNorm() = default;
void HttpJsNorm::configure(){}
+int64_t Parameter::get_int(char const*) { return 0; }
TEST_GROUP(http_peg_count_test)
{
void show_stats(PegCount*, const PegInfo*, unsigned, const char*) { }
void show_stats(PegCount*, const PegInfo*, const IndexVec&, const char*, FILE*) { }
-HttpJsNorm::HttpJsNorm(int, const HttpParaList::UriParam& uri_param_, int) :
- normalizer(nullptr), max_javascript_whitespaces(0), uri_param(uri_param_),
- normalization_depth(0), javascript_search_mpse(nullptr), htmltype_search_mpse(nullptr) {}
+HttpJsNorm::HttpJsNorm(const HttpParaList::UriParam& uri_param_) :
+ uri_param(uri_param_), javascript_search_mpse(nullptr), htmltype_search_mpse(nullptr) {}
HttpJsNorm::~HttpJsNorm() = default;
void HttpJsNorm::configure() {}
+int64_t Parameter::get_int(char const*) { return 0; }
TEST_GROUP(http_inspect_uri_norm)
{
using namespace snort;
int JSNormalizer::normalize(const char* srcbuf, uint16_t srclen, char* dstbuf, uint16_t dstlen,
- const char** ptr, int* bytes_copied, int norm_depth)
+ const char** ptr, int* bytes_copied, int64_t norm_depth)
{
std::stringstream in, out;
{
public:
static int normalize(const char* srcbuf, uint16_t srclen, char* dstbuf, uint16_t dstlen,
- const char** ptr, int* bytes_copied, int norm_depth);
+ const char** ptr, int* bytes_copied, int64_t norm_depth);
};
}
{ CountType::SUM, "raw_key_searches", "fast pattern searches in raw key buffer" },
{ CountType::SUM, "raw_header_searches", "fast pattern searches in raw header buffer" },
{ CountType::SUM, "method_searches", "fast pattern searches in method buffer" },
+ { CountType::SUM, "script_searches", "fast pattern searches in script buffer" },
{ CountType::SUM, "stat_code_searches", "fast pattern searches in status code buffer" },
{ CountType::SUM, "stat_msg_searches", "fast pattern searches in status message buffer" },
{ CountType::SUM, "cookie_searches", "fast pattern searches in cookie buffer" },
PegCount raw_key_searches;
PegCount raw_header_searches;
PegCount method_searches;
+ PegCount script_searches;
PegCount stat_code_searches;
PegCount stat_msg_searches;
PegCount cookie_searches;