cache regex for allowlist and regexes keyword. (#174)

This commit is contained in:
James
2021-11-10 03:10:03 +09:00
committed by GitHub
parent 1bdf6943ff
commit 15a28e5602
2 changed files with 50 additions and 48 deletions

View File

@@ -72,14 +72,12 @@ impl LeafMatcher for MinlengthMatcher {
/// 正規表現のリストが記載されたファイルを読み取って、比較するロジックを表すクラス /// 正規表現のリストが記載されたファイルを読み取って、比較するロジックを表すクラス
/// DeepBlueCLIのcheck_cmdメソッドの一部に同様の処理が実装されていた。 /// DeepBlueCLIのcheck_cmdメソッドの一部に同様の処理が実装されていた。
pub struct RegexesFileMatcher { pub struct RegexesFileMatcher {
regexes_csv_content: Vec<String>, regexes: Vec<Regex>,
} }
impl RegexesFileMatcher { impl RegexesFileMatcher {
pub fn new() -> RegexesFileMatcher { pub fn new() -> RegexesFileMatcher {
return RegexesFileMatcher { return RegexesFileMatcher { regexes: vec![] };
regexes_csv_content: vec![],
};
} }
} }
@@ -107,11 +105,15 @@ impl LeafMatcher for RegexesFileMatcher {
return Result::Err(vec![errmsg]); return Result::Err(vec![errmsg]);
} }
let regexes_csv_content = utils::read_txt(&value.unwrap()); let regexes_strs = utils::read_txt(&value.unwrap());
if regexes_csv_content.is_err() { if regexes_strs.is_err() {
return Result::Err(vec![regexes_csv_content.unwrap_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(&regex_str).unwrap())
.collect();
return Result::Ok(()); return Result::Ok(());
} }
@@ -119,8 +121,8 @@ impl LeafMatcher for RegexesFileMatcher {
fn is_match(&self, event_value: Option<&Value>) -> bool { fn is_match(&self, event_value: Option<&Value>) -> bool {
//TODO Wildcardの場合、CaseInsensitiveなので、ToLowerする。 //TODO Wildcardの場合、CaseInsensitiveなので、ToLowerする。
return match event_value.unwrap_or(&Value::Null) { return match event_value.unwrap_or(&Value::Null) {
Value::String(s) => !utils::check_regex(s, &self.regexes_csv_content), Value::String(s) => !utils::check_regex(s, &self.regexes),
Value::Number(n) => !utils::check_regex(&n.to_string(), &self.regexes_csv_content), Value::Number(n) => !utils::check_regex(&n.to_string(), &self.regexes),
_ => false, _ => false,
}; };
} }
@@ -129,14 +131,12 @@ impl LeafMatcher for RegexesFileMatcher {
/// ファイルに列挙された文字列に一致する場合に検知するロジックを表す /// ファイルに列挙された文字列に一致する場合に検知するロジックを表す
/// DeepBlueCLIのcheck_cmdメソッドの一部に同様の処理が実装されていた。 /// DeepBlueCLIのcheck_cmdメソッドの一部に同様の処理が実装されていた。
pub struct AllowlistFileMatcher { pub struct AllowlistFileMatcher {
allowlist_csv_content: Vec<String>, regexes: Vec<Regex>,
} }
impl AllowlistFileMatcher { impl AllowlistFileMatcher {
pub fn new() -> AllowlistFileMatcher { pub fn new() -> AllowlistFileMatcher {
return AllowlistFileMatcher { return AllowlistFileMatcher { regexes: vec![] };
allowlist_csv_content: vec![],
};
} }
} }
@@ -164,22 +164,24 @@ impl LeafMatcher for AllowlistFileMatcher {
return Result::Err(vec![errmsg]); return Result::Err(vec![errmsg]);
} }
let allowlist_content = utils::read_txt(&value.unwrap()); let regexes_strs = utils::read_txt(&value.unwrap());
if allowlist_content.is_err() { if regexes_strs.is_err() {
return Result::Err(vec![allowlist_content.unwrap_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(&regex_str).unwrap())
.collect();
return Result::Ok(()); return Result::Ok(());
} }
fn is_match(&self, event_value: Option<&Value>) -> bool { fn is_match(&self, event_value: Option<&Value>) -> bool {
return match event_value.unwrap_or(&Value::Null) { return match event_value.unwrap_or(&Value::Null) {
Value::String(s) => !utils::check_allowlist(s, &self.allowlist_csv_content), Value::String(s) => !utils::check_allowlist(s, &self.regexes),
Value::Number(n) => { Value::Number(n) => !utils::check_allowlist(&n.to_string(), &self.regexes),
!utils::check_allowlist(&n.to_string(), &self.allowlist_csv_content) Value::Bool(b) => !utils::check_allowlist(&b.to_string(), &self.regexes),
}
Value::Bool(b) => !utils::check_allowlist(&b.to_string(), &self.allowlist_csv_content),
_ => true, _ => true,
}; };
} }
@@ -651,15 +653,15 @@ mod tests {
.unwrap(); .unwrap();
// regexes.txtの中身と一致していることを確認 // regexes.txtの中身と一致していることを確認
let csvcontent = &ancestor_matcher.regexes_csv_content; let csvcontent = &ancestor_matcher.regexes;
assert_eq!(csvcontent.len(), 17); assert_eq!(csvcontent.len(), 17);
assert_eq!( assert_eq!(
csvcontent[0], csvcontent[0].as_str().to_string(),
r"^cmd.exe /c echo [a-z]{6} > \\\\.\\pipe\\[a-z]{6}$" r"^cmd.exe /c echo [a-z]{6} > \\\\.\\pipe\\[a-z]{6}$"
); );
assert_eq!( assert_eq!(
csvcontent[14], csvcontent[14].as_str().to_string(),
r"\\cvtres\.exe.*\\AppData\\Local\\Temp\\[A-Z0-9]{7}\.tmp" r"\\cvtres\.exe.*\\AppData\\Local\\Temp\\[A-Z0-9]{7}\.tmp"
); );
} }
@@ -678,15 +680,15 @@ mod tests {
.downcast_ref::<AllowlistFileMatcher>() .downcast_ref::<AllowlistFileMatcher>()
.unwrap(); .unwrap();
let csvcontent = &ancestor_matcher.allowlist_csv_content; let csvcontent = &ancestor_matcher.regexes;
assert_eq!(csvcontent.len(), 2); assert_eq!(csvcontent.len(), 2);
assert_eq!( assert_eq!(
csvcontent[0], csvcontent[0].as_str().to_string(),
r#"^"C:\\Program Files\\Google\\Chrome\\Application\\chrome\.exe""#.to_string() r#"^"C:\\Program Files\\Google\\Chrome\\Application\\chrome\.exe""#.to_string()
); );
assert_eq!( assert_eq!(
csvcontent[1], csvcontent[1].as_str().to_string(),
r#"^"C:\\Program Files\\Google\\Update\\GoogleUpdate\.exe""#.to_string() r#"^"C:\\Program Files\\Google\\Update\\GoogleUpdate\.exe""#.to_string()
); );
} }

View File

@@ -24,14 +24,9 @@ pub fn concat_selection_key(key_list: &Vec<String>) -> String {
}); });
} }
pub fn check_regex(string: &str, regex_list: &Vec<String>) -> bool { pub fn check_regex(string: &str, regex_list: &Vec<Regex>) -> bool {
for line in regex_list { for regex in regex_list {
if line.is_empty() { if regex.is_match(string) == false {
continue;
}
let re = Regex::new(line);
if re.is_err() || re.unwrap().is_match(string) == false {
continue; continue;
} }
@@ -41,14 +36,9 @@ pub fn check_regex(string: &str, regex_list: &Vec<String>) -> bool {
return false; return false;
} }
pub fn check_allowlist(target: &str, allowlist: &Vec<String>) -> bool { pub fn check_allowlist(target: &str, regexes: &Vec<Regex>) -> bool {
for line in allowlist { for regex in regexes {
if line.is_empty() { if regex.is_match(target) {
continue;
}
let r = Regex::new(line);
if r.is_ok() && r.unwrap().is_match(target) {
return true; return true;
} }
} }
@@ -159,9 +149,15 @@ pub fn create_tokio_runtime() -> Runtime {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::detections::utils; use crate::detections::utils;
use regex::Regex;
#[test] #[test]
fn test_check_regex() { 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(&regex_str).unwrap())
.collect();
let regextext = utils::check_regex("\\cvtres.exe", &regexes); let regextext = utils::check_regex("\\cvtres.exe", &regexes);
assert!(regextext == true); assert!(regextext == true);
@@ -172,7 +168,11 @@ mod tests {
#[test] #[test]
fn test_check_allowlist() { fn test_check_allowlist() {
let commandline = "\"C:\\Program Files\\Google\\Update\\GoogleUpdate.exe\""; 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)); assert!(true == utils::check_allowlist(commandline, &allowlist));
let commandline = "\"C:\\Program Files\\Google\\Update\\GoogleUpdate2.exe\""; let commandline = "\"C:\\Program Files\\Google\\Update\\GoogleUpdate2.exe\"";