diff --git a/src/detections/rule/matchers.rs b/src/detections/rule/matchers.rs index c3c267ce..f26dd327 100644 --- a/src/detections/rule/matchers.rs +++ b/src/detections/rule/matchers.rs @@ -72,14 +72,12 @@ impl LeafMatcher for MinlengthMatcher { /// 正規表現のリストが記載されたファイルを読み取って、比較するロジックを表すクラス /// DeepBlueCLIのcheck_cmdメソッドの一部に同様の処理が実装されていた。 pub struct RegexesFileMatcher { - regexes_csv_content: Vec, + regexes: Vec, } impl RegexesFileMatcher { pub fn new() -> RegexesFileMatcher { - return RegexesFileMatcher { - regexes_csv_content: vec![], - }; + return RegexesFileMatcher { regexes: vec![] }; } } @@ -107,11 +105,15 @@ impl LeafMatcher for RegexesFileMatcher { return Result::Err(vec![errmsg]); } - let regexes_csv_content = utils::read_txt(&value.unwrap()); - if regexes_csv_content.is_err() { - return Result::Err(vec![regexes_csv_content.unwrap_err()]); + let regexes_strs = utils::read_txt(&value.unwrap()); + if regexes_strs.is_err() { + return Result::Err(vec![regexes_strs.unwrap_err()]); } - self.regexes_csv_content = regexes_csv_content.unwrap(); + let regexes_strs = regexes_strs.unwrap(); + self.regexes = regexes_strs + .into_iter() + .map(|regex_str| Regex::new(®ex_str).unwrap()) + .collect(); return Result::Ok(()); } @@ -119,8 +121,8 @@ impl LeafMatcher for RegexesFileMatcher { fn is_match(&self, event_value: Option<&Value>) -> bool { //TODO Wildcardの場合、CaseInsensitiveなので、ToLowerする。 return match event_value.unwrap_or(&Value::Null) { - Value::String(s) => !utils::check_regex(s, &self.regexes_csv_content), - Value::Number(n) => !utils::check_regex(&n.to_string(), &self.regexes_csv_content), + Value::String(s) => !utils::check_regex(s, &self.regexes), + Value::Number(n) => !utils::check_regex(&n.to_string(), &self.regexes), _ => false, }; } @@ -129,14 +131,12 @@ impl LeafMatcher for RegexesFileMatcher { /// ファイルに列挙された文字列に一致する場合に検知するロジックを表す /// DeepBlueCLIのcheck_cmdメソッドの一部に同様の処理が実装されていた。 pub struct AllowlistFileMatcher { - allowlist_csv_content: Vec, + regexes: Vec, } impl AllowlistFileMatcher { pub fn new() -> AllowlistFileMatcher { - return AllowlistFileMatcher { - allowlist_csv_content: vec![], - }; + return AllowlistFileMatcher { regexes: vec![] }; } } @@ -164,22 +164,24 @@ impl LeafMatcher for AllowlistFileMatcher { return Result::Err(vec![errmsg]); } - let allowlist_content = utils::read_txt(&value.unwrap()); - if allowlist_content.is_err() { - return Result::Err(vec![allowlist_content.unwrap_err()]); + let regexes_strs = utils::read_txt(&value.unwrap()); + if regexes_strs.is_err() { + return Result::Err(vec![regexes_strs.unwrap_err()]); } - self.allowlist_csv_content = allowlist_content.unwrap(); + self.regexes = regexes_strs + .unwrap() + .into_iter() + .map(|regex_str| Regex::new(®ex_str).unwrap()) + .collect(); return Result::Ok(()); } fn is_match(&self, event_value: Option<&Value>) -> bool { return match event_value.unwrap_or(&Value::Null) { - Value::String(s) => !utils::check_allowlist(s, &self.allowlist_csv_content), - Value::Number(n) => { - !utils::check_allowlist(&n.to_string(), &self.allowlist_csv_content) - } - Value::Bool(b) => !utils::check_allowlist(&b.to_string(), &self.allowlist_csv_content), + Value::String(s) => !utils::check_allowlist(s, &self.regexes), + Value::Number(n) => !utils::check_allowlist(&n.to_string(), &self.regexes), + Value::Bool(b) => !utils::check_allowlist(&b.to_string(), &self.regexes), _ => true, }; } @@ -651,15 +653,15 @@ mod tests { .unwrap(); // regexes.txtの中身と一致していることを確認 - let csvcontent = &ancestor_matcher.regexes_csv_content; + let csvcontent = &ancestor_matcher.regexes; + assert_eq!(csvcontent.len(), 17); assert_eq!( - csvcontent[0], + csvcontent[0].as_str().to_string(), r"^cmd.exe /c echo [a-z]{6} > \\\\.\\pipe\\[a-z]{6}$" ); - assert_eq!( - csvcontent[14], + csvcontent[14].as_str().to_string(), r"\\cvtres\.exe.*\\AppData\\Local\\Temp\\[A-Z0-9]{7}\.tmp" ); } @@ -678,15 +680,15 @@ mod tests { .downcast_ref::() .unwrap(); - let csvcontent = &ancestor_matcher.allowlist_csv_content; + let csvcontent = &ancestor_matcher.regexes; assert_eq!(csvcontent.len(), 2); assert_eq!( - csvcontent[0], + csvcontent[0].as_str().to_string(), r#"^"C:\\Program Files\\Google\\Chrome\\Application\\chrome\.exe""#.to_string() ); assert_eq!( - csvcontent[1], + csvcontent[1].as_str().to_string(), r#"^"C:\\Program Files\\Google\\Update\\GoogleUpdate\.exe""#.to_string() ); } diff --git a/src/detections/utils.rs b/src/detections/utils.rs index 7e27a9f6..202e7410 100644 --- a/src/detections/utils.rs +++ b/src/detections/utils.rs @@ -24,14 +24,9 @@ pub fn concat_selection_key(key_list: &Vec) -> String { }); } -pub fn check_regex(string: &str, regex_list: &Vec) -> bool { - for line in regex_list { - if line.is_empty() { - continue; - } - - let re = Regex::new(line); - if re.is_err() || re.unwrap().is_match(string) == false { +pub fn check_regex(string: &str, regex_list: &Vec) -> bool { + for regex in regex_list { + if regex.is_match(string) == false { continue; } @@ -41,14 +36,9 @@ pub fn check_regex(string: &str, regex_list: &Vec) -> bool { return false; } -pub fn check_allowlist(target: &str, allowlist: &Vec) -> bool { - for line in allowlist { - if line.is_empty() { - continue; - } - - let r = Regex::new(line); - if r.is_ok() && r.unwrap().is_match(target) { +pub fn check_allowlist(target: &str, regexes: &Vec) -> bool { + for regex in regexes { + if regex.is_match(target) { return true; } } @@ -159,9 +149,15 @@ pub fn create_tokio_runtime() -> Runtime { #[cfg(test)] mod tests { use crate::detections::utils; + use regex::Regex; + #[test] fn test_check_regex() { - let regexes = utils::read_txt("regexes.txt").unwrap(); + let regexes = utils::read_txt("regexes.txt") + .unwrap() + .into_iter() + .map(|regex_str| Regex::new(®ex_str).unwrap()) + .collect(); let regextext = utils::check_regex("\\cvtres.exe", ®exes); assert!(regextext == true); @@ -172,7 +168,11 @@ mod tests { #[test] fn test_check_allowlist() { let commandline = "\"C:\\Program Files\\Google\\Update\\GoogleUpdate.exe\""; - let allowlist = utils::read_txt("allowlist.txt").unwrap(); + let allowlist = utils::read_txt("allowlist.txt") + .unwrap() + .into_iter() + .map(|allow_str| Regex::new(&allow_str).unwrap()) + .collect(); assert!(true == utils::check_allowlist(commandline, &allowlist)); let commandline = "\"C:\\Program Files\\Google\\Update\\GoogleUpdate2.exe\"";