Merge branch 'main' into 654-enhancement-output-to-json

This commit is contained in:
DastInDark
2022-08-21 11:48:04 +09:00
8 changed files with 88 additions and 14 deletions
+72
View File
@@ -203,12 +203,15 @@ fn emit_csv<W: std::io::Write>(
HashMap::new();
let mut detect_counts_by_computer_and_level: HashMap<String, HashMap<String, i128>> =
HashMap::new();
let mut detect_counts_by_rule_and_level: HashMap<String, HashMap<String, i128>> =
HashMap::new();
let levels = Vec::from(["crit", "high", "med ", "low ", "info", "undefined"]);
// レベル別、日ごとの集計用変数の初期化
for level_init in levels {
detect_counts_by_date_and_level.insert(level_init.to_string(), HashMap::new());
detect_counts_by_computer_and_level.insert(level_init.to_string(), HashMap::new());
detect_counts_by_rule_and_level.insert(level_init.to_string(), HashMap::new());
}
if displayflag {
println!();
@@ -283,6 +286,7 @@ fn emit_csv<W: std::io::Write>(
)
.unwrap_or(&0) as usize;
let time_str_date = format_time(time, true);
let mut detect_counts_by_date = detect_counts_by_date_and_level
.get(&detect_info.level.to_lowercase())
.unwrap_or_else(|| detect_counts_by_date_and_level.get("undefined").unwrap())
@@ -294,6 +298,7 @@ fn emit_csv<W: std::io::Write>(
detected_rule_files.insert(detect_info.rulepath.clone());
unique_detect_counts_by_level[level_suffix] += 1;
}
let computer_rule_check_key =
format!("{}|{}", &detect_info.computername, &detect_info.rulepath);
if !detected_computer_and_rule_names.contains(&computer_rule_check_key) {
@@ -313,6 +318,20 @@ fn emit_csv<W: std::io::Write>(
.insert(detect_info.level.to_lowercase(), detect_counts_by_computer);
}
let mut detect_counts_by_rules = detect_counts_by_rule_and_level
.get(&detect_info.level.to_lowercase())
.unwrap_or_else(|| {
detect_counts_by_computer_and_level
.get("undefined")
.unwrap()
})
.clone();
*detect_counts_by_rules
.entry(Clone::clone(&detect_info.ruletitle))
.or_insert(0) += 1;
detect_counts_by_rule_and_level
.insert(detect_info.level.to_lowercase(), detect_counts_by_rules);
total_detect_counts_by_level[level_suffix] += 1;
detect_counts_by_date_and_level
.insert(detect_info.level.to_lowercase(), detect_counts_by_date);
@@ -415,6 +434,9 @@ fn emit_csv<W: std::io::Write>(
println!();
_print_detection_summary_by_computer(detect_counts_by_computer_and_level, &color_map);
println!();
_print_detection_summary_by_rule(detect_counts_by_rule_and_level, &color_map);
Ok(())
}
@@ -610,6 +632,55 @@ fn _print_detection_summary_by_computer(
buf_wtr.print(&wtr).ok();
}
/// 各レベルごとで検出数が多かったルールのタイトルを出力する関数
fn _print_detection_summary_by_rule(
detect_counts_by_rule_and_level: HashMap<String, HashMap<String, i128>>,
color_map: &HashMap<String, Color>,
) {
let buf_wtr = BufferWriter::stdout(ColorChoice::Always);
let mut wtr = buf_wtr.buffer();
wtr.set_color(ColorSpec::new().set_fg(None)).ok();
let level_cnt = detect_counts_by_rule_and_level.len();
for (idx, level) in LEVEL_ABBR.values().enumerate() {
// output_levelsはlevelsからundefinedを除外した配列であり、各要素は必ず初期化されているのでSomeであることが保証されているのでunwrapをそのまま実施
let detections_by_computer = detect_counts_by_rule_and_level.get(level).unwrap();
let mut result_vec: Vec<String> = Vec::new();
let mut sorted_detections: Vec<(&String, &i128)> = detections_by_computer.iter().collect();
sorted_detections.sort_by(|a, b| (-a.1).cmp(&(-b.1)));
for x in sorted_detections.iter().take(5) {
result_vec.push(format!(
"{} ({})",
x.0,
x.1.to_formatted_string(&Locale::en)
));
}
let result_str = if result_vec.is_empty() {
"None".to_string()
} else {
result_vec.join("\n")
};
wtr.set_color(ColorSpec::new().set_fg(_get_output_color(
color_map,
LEVEL_FULL.get(level.as_str()).unwrap(),
)))
.ok();
writeln!(
wtr,
"Top {} alerts:\n{}",
LEVEL_FULL.get(level.as_str()).unwrap(),
&result_str
)
.ok();
if idx != level_cnt - 1 {
writeln!(wtr).ok();
}
}
buf_wtr.print(&wtr).ok();
}
/// get timestamp to input datetime.
fn _get_timestamp(time: &DateTime<Utc>) -> i64 {
if configs::CONFIG.read().unwrap().args.utc {
@@ -863,6 +934,7 @@ mod tests {
output.to_string(),
DetectInfo {
rulepath: test_rulepath.to_string(),
ruletitle: test_title.to_string(),
level: test_level.to_string(),
computername: test_computername.to_string(),
eventid: test_eventid.to_string(),
+3 -1
View File
@@ -37,7 +37,7 @@ use super::message::LEVEL_ABBR;
// イベントファイルの1レコード分の情報を保持する構造体
#[derive(Clone, Debug)]
pub struct EvtxRecordInfo {
pub evtx_filepath: String, // イベントファイルのファイルパス ログで出力するときに使う
pub evtx_filepath: String, // イベントファイルのファイルパス ログで出力するときに使う
pub record: Value, // 1レコード分のデータをJSON形式にシリアライズしたもの
pub data_string: String,
pub key_2_value: HashMap<String, String>,
@@ -362,6 +362,7 @@ impl Detection {
let detect_info = DetectInfo {
rulepath: (&rule.rulepath).to_owned(),
ruletitle: rule.yaml["title"].as_str().unwrap_or("-").to_string(),
level: LEVEL_ABBR.get(&level).unwrap_or(&level).to_string(),
computername: record_info.record["Event"]["System"]["Computer"]
.to_string()
@@ -492,6 +493,7 @@ impl Detection {
let detect_info = DetectInfo {
rulepath: (&rule.rulepath).to_owned(),
ruletitle: rule.yaml["title"].as_str().unwrap_or("-").to_string(),
level: LEVEL_ABBR.get(&level).unwrap_or(&level).to_string(),
computername: "-".to_owned(),
eventid: "-".to_owned(),
+2
View File
@@ -24,6 +24,7 @@ use termcolor::{BufferWriter, ColorChoice};
#[derive(Debug, Clone)]
pub struct DetectInfo {
pub rulepath: String,
pub ruletitle: String,
pub level: String,
pub computername: String,
pub eventid: String,
@@ -634,6 +635,7 @@ mod tests {
for i in 1..2001 {
let detect_info = DetectInfo {
rulepath: "".to_string(),
ruletitle: "".to_string(),
level: "".to_string(),
computername: "".to_string(),
eventid: i.to_string(),
-1
View File
@@ -305,7 +305,6 @@ impl App {
let analysis_end_time: DateTime<Local> = Local::now();
let analysis_duration = analysis_end_time.signed_duration_since(analysis_start_time);
println!();
write_color_buffer(
&BufferWriter::stdout(ColorChoice::Always),
None,