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
This commit is contained in:
@@ -23,6 +23,7 @@ pub struct CsvFormat<'a> {
|
|||||||
level: &'a str,
|
level: &'a str,
|
||||||
rule_title: &'a str,
|
rule_title: &'a str,
|
||||||
details: &'a str,
|
details: &'a str,
|
||||||
|
mitre_attack: &'a str,
|
||||||
rule_path: &'a str,
|
rule_path: &'a str,
|
||||||
file_path: &'a str,
|
file_path: &'a str,
|
||||||
}
|
}
|
||||||
@@ -213,6 +214,7 @@ fn emit_csv<W: std::io::Write>(
|
|||||||
event_i_d: &detect_info.eventid,
|
event_i_d: &detect_info.eventid,
|
||||||
rule_title: &detect_info.alert,
|
rule_title: &detect_info.alert,
|
||||||
details: &detect_info.detail,
|
details: &detect_info.detail,
|
||||||
|
mitre_attack: &detect_info.tag_info,
|
||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
let level_suffix = *configs::LEVELMAP
|
let level_suffix = *configs::LEVELMAP
|
||||||
@@ -350,6 +352,7 @@ mod tests {
|
|||||||
let test_computername = "testcomputer";
|
let test_computername = "testcomputer";
|
||||||
let test_eventid = "1111";
|
let test_eventid = "1111";
|
||||||
let output = "pokepoke";
|
let output = "pokepoke";
|
||||||
|
let test_attack = "execution/txxxx.yyy";
|
||||||
{
|
{
|
||||||
let mut messages = print::MESSAGES.lock().unwrap();
|
let mut messages = print::MESSAGES.lock().unwrap();
|
||||||
messages.clear();
|
messages.clear();
|
||||||
@@ -377,33 +380,37 @@ mod tests {
|
|||||||
test_eventid.to_string(),
|
test_eventid.to_string(),
|
||||||
test_title.to_string(),
|
test_title.to_string(),
|
||||||
output.to_string(),
|
output.to_string(),
|
||||||
|
test_attack.to_string(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
let expect_time = Utc
|
let expect_time = Utc
|
||||||
.datetime_from_str("1996-02-27T01:05:01Z", "%Y-%m-%dT%H:%M:%SZ")
|
.datetime_from_str("1996-02-27T01:05:01Z", "%Y-%m-%dT%H:%M:%SZ")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let expect_tz = expect_time.with_timezone(&Local);
|
let expect_tz = expect_time.with_timezone(&Local);
|
||||||
let expect = "Timestamp,Computer,EventID,Level,RuleTitle,Details,RulePath,FilePath\n"
|
let expect =
|
||||||
.to_string()
|
"Timestamp,Computer,EventID,Level,RuleTitle,Details,MitreAttack,RulePath,FilePath\n"
|
||||||
+ &expect_tz
|
|
||||||
.clone()
|
|
||||||
.format("%Y-%m-%d %H:%M:%S%.3f %:z")
|
|
||||||
.to_string()
|
.to_string()
|
||||||
+ ","
|
+ &expect_tz
|
||||||
+ test_computername
|
.clone()
|
||||||
+ ","
|
.format("%Y-%m-%d %H:%M:%S%.3f %:z")
|
||||||
+ test_eventid
|
.to_string()
|
||||||
+ ","
|
+ ","
|
||||||
+ test_level
|
+ test_computername
|
||||||
+ ","
|
+ ","
|
||||||
+ test_title
|
+ test_eventid
|
||||||
+ ","
|
+ ","
|
||||||
+ output
|
+ test_level
|
||||||
+ ","
|
+ ","
|
||||||
+ testrulepath
|
+ test_title
|
||||||
+ ","
|
+ ","
|
||||||
+ &testfilepath.to_string()
|
+ output
|
||||||
+ "\n";
|
+ ","
|
||||||
|
+ test_attack
|
||||||
|
+ ","
|
||||||
|
+ testrulepath
|
||||||
|
+ ","
|
||||||
|
+ &testfilepath.to_string()
|
||||||
|
+ "\n";
|
||||||
let mut file: Box<dyn io::Write> =
|
let mut file: Box<dyn io::Write> =
|
||||||
Box::new(File::create("./test_emit_csv.csv".to_string()).unwrap());
|
Box::new(File::create("./test_emit_csv.csv".to_string()).unwrap());
|
||||||
assert!(emit_csv(&mut file, false, None).is_ok());
|
assert!(emit_csv(&mut file, false, None).is_ok());
|
||||||
@@ -425,6 +432,7 @@ mod tests {
|
|||||||
let test_computername = "testcomputer2";
|
let test_computername = "testcomputer2";
|
||||||
let test_eventid = "2222";
|
let test_eventid = "2222";
|
||||||
let output = "displaytest";
|
let output = "displaytest";
|
||||||
|
let test_attack = "execution/txxxx.zzz";
|
||||||
{
|
{
|
||||||
let mut messages = print::MESSAGES.lock().unwrap();
|
let mut messages = print::MESSAGES.lock().unwrap();
|
||||||
messages.clear();
|
messages.clear();
|
||||||
@@ -452,6 +460,7 @@ mod tests {
|
|||||||
test_eventid.to_string(),
|
test_eventid.to_string(),
|
||||||
test_title.to_string(),
|
test_title.to_string(),
|
||||||
output.to_string(),
|
output.to_string(),
|
||||||
|
test_attack.to_string(),
|
||||||
);
|
);
|
||||||
messages.debug();
|
messages.debug();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -190,6 +190,12 @@ impl Detection {
|
|||||||
|
|
||||||
/// 条件に合致したレコードを表示するための関数
|
/// 条件に合致したレコードを表示するための関数
|
||||||
fn insert_message(rule: &RuleNode, record_info: &EvtxRecordInfo) {
|
fn insert_message(rule: &RuleNode, record_info: &EvtxRecordInfo) {
|
||||||
|
let tag_info: Vec<String> = 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(
|
MESSAGES.lock().unwrap().insert(
|
||||||
record_info.evtx_filepath.to_string(),
|
record_info.evtx_filepath.to_string(),
|
||||||
rule.rulepath.to_string(),
|
rule.rulepath.to_string(),
|
||||||
@@ -203,11 +209,18 @@ impl Detection {
|
|||||||
.to_string(),
|
.to_string(),
|
||||||
rule.yaml["title"].as_str().unwrap_or("").to_string(),
|
rule.yaml["title"].as_str().unwrap_or("").to_string(),
|
||||||
rule.yaml["details"].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
|
/// insert aggregation condition detection message to output stack
|
||||||
fn insert_agg_message(rule: &RuleNode, agg_result: AggResult) {
|
fn insert_agg_message(rule: &RuleNode, agg_result: AggResult) {
|
||||||
|
let tag_info: Vec<String> = 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);
|
let output = Detection::create_count_output(rule, &agg_result);
|
||||||
MESSAGES.lock().unwrap().insert_message(
|
MESSAGES.lock().unwrap().insert_message(
|
||||||
"-".to_owned(),
|
"-".to_owned(),
|
||||||
@@ -218,6 +231,7 @@ impl Detection {
|
|||||||
"-".to_owned(),
|
"-".to_owned(),
|
||||||
rule.yaml["title"].as_str().unwrap_or("").to_owned(),
|
rule.yaml["title"].as_str().unwrap_or("").to_owned(),
|
||||||
output.to_owned(),
|
output.to_owned(),
|
||||||
|
tag_info.join(" : "),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ pub struct DetectInfo {
|
|||||||
pub eventid: String,
|
pub eventid: String,
|
||||||
pub alert: String,
|
pub alert: String,
|
||||||
pub detail: String,
|
pub detail: String,
|
||||||
|
pub tag_info: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct AlertMessage {}
|
pub struct AlertMessage {}
|
||||||
@@ -71,6 +72,7 @@ impl Message {
|
|||||||
eventid: String,
|
eventid: String,
|
||||||
event_title: String,
|
event_title: String,
|
||||||
event_detail: String,
|
event_detail: String,
|
||||||
|
tag_info: String,
|
||||||
) {
|
) {
|
||||||
let detect_info = DetectInfo {
|
let detect_info = DetectInfo {
|
||||||
filepath: target_file,
|
filepath: target_file,
|
||||||
@@ -80,6 +82,7 @@ impl Message {
|
|||||||
eventid: eventid,
|
eventid: eventid,
|
||||||
alert: event_title,
|
alert: event_title,
|
||||||
detail: event_detail,
|
detail: event_detail,
|
||||||
|
tag_info: tag_info,
|
||||||
};
|
};
|
||||||
|
|
||||||
match self.map.get_mut(&event_time) {
|
match self.map.get_mut(&event_time) {
|
||||||
@@ -104,6 +107,7 @@ impl Message {
|
|||||||
eventid: String,
|
eventid: String,
|
||||||
event_title: String,
|
event_title: String,
|
||||||
output: String,
|
output: String,
|
||||||
|
tag_info: String,
|
||||||
) {
|
) {
|
||||||
let message = &self.parse_message(event_record, output);
|
let message = &self.parse_message(event_record, output);
|
||||||
let default_time = Utc.ymd(1970, 1, 1).and_hms(0, 0, 0);
|
let default_time = Utc.ymd(1970, 1, 1).and_hms(0, 0, 0);
|
||||||
@@ -117,6 +121,7 @@ impl Message {
|
|||||||
eventid,
|
eventid,
|
||||||
event_title,
|
event_title,
|
||||||
message.to_string(),
|
message.to_string(),
|
||||||
|
tag_info,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,6 +284,7 @@ mod tests {
|
|||||||
"1".to_string(),
|
"1".to_string(),
|
||||||
"test1".to_string(),
|
"test1".to_string(),
|
||||||
"CommandLine1: %CommandLine%".to_string(),
|
"CommandLine1: %CommandLine%".to_string(),
|
||||||
|
"txxx.001".to_string(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let json_str_2 = r##"
|
let json_str_2 = r##"
|
||||||
@@ -305,6 +311,7 @@ mod tests {
|
|||||||
"2".to_string(),
|
"2".to_string(),
|
||||||
"test2".to_string(),
|
"test2".to_string(),
|
||||||
"CommandLine2: %CommandLine%".to_string(),
|
"CommandLine2: %CommandLine%".to_string(),
|
||||||
|
"txxx.002".to_string(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let json_str_3 = r##"
|
let json_str_3 = r##"
|
||||||
@@ -331,6 +338,7 @@ mod tests {
|
|||||||
"3".to_string(),
|
"3".to_string(),
|
||||||
"test3".to_string(),
|
"test3".to_string(),
|
||||||
"CommandLine3: %CommandLine%".to_string(),
|
"CommandLine3: %CommandLine%".to_string(),
|
||||||
|
"txxx.003".to_string(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let json_str_4 = r##"
|
let json_str_4 = r##"
|
||||||
@@ -352,11 +360,12 @@ mod tests {
|
|||||||
"4".to_string(),
|
"4".to_string(),
|
||||||
"test4".to_string(),
|
"test4".to_string(),
|
||||||
"CommandLine4: %CommandLine%".to_string(),
|
"CommandLine4: %CommandLine%".to_string(),
|
||||||
|
"txxx.004".to_string(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let display = format!("{}", format_args!("{:?}", message));
|
let display = format!("{}", format_args!("{:?}", message));
|
||||||
println!("display::::{}", display);
|
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);
|
assert_eq!(display, expect);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user