From: Vitalii Date: Fri, 15 Jul 2022 14:54:43 +0000 (+0300) Subject: snort2lua: change the conversion of sensitive data rules X-Git-Tag: 3.1.38.0~6 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=906c728503e922884c81bd4766700fc25ea79d54;p=thirdparty%2Fsnort3.git snort2lua: change the conversion of sensitive data rules --- diff --git a/tools/snort2lua/helpers/s2l_util.cc b/tools/snort2lua/helpers/s2l_util.cc index 2ecf5dd7c..6a016ea12 100644 --- a/tools/snort2lua/helpers/s2l_util.cc +++ b/tools/snort2lua/helpers/s2l_util.cc @@ -124,10 +124,10 @@ std::string& trim(std::string& s) std::string& trim_quotes(std::string& s) { - if(s.length() < 2) + if (s.length() < 2) return s; - if((s.front() == '"' and s.back() == '"') or + if ((s.front() == '"' and s.back() == '"') or (s.front() == '\'' and s.back() == '\'')) { s.erase(0,1); @@ -224,7 +224,7 @@ bool get_string(std::istringstream& stream, } } -std::string get_remain_data(std::istringstream& stream) +std::string get_remain_data(std::istringstream& stream, bool trim) { // get string length const std::streamoff pos = stream.tellg(); @@ -238,10 +238,24 @@ std::string get_remain_data(std::istringstream& stream) arg_c[length] = '\0'; std::string arg_s(arg_c); delete[] arg_c; - util::trim(arg_s); + + if (trim) + util::trim(arg_s); + return arg_s; } +static bool is_semicolon_escaped(const std::string& args) +{ + unsigned bs_count = 0; + + for (auto sym_it = args.rbegin(); + sym_it != args.rend() and *sym_it == '\\'; + ++sym_it, ++bs_count); + + return bs_count % 2; +} + std::string get_rule_option_args(std::istringstream& stream) { std::string args = std::string(); @@ -251,12 +265,12 @@ std::string get_rule_option_args(std::istringstream& stream) { std::getline(stream, tmp, ';'); + args += tmp + ";"; + if (tmp.empty()) break; - - args += tmp + ";"; } - while (tmp.back() == '\\'); + while (is_semicolon_escaped(tmp)); // semicolon will be added when printing if (!args.empty()) diff --git a/tools/snort2lua/helpers/s2l_util.h b/tools/snort2lua/helpers/s2l_util.h index 8145e9d02..9c8a17edd 100644 --- a/tools/snort2lua/helpers/s2l_util.h +++ b/tools/snort2lua/helpers/s2l_util.h @@ -82,8 +82,16 @@ bool get_string(std::istringstream& data_stream, * characters which can get removed by c++ libraries * * NO SIDE EFFECTS + * + * PARAMS: + * data_stream - the rule's data stream + * trim - specifies whether to trim the result string + * RETURN: + * a string containing all the data left in the rule's + * data stream + * */ -std::string get_remain_data(std::istringstream& data_stream); +std::string get_remain_data(std::istringstream& data_stream, bool trim = true); std::string get_rule_option_args(std::istringstream& data_stream); diff --git a/tools/snort2lua/rule_states/rule_gid_sid.cc b/tools/snort2lua/rule_states/rule_gid_sid.cc index 18a1c4da7..722cf2f32 100644 --- a/tools/snort2lua/rule_states/rule_gid_sid.cc +++ b/tools/snort2lua/rule_states/rule_gid_sid.cc @@ -26,6 +26,7 @@ // Handle 2 cases: sid was read before/after gid. #include +#include #include "conversion_state.h" #include "helpers/converter.h" @@ -40,6 +41,12 @@ namespace static const std::string removed_gids[] = { "146" , "147" }; constexpr uint8_t MAX_GIDS = (sizeof(removed_gids) / sizeof(removed_gids[0])); +// first -> gid, second -> error message +static const std::unordered_map rejected_gids = +{ + {"138", "gid 138(sensitive data) rules should be written with Snort3 functionality in mind"} +}; + class Gid : public ConversionState { public: @@ -100,6 +107,12 @@ bool Gid::convert(std::istringstream& data_stream) } } rule_api.add_option("gid", gid); + + auto reject_it = rejected_gids.find(gid); + + if ( reject_it != rejected_gids.end() ) + rule_api.bad_rule(data_stream, reject_it->second); + return set_next_rule_state(data_stream); } diff --git a/tools/snort2lua/rule_states/rule_sd_pattern.cc b/tools/snort2lua/rule_states/rule_sd_pattern.cc index c33a48f95..cc108909f 100644 --- a/tools/snort2lua/rule_states/rule_sd_pattern.cc +++ b/tools/snort2lua/rule_states/rule_sd_pattern.cc @@ -34,26 +34,109 @@ class SDPattern : public ConversionState public: SDPattern(Converter& c) : ConversionState(c) { } bool convert(std::istringstream& data) override; +private: + std::string convert_pattern(const std::string& pattern); }; } // namespace -bool SDPattern::convert(std::istringstream& stream) +std::string SDPattern::convert_pattern(const std::string& pattern) { - std::string count; - std::string pattern; + const std::string unused_pcre_tokens("()[].+*^$|"); + + std::string s3_pattern; + + for (unsigned i = 0; i < pattern.size(); ++i) + { + char sym = pattern[i]; + + switch (sym) + { + case '\\': + { + if (i + 1 < pattern.size()) + sym = pattern[++i]; + else + { + // if backslash placed at the end of the pattern + // Snort2 will process it as a usual symbol + s3_pattern.append("\\\\"); + break; + } + + switch (sym) + { + case 'l': + s3_pattern.append("\\p{L}"); + break; + + case 'L': + s3_pattern.append("[^\\p{L}]"); + break; + + case 'w': + case 'W': + case 'd': + case 'D': + case '\\': + case '{': + case '}': + case '?': + s3_pattern.push_back('\\'); + s3_pattern.push_back(sym); + break; + + default: + // Snort2 ignores unknown escape sequences + break; + } + + break; + } + + case '{': + case '}': + case '?': + s3_pattern.push_back(sym); + break; + + default: + if (unused_pcre_tokens.find(sym) != std::string::npos) + s3_pattern.push_back('\\'); + s3_pattern.push_back(sym); + break; + } + } + + return s3_pattern; +} +bool SDPattern::convert(std::istringstream& stream) +{ std::string args = util::get_rule_option_args(stream); std::istringstream arg_stream(args); - if ( !util::get_string(arg_stream, count, ",") - || !util::get_string(arg_stream, pattern, ",")) + std::string count; + + if ( !util::get_string(arg_stream, count, ",") ) { - rule_api.bad_rule(stream, "sd_pattern missing arguments"); + rule_api.bad_rule(stream, "sd_pattern missing threshold argument"); return set_next_rule_state(stream); } - rule_api.add_option("sd_pattern", "\"" + pattern + "\""); + std::string pattern = util::get_remain_data(arg_stream, false); + + if ( pattern.empty() ) + { + rule_api.bad_rule(stream, "sd_pattern missing pattern argument"); + return set_next_rule_state(stream); + } + + std::string s3_pattern = convert_pattern(pattern); + + rule_api.add_option("sd_pattern", "\"" + s3_pattern + "\""); rule_api.add_suboption("threshold", count); + rule_api.bad_rule(stream, "sd_pattern: rules should be written with Snort3 " + "functionality in mind"); return set_next_rule_state(stream); }