diff --git a/config/eventkey_alias.txt b/config/eventkey_alias.txt index d7ea313a..3188c4b9 100644 --- a/config/eventkey_alias.txt +++ b/config/eventkey_alias.txt @@ -126,7 +126,7 @@ SubjectDomainName,Event.EventData.SubjectDomainName SubjectLogonId,Event.EventData.SubjectLogonId SubjectUserName,Event.EventData.SubjectUserName SubjectUserSid,Event.EventData.SubjectUserSid -TargetDomainName,Event.EventData.TargetDomainName +TargetDomainName,Event.EventData.TargetDomainName TargetFilename,Event.EventData.TargetFilename TargetImage,Event.EventData.TargetImage TargetLogonId,Event.EventData.TargetLogonId diff --git a/src/detections/detection.rs b/src/detections/detection.rs index 8012f1b9..b7173ffd 100644 --- a/src/detections/detection.rs +++ b/src/detections/detection.rs @@ -206,7 +206,9 @@ impl Detection { record_info.record["Event"]["System"]["Computer"] .to_string() .replace("\"", ""), - get_serde_number_to_string(&record_info.record["Event"]["System"]["EventID"]), + get_serde_number_to_string(&record_info.record["Event"]["System"]["EventID"]) + .unwrap_or("-".to_owned()) + .to_string(), rule.yaml["title"].as_str().unwrap_or("").to_string(), rule.yaml["output"].as_str().unwrap_or("").to_string(), ); diff --git a/src/detections/print.rs b/src/detections/print.rs index e489587b..51e65acb 100644 --- a/src/detections/print.rs +++ b/src/detections/print.rs @@ -30,6 +30,7 @@ pub struct AlertMessage {} lazy_static! { pub static ref MESSAGES: Mutex = Mutex::new(Message::new()); + pub static ref ALIASREGEX: Regex = Regex::new(r"%[a-zA-Z0-9-_]+%").unwrap(); } impl Message { @@ -101,8 +102,7 @@ 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 re = Regex::new(r"%[a-zA-Z0-9-_]+%").unwrap(); - for caps in re.captures_iter(&return_message) { + 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 let target_str = full_target_str @@ -118,16 +118,20 @@ impl Message { .get_event_key(target_str.to_string()) { let split: Vec<&str> = array_str.split(".").collect(); + let mut is_exist_event_key = false; let mut tmp_event_record: &Value = event_record.into(); for s in split { if let Some(record) = tmp_event_record.get(s) { + is_exist_event_key = true; tmp_event_record = record; } } - hash_map.insert( - full_target_str.to_string(), - get_serde_number_to_string(tmp_event_record), - ); + if is_exist_event_key { + let hash_value = get_serde_number_to_string(tmp_event_record); + if hash_value.is_some() { + hash_map.insert(full_target_str.to_string(), hash_value.unwrap()); + } + } } } @@ -332,4 +336,87 @@ mod tests { let mut stdout = stdout.lock(); AlertMessage::alert(&mut stdout, input.to_string()).expect("[WARN] TESTWarn!"); } + + #[test] + /// outputで指定されているキー(eventkey_alias.txt内で設定済み)から対象のレコード内の情報でメッセージをパースしているか確認する関数 + fn test_parse_message() { + let mut message = Message::new(); + let json_str = r##" + { + "Event": { + "EventData": { + "CommandLine": "parsetest1" + }, + "System": { + "Computer": "testcomputer1", + "TimeCreated_attributes": { + "SystemTime": "1996-02-27T01:05:01Z" + } + } + } + } + "##; + let event_record: Value = serde_json::from_str(json_str).unwrap(); + let expected = "commandline:parsetest1 computername:testcomputer1"; + assert_eq!( + message.parse_message( + &event_record, + "commandline:%CommandLine% computername:%ComputerName%".to_owned() + ), + expected, + ); + } + #[test] + /// outputで指定されているキーが、eventkey_alias.txt内で設定されていない場合の出力テスト + fn test_parse_message_not_exist_key_in_output() { + let mut message = Message::new(); + let json_str = r##" + { + "Event": { + "EventData": { + "CommandLine": "parsetest2" + }, + "System": { + "TimeCreated_attributes": { + "SystemTime": "1996-02-27T01:05:01Z" + } + } + } + } + "##; + let event_record: Value = serde_json::from_str(json_str).unwrap(); + let expected = "NoExistKey:%TESTNoExistKey%"; + assert_eq!( + message.parse_message(&event_record, "NoExistKey:%TESTNoExistKey%".to_owned()), + expected, + ); + } + #[test] + /// outputで指定されているキー(eventkey_alias.txt内で設定済み)が対象のレコード内に該当する情報がない場合の出力テスト + fn test_parse_message_not_exist_value_in_record() { + let mut message = Message::new(); + let json_str = r##" + { + "Event": { + "EventData": { + "CommandLine": "parsetest3" + }, + "System": { + "TimeCreated_attributes": { + "SystemTime": "1996-02-27T01:05:01Z" + } + } + } + } + "##; + let event_record: Value = serde_json::from_str(json_str).unwrap(); + let expected = "commandline:parsetest3 computername:%ComputerName%"; + assert_eq!( + message.parse_message( + &event_record, + "commandline:%CommandLine% computername:%ComputerName%".to_owned() + ), + expected, + ); + } } diff --git a/src/detections/utils.rs b/src/detections/utils.rs index f354c3b5..9df91ff7 100644 --- a/src/detections/utils.rs +++ b/src/detections/utils.rs @@ -94,11 +94,14 @@ pub fn get_event_id_key() -> String { } /// serde:Valueの型を確認し、文字列を返します。 -pub fn get_serde_number_to_string(value: &serde_json::Value) -> String { +pub fn get_serde_number_to_string(value: &serde_json::Value) -> Option { if value.is_string() { - return value.as_str().unwrap_or("").to_string(); + return Option::Some(value.as_str().unwrap_or("").to_string()); + } else if value.is_object() { + // Object type is not specified record value. + return Option::None; } else { - return value.to_string(); + return Option::Some(value.to_string()); } } @@ -163,6 +166,7 @@ pub fn create_tokio_runtime() -> Runtime { mod tests { use crate::detections::utils; use regex::Regex; + use serde_json::Value; #[test] fn test_check_regex() { @@ -191,4 +195,62 @@ mod tests { let commandline = "\"C:\\Program Files\\Google\\Update\\GoogleUpdate2.exe\""; assert!(false == utils::check_allowlist(commandline, &allowlist)); } + + #[test] + /// Serde::Valueの数値型の値を文字列として返却することを確かめるテスト + fn test_get_serde_number_to_string() { + let json_str = r##" + { + "Event": { + "System": { + "EventID": 11111 + } + } + } + "##; + let event_record: Value = serde_json::from_str(json_str).unwrap(); + + assert_eq!( + utils::get_serde_number_to_string(&event_record["Event"]["System"]["EventID"]).unwrap(), + "11111".to_owned() + ); + } + + #[test] + /// Serde::Valueの文字列型の値を文字列として返却することを確かめるテスト + fn test_get_serde_number_serde_string_to_string() { + let json_str = r##" + { + "Event": { + "EventData": { + "ComputerName": "HayabusaComputer1" + } + } + } + "##; + let event_record: Value = serde_json::from_str(json_str).unwrap(); + + assert_eq!( + utils::get_serde_number_to_string(&event_record["Event"]["EventData"]["ComputerName"]) + .unwrap(), + "HayabusaComputer1".to_owned() + ); + } + + #[test] + /// Serde::Valueのオブジェクト型の内容を誤って渡した際にNoneを返却することを確かめるテスト + fn test_get_serde_number_serde_object_ret_none() { + let json_str = r##" + { + "Event": { + "EventData": { + "ComputerName": "HayabusaComputer1" + } + } + } + "##; + let event_record: Value = serde_json::from_str(json_str).unwrap(); + + assert!(utils::get_serde_number_to_string(&event_record["Event"]["EventData"]).is_none()); + } }