From 19c44b4f668c75f287d2aacbd9b860dc20ac2a2c Mon Sep 17 00:00:00 2001 From: DustInDark Date: Tue, 15 Feb 2022 02:13:37 +0900 Subject: [PATCH] added mitre attack data output in csv output (#397) * added tags information in csv output #234 * fixed test due to change csvformat struct #234 * changed tag info separator #234 * changed separator #234 * changed tag info separator #234 --- src/afterfact.rs | 49 ++++++++++++++++++++++--------------- src/detections/detection.rs | 14 +++++++++++ src/detections/print.rs | 11 ++++++++- 3 files changed, 53 insertions(+), 21 deletions(-) diff --git a/src/afterfact.rs b/src/afterfact.rs index 6f297053..6ea9d4fd 100644 --- a/src/afterfact.rs +++ b/src/afterfact.rs @@ -23,6 +23,7 @@ pub struct CsvFormat<'a> { level: &'a str, rule_title: &'a str, details: &'a str, + mitre_attack: &'a str, rule_path: &'a str, file_path: &'a str, } @@ -213,6 +214,7 @@ fn emit_csv( event_i_d: &detect_info.eventid, rule_title: &detect_info.alert, details: &detect_info.detail, + mitre_attack: &detect_info.tag_info, })?; } let level_suffix = *configs::LEVELMAP @@ -350,6 +352,7 @@ mod tests { let test_computername = "testcomputer"; let test_eventid = "1111"; let output = "pokepoke"; + let test_attack = "execution/txxxx.yyy"; { let mut messages = print::MESSAGES.lock().unwrap(); messages.clear(); @@ -377,33 +380,37 @@ mod tests { test_eventid.to_string(), test_title.to_string(), output.to_string(), + test_attack.to_string(), ); } let expect_time = Utc .datetime_from_str("1996-02-27T01:05:01Z", "%Y-%m-%dT%H:%M:%SZ") .unwrap(); let expect_tz = expect_time.with_timezone(&Local); - let expect = "Timestamp,Computer,EventID,Level,RuleTitle,Details,RulePath,FilePath\n" - .to_string() - + &expect_tz - .clone() - .format("%Y-%m-%d %H:%M:%S%.3f %:z") + let expect = + "Timestamp,Computer,EventID,Level,RuleTitle,Details,MitreAttack,RulePath,FilePath\n" .to_string() - + "," - + test_computername - + "," - + test_eventid - + "," - + test_level - + "," - + test_title - + "," - + output - + "," - + testrulepath - + "," - + &testfilepath.to_string() - + "\n"; + + &expect_tz + .clone() + .format("%Y-%m-%d %H:%M:%S%.3f %:z") + .to_string() + + "," + + test_computername + + "," + + test_eventid + + "," + + test_level + + "," + + test_title + + "," + + output + + "," + + test_attack + + "," + + testrulepath + + "," + + &testfilepath.to_string() + + "\n"; let mut file: Box = Box::new(File::create("./test_emit_csv.csv".to_string()).unwrap()); assert!(emit_csv(&mut file, false, None).is_ok()); @@ -425,6 +432,7 @@ mod tests { let test_computername = "testcomputer2"; let test_eventid = "2222"; let output = "displaytest"; + let test_attack = "execution/txxxx.zzz"; { let mut messages = print::MESSAGES.lock().unwrap(); messages.clear(); @@ -452,6 +460,7 @@ mod tests { test_eventid.to_string(), test_title.to_string(), output.to_string(), + test_attack.to_string(), ); messages.debug(); } diff --git a/src/detections/detection.rs b/src/detections/detection.rs index 71edb905..66dcce1a 100644 --- a/src/detections/detection.rs +++ b/src/detections/detection.rs @@ -190,6 +190,12 @@ impl Detection { /// 条件に合致したレコードを表示するための関数 fn insert_message(rule: &RuleNode, record_info: &EvtxRecordInfo) { + let tag_info: Vec = rule.yaml["tags"] + .as_vec() + .unwrap_or(&Vec::default()) + .into_iter() + .map(|info| info.as_str().unwrap_or("").replace("attack.", "")) + .collect(); MESSAGES.lock().unwrap().insert( record_info.evtx_filepath.to_string(), rule.rulepath.to_string(), @@ -203,11 +209,18 @@ impl Detection { .to_string(), rule.yaml["title"].as_str().unwrap_or("").to_string(), rule.yaml["details"].as_str().unwrap_or("").to_string(), + tag_info.join(" : "), ); } /// insert aggregation condition detection message to output stack fn insert_agg_message(rule: &RuleNode, agg_result: AggResult) { + let tag_info: Vec = rule.yaml["tags"] + .as_vec() + .unwrap_or(&Vec::default()) + .into_iter() + .map(|info| info.as_str().unwrap_or("").replace("attack.", "")) + .collect(); let output = Detection::create_count_output(rule, &agg_result); MESSAGES.lock().unwrap().insert_message( "-".to_owned(), @@ -218,6 +231,7 @@ impl Detection { "-".to_owned(), rule.yaml["title"].as_str().unwrap_or("").to_owned(), output.to_owned(), + tag_info.join(" : "), ) } diff --git a/src/detections/print.rs b/src/detections/print.rs index 4bd5b291..229b46bb 100644 --- a/src/detections/print.rs +++ b/src/detections/print.rs @@ -30,6 +30,7 @@ pub struct DetectInfo { pub eventid: String, pub alert: String, pub detail: String, + pub tag_info: String, } pub struct AlertMessage {} @@ -71,6 +72,7 @@ impl Message { eventid: String, event_title: String, event_detail: String, + tag_info: String, ) { let detect_info = DetectInfo { filepath: target_file, @@ -80,6 +82,7 @@ impl Message { eventid: eventid, alert: event_title, detail: event_detail, + tag_info: tag_info, }; match self.map.get_mut(&event_time) { @@ -104,6 +107,7 @@ impl Message { eventid: String, event_title: String, output: String, + tag_info: String, ) { let message = &self.parse_message(event_record, output); let default_time = Utc.ymd(1970, 1, 1).and_hms(0, 0, 0); @@ -117,6 +121,7 @@ impl Message { eventid, event_title, message.to_string(), + tag_info, ) } @@ -279,6 +284,7 @@ mod tests { "1".to_string(), "test1".to_string(), "CommandLine1: %CommandLine%".to_string(), + "txxx.001".to_string(), ); let json_str_2 = r##" @@ -305,6 +311,7 @@ mod tests { "2".to_string(), "test2".to_string(), "CommandLine2: %CommandLine%".to_string(), + "txxx.002".to_string(), ); let json_str_3 = r##" @@ -331,6 +338,7 @@ mod tests { "3".to_string(), "test3".to_string(), "CommandLine3: %CommandLine%".to_string(), + "txxx.003".to_string(), ); let json_str_4 = r##" @@ -352,11 +360,12 @@ mod tests { "4".to_string(), "test4".to_string(), "CommandLine4: %CommandLine%".to_string(), + "txxx.004".to_string(), ); let display = format!("{}", format_args!("{:?}", message)); println!("display::::{}", display); - let expect = "Message { map: {1970-01-01T00:00:00Z: [DetectInfo { filepath: \"a\", rulepath: \"test_rule4\", level: \"medium\", computername: \"testcomputer4\", eventid: \"4\", alert: \"test4\", detail: \"CommandLine4: hoge\" }], 1996-02-27T01:05:01Z: [DetectInfo { filepath: \"a\", rulepath: \"test_rule\", level: \"high\", computername: \"testcomputer1\", eventid: \"1\", alert: \"test1\", detail: \"CommandLine1: hoge\" }, DetectInfo { filepath: \"a\", rulepath: \"test_rule2\", level: \"high\", computername: \"testcomputer2\", eventid: \"2\", alert: \"test2\", detail: \"CommandLine2: hoge\" }], 2000-01-21T09:06:01Z: [DetectInfo { filepath: \"a\", rulepath: \"test_rule3\", level: \"high\", computername: \"testcomputer3\", eventid: \"3\", alert: \"test3\", detail: \"CommandLine3: hoge\" }]} }"; + let expect = "Message { map: {1970-01-01T00:00:00Z: [DetectInfo { filepath: \"a\", rulepath: \"test_rule4\", level: \"medium\", computername: \"testcomputer4\", eventid: \"4\", alert: \"test4\", detail: \"CommandLine4: hoge\", tag_info: \"txxx.004\" }], 1996-02-27T01:05:01Z: [DetectInfo { filepath: \"a\", rulepath: \"test_rule\", level: \"high\", computername: \"testcomputer1\", eventid: \"1\", alert: \"test1\", detail: \"CommandLine1: hoge\", tag_info: \"txxx.001\" }, DetectInfo { filepath: \"a\", rulepath: \"test_rule2\", level: \"high\", computername: \"testcomputer2\", eventid: \"2\", alert: \"test2\", detail: \"CommandLine2: hoge\", tag_info: \"txxx.002\" }], 2000-01-21T09:06:01Z: [DetectInfo { filepath: \"a\", rulepath: \"test_rule3\", level: \"high\", computername: \"testcomputer3\", eventid: \"3\", alert: \"test3\", detail: \"CommandLine3: hoge\", tag_info: \"txxx.003\" }]} }"; assert_eq!(display, expect); }