diff --git a/src/detections/print.rs b/src/detections/print.rs index 04d1d0de..fcd031f1 100644 --- a/src/detections/print.rs +++ b/src/detections/print.rs @@ -2,8 +2,6 @@ extern crate lazy_static; use crate::detections::configs; use crate::detections::utils; use crate::detections::utils::get_serde_number_to_string; -use crate::filter::DataFilterRule; -use crate::filter::FILTER_REGEX; use chrono::{DateTime, Local, TimeZone, Utc}; use hashbrown::HashMap; use lazy_static::lazy_static; @@ -90,7 +88,6 @@ impl Message { fn parse_message(&mut self, event_record: &Value, output: String) -> String { let mut return_message: String = output; let mut hash_map: HashMap = HashMap::new(); - let mut output_filter: Option<&DataFilterRule> = None; for caps in ALIASREGEX.captures_iter(&return_message) { let full_target_str = &caps[0]; let target_length = full_target_str.chars().count() - 2; // The meaning of 2 is two percent @@ -114,17 +111,13 @@ impl Message { if let Some(record) = tmp_event_record.get(s) { is_exist_event_key = true; tmp_event_record = record; - output_filter = FILTER_REGEX.get(&s.to_string()); } } if is_exist_event_key { - let mut hash_value = get_serde_number_to_string(tmp_event_record); - if hash_value.is_some() { - if output_filter.is_some() { - hash_value = - utils::replace_target_character(hash_value.as_ref(), output_filter); - } - hash_map.insert(full_target_str.to_string(), hash_value.unwrap()); + let hash_value = get_serde_number_to_string(tmp_event_record); + if let Some(hash_value) = hash_value { + let hash_value = hash_value.replace(r"(\\a|\\f|\\t|\\n|\\r|\\v)", " "); + hash_map.insert(full_target_str.to_string(), hash_value); } } } diff --git a/src/detections/rule/matchers.rs b/src/detections/rule/matchers.rs index 82189753..7c559411 100644 --- a/src/detections/rule/matchers.rs +++ b/src/detections/rule/matchers.rs @@ -448,7 +448,11 @@ impl PipeElement { regex::escape(pattern) } else { // wildcardの場合、"*"は".*"という正規表現に変換し、"?"は"."に変換する。 - let wildcard_regex_value = if *pattern == "*" { ".*" } else { "." }; + let wildcard_regex_value = if *pattern == "*" { + "(.|\\a|\\f|\\t|\\n|\\r|\\v)*" + } else { + "." + }; wildcard_regex_value.to_string() }; @@ -1516,7 +1520,7 @@ mod tests { #[test] fn test_pipe_pattern_wildcard_asterisk() { let value = PipeElement::pipe_pattern_wildcard(r"*ho*ge*".to_string()); - assert_eq!("(?i).*ho.*ge.*", value); + assert_eq!("(?i)(.|\\a|\\f|\\t|\\n|\\r|\\v)*ho(.|\\a|\\f|\\t|\\n|\\r|\\v)*ge(.|\\a|\\f|\\t|\\n|\\r|\\v)*", value); } #[test] @@ -1532,7 +1536,10 @@ mod tests { // wildcardの「\\*」は文字列としての「\」と正規表現の「.*」を表す。 // 文字列としての「\」はエスケープされるので、「\\.*」が正解 let value = PipeElement::pipe_pattern_wildcard(r"\\*ho\\*ge\\*".to_string()); - assert_eq!(r"(?i)\\.*ho\\.*ge\\.*", value); + assert_eq!( + r"(?i)\\(.|\a|\f|\t|\n|\r|\v)*ho\\(.|\a|\f|\t|\n|\r|\v)*ge\\(.|\a|\f|\t|\n|\r|\v)*", + value + ); } #[test] @@ -1562,13 +1569,19 @@ mod tests { #[test] fn test_pipe_pattern_wildcard_mixed() { let value = PipeElement::pipe_pattern_wildcard(r"\\*\****\*\\*".to_string()); - assert_eq!(r"(?i)\\.*\*.*.*.*\*\\.*", value); + assert_eq!( + r"(?i)\\(.|\a|\f|\t|\n|\r|\v)*\*(.|\a|\f|\t|\n|\r|\v)*(.|\a|\f|\t|\n|\r|\v)*(.|\a|\f|\t|\n|\r|\v)*\*\\(.|\a|\f|\t|\n|\r|\v)*", + value + ); } #[test] fn test_pipe_pattern_wildcard_many_backshashs() { let value = PipeElement::pipe_pattern_wildcard(r"\\\*ho\\\*ge\\\".to_string()); - assert_eq!(r"(?i)\\\\.*ho\\\\.*ge\\\\\\", value); + assert_eq!( + r"(?i)\\\\(.|\a|\f|\t|\n|\r|\v)*ho\\\\(.|\a|\f|\t|\n|\r|\v)*ge\\\\\\", + value + ); } #[test] diff --git a/src/detections/rule/selectionnodes.rs b/src/detections/rule/selectionnodes.rs index 2ba92d35..becb3253 100644 --- a/src/detections/rule/selectionnodes.rs +++ b/src/detections/rule/selectionnodes.rs @@ -1,5 +1,4 @@ use crate::detections::{detection::EvtxRecordInfo, utils}; -use crate::filter::FILTER_REGEX; use downcast_rs::Downcast; use std::{sync::Arc, vec}; use yaml_rust::Yaml; @@ -309,9 +308,6 @@ impl SelectionNode for LeafSelectionNode { ] } */ - - let filter_rule = FILTER_REGEX.get(self.get_key()); - if self.get_key() == "EventData" { let values = utils::get_event_value("Event.EventData.Data", &event_record.record); if values.is_none() { @@ -326,15 +322,12 @@ impl SelectionNode for LeafSelectionNode { let eventdata_data = values.unwrap(); if eventdata_data.is_boolean() || eventdata_data.is_i64() || eventdata_data.is_string() { - let replaced_str = utils::replace_target_character( - event_record.get_value(self.get_key()), - filter_rule, - ); + let event_value = event_record.get_value(self.get_key()); return self .matcher .as_ref() .unwrap() - .is_match(replaced_str.as_ref(), event_record); + .is_match(event_value, event_record); } // 配列の場合は配列の要素のどれか一つでもルールに合致すれば条件に一致したことにする。 if eventdata_data.is_array() { @@ -343,15 +336,12 @@ impl SelectionNode for LeafSelectionNode { .unwrap() .iter() .any(|ary_element| { - let replaced_str = utils::replace_target_character( - utils::value_to_string(ary_element).as_ref(), - filter_rule, - ); + let event_value = utils::value_to_string(ary_element); return self .matcher .as_ref() .unwrap() - .is_match(replaced_str.as_ref(), event_record); + .is_match(event_value.as_ref(), event_record); }); } else { return self @@ -362,14 +352,12 @@ impl SelectionNode for LeafSelectionNode { } } - let replaced_str = - utils::replace_target_character(self.get_event_value(event_record), filter_rule); - + let event_value = self.get_event_value(event_record); return self .matcher .as_ref() .unwrap() - .is_match(replaced_str.as_ref(), event_record); + .is_match(event_value, event_record); } fn init(&mut self) -> Result<(), Vec> { diff --git a/src/detections/utils.rs b/src/detections/utils.rs index 08f6481d..0dd1a6c6 100644 --- a/src/detections/utils.rs +++ b/src/detections/utils.rs @@ -3,7 +3,6 @@ extern crate csv; extern crate regex; use crate::detections::configs; -use crate::filter::DataFilterRule; use tokio::runtime::Builder; use tokio::runtime::Runtime; @@ -40,26 +39,6 @@ pub fn check_regex(string: &str, regex_list: &[Regex]) -> bool { false } -/// replace string from all defined regex in input to replace_str -pub fn replace_target_character<'a>( - input_str: Option<&'a String>, - replace_rule: Option<&'a DataFilterRule>, -) -> Option { - input_str?; - if replace_rule.is_none() { - return Some(input_str.unwrap().to_string()); - } - - let replace_regex_rule = &replace_rule.unwrap().regex_rule; - let replace_str = &replace_rule.unwrap().replace_str; - - Some( - replace_regex_rule - .replace_all(input_str.unwrap(), replace_str) - .to_string(), - ) -} - pub fn check_allowlist(target: &str, regexes: &[Regex]) -> bool { for regex in regexes { if regex.is_match(target) { @@ -247,7 +226,7 @@ pub fn create_rec_info(data: Value, path: String, keys: &[String]) -> EvtxRecord continue; } - rec.key_2_value.insert(key.to_string(), val.unwrap()); + rec.key_2_value.insert(key.trim().to_string(), val.unwrap()); } rec @@ -256,7 +235,6 @@ pub fn create_rec_info(data: Value, path: String, keys: &[String]) -> EvtxRecord #[cfg(test)] mod tests { use crate::detections::utils; - use crate::filter::DataFilterRule; use regex::Regex; use serde_json::Value; @@ -347,25 +325,4 @@ mod tests { assert!(utils::get_serde_number_to_string(&event_record["Event"]["EventData"]).is_none()); } - - #[test] - /// 指定された文字から指定されたregexぉ実行する関数が動作するかのテスト - fn test_remove_space_control() { - let test_filter_rule = DataFilterRule { - regex_rule: Regex::new(r"[\r\n\t]+").unwrap(), - replace_str: "".to_string(), - }; - let none_test_str: Option<&String> = None; - - assert!(utils::replace_target_character(none_test_str, None).is_none()); - - assert!(utils::replace_target_character(none_test_str, Some(&test_filter_rule)).is_none()); - - let tmp = "h\ra\ny\ta\tb\nu\r\nsa".to_string(); - let test_str: Option<&String> = Some(&tmp); - assert_eq!( - utils::replace_target_character(test_str, Some(&test_filter_rule)).unwrap(), - "hayabusa" - ); - } } diff --git a/src/filter.rs b/src/filter.rs index 3f9bcf11..69d7ee3c 100644 --- a/src/filter.rs +++ b/src/filter.rs @@ -2,8 +2,6 @@ use crate::detections::configs; use crate::detections::print::AlertMessage; use crate::detections::print::ERROR_LOG_STACK; use crate::detections::print::QUIET_ERRORS_FLAG; -use crate::detections::utils; -use hashbrown::HashMap; use hashbrown::HashSet; use lazy_static::lazy_static; use regex::Regex; @@ -14,7 +12,6 @@ use std::io::{BufRead, BufReader}; lazy_static! { static ref IDS_REGEX: Regex = Regex::new(r"^[0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12}$").unwrap(); - pub static ref FILTER_REGEX: HashMap = load_record_filters(); } #[derive(Debug)] @@ -23,70 +20,6 @@ pub struct DataFilterRule { pub replace_str: String, } -fn load_record_filters() -> HashMap { - let file_path = "./rules/config/regex/record_data_filter.txt"; - let read_result = utils::read_csv(file_path); - let mut ret = HashMap::new(); - if read_result.is_err() { - if configs::CONFIG.read().unwrap().args.is_present("verbose") { - AlertMessage::warn( - &mut BufWriter::new(std::io::stderr().lock()), - &format!("{} does not exist", file_path), - ) - .ok(); - } - if !*QUIET_ERRORS_FLAG { - ERROR_LOG_STACK - .lock() - .unwrap() - .push(format!("{} does not exist", file_path)); - } - return HashMap::default(); - } - read_result.unwrap().into_iter().for_each(|line| { - if line.len() != 3 { - return; - } - - let empty = &"".to_string(); - let key = line.get(0).unwrap_or(empty).trim(); - let regex_str = line.get(1).unwrap_or(empty).trim(); - let replaced_str = line.get(2).unwrap_or(empty).trim(); - if key.is_empty() || regex_str.is_empty() { - return; - } - - let regex_rule: Option = match Regex::new(regex_str) { - Ok(regex) => Some(regex), - Err(_err) => { - let errmsg = "failed to read regex filter in record_data_filter.txt"; - if configs::CONFIG.read().unwrap().args.is_present("verbose") { - AlertMessage::alert(&mut BufWriter::new(std::io::stderr().lock()), errmsg).ok(); - } - if !*QUIET_ERRORS_FLAG { - ERROR_LOG_STACK - .lock() - .unwrap() - .push(format!("[ERROR] {}", errmsg)); - } - None - } - }; - - if regex_rule.is_none() { - return; - } - ret.insert( - key.to_string(), - DataFilterRule { - regex_rule: regex_rule.unwrap(), - replace_str: replaced_str.to_string(), - }, - ); - }); - ret -} - #[derive(Clone, Debug)] pub struct RuleExclude { pub no_use_rule: HashSet,