]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
snort2lua: change the conversion of sensitive data rules
authorVitalii <vhorbato@cisco.com>
Fri, 15 Jul 2022 14:54:43 +0000 (17:54 +0300)
committerVitalii <vhorbato@cisco.com>
Mon, 25 Jul 2022 12:35:10 +0000 (15:35 +0300)
tools/snort2lua/helpers/s2l_util.cc
tools/snort2lua/helpers/s2l_util.h
tools/snort2lua/rule_states/rule_gid_sid.cc
tools/snort2lua/rule_states/rule_sd_pattern.cc

index 2ecf5dd7c2b8df272766ce2907bc0ad97454a200..6a016ea12d302dad29e169ff7933f195e514dcd3 100644 (file)
@@ -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())
index 8145e9d02504322ddb803cbbc7e4dda1918cbef6..9c8a17eddeb0833255d4885559dd318c996ede1e 100644 (file)
@@ -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);
 
index 18a1c4da75479ef9f2ff079784658a3e7ed870c9..722cf2f3281bf136b276e6fcf958c8d8bb4ad5fa 100644 (file)
@@ -26,6 +26,7 @@
 // Handle 2 cases: sid was read before/after gid.
 
 #include <sstream>
+#include <unordered_map>
 
 #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<std::string, std::string> 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);
 }
 
index c33a48f950d71d1b26dea6dc3560bb6031f924d3..cc108909f868316879842934d43ecc439903c687 100644 (file)
@@ -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);
 }