diff --git a/contributors.txt b/contributors.txt index 6b8fe43e..927b19a0 100644 --- a/contributors.txt +++ b/contributors.txt @@ -1,16 +1,12 @@ Hayabusa was possible thanks to the following people (in alphabetical order): Akira Nishikawa (@nishikawaakira): Previous lead developer, core hayabusa rule support, etc... -Dai (@__da13__): Developer DustInDark(@hitenkoku): Core developer, project management, sigma count implementation, rule creation, countless feature additions and fixes, etc… Garigariganzy (@garigariganzy31): Developer, event ID statistics implementation, etc... ItiB (@itiB_S144) : Core developer, sigmac hayabusa backend, rule creation, etc... James Takai / hachiyone(@hach1yon): Current lead developer, tokio multi-threading, sigma aggregation logic, sigmac backend, rule creation, etc… Kazuminn (@k2warugaki): Developer -Mimura (@mimura1133): Developer Yusuke Matsui (@apt773): AD hacking working group leader, rule testing, documentation, research, support, etc... -Siam (@siamease): Developer -Tsubokku (@ytsuboi0322): Japanese translations Zach Mathis (@yamatosecurity, Yamato Security Founder): Project leader, tool and concept design, rule creation and tuning, etc… diff --git a/src/afterfact.rs b/src/afterfact.rs index 15fd0fdf..47d4457b 100644 --- a/src/afterfact.rs +++ b/src/afterfact.rs @@ -82,7 +82,7 @@ fn emit_csv(writer: &mut W) -> Result<(), Box> { wtr.flush()?; println!(""); - println!("Events Detected:{:?}", detect_count); + println!("Total Events Detected:{:?}", detect_count); Ok(()) } diff --git a/src/detections/configs.rs b/src/detections/configs.rs index d3a8db51..b4b18c21 100644 --- a/src/detections/configs.rs +++ b/src/detections/configs.rs @@ -5,7 +5,7 @@ use std::collections::HashMap; use std::sync::RwLock; lazy_static! { pub static ref CONFIG: RwLock = RwLock::new(ConfigReader::new()); - pub static ref LEVELMAP: HashMap = { + pub static ref LEVELMAP: HashMap = { let mut levelmap = HashMap::new(); levelmap.insert("INFO".to_owned(), 1); levelmap.insert("LOW".to_owned(), 2); diff --git a/src/detections/detection.rs b/src/detections/detection.rs index 2b435835..3f02c616 100644 --- a/src/detections/detection.rs +++ b/src/detections/detection.rs @@ -5,6 +5,7 @@ use serde_json::Value; use std::collections::HashMap; use tokio::{runtime::Runtime, spawn, task::JoinHandle}; +use crate::detections::configs; use crate::detections::print::AlertMessage; use crate::detections::print::MESSAGES; use crate::detections::rule; @@ -54,11 +55,6 @@ impl Detection { // ルールファイルのパースを実行 let mut rulefile_loader = ParseYaml::new(); let result_readdir = rulefile_loader.read_dir(rulespath.unwrap_or(DIRPATH_RULES), &level); - Detection::print_rule_load_info( - rulefile_loader.rulecounter, - rulefile_loader.parseerror_count, - rulefile_loader.ignore_count, - ); if result_readdir.is_err() { AlertMessage::alert( &mut std::io::stderr().lock(), @@ -67,7 +63,7 @@ impl Detection { .ok(); return vec![]; } - + let mut parseerror_count = rulefile_loader.errorrule_count; let return_if_success = |mut rule: RuleNode| { let err_msgs_result = rule.init(); if err_msgs_result.is_ok() { @@ -83,18 +79,24 @@ impl Detection { err_msgs.iter().for_each(|err_msg| { AlertMessage::warn(&mut std::io::stdout().lock(), err_msg.to_string()).ok(); }); + parseerror_count += 1; println!(""); // 一行開けるためのprintln }); return Option::None; }; - // parse rule files - return rulefile_loader + let ret = rulefile_loader .files .into_iter() .map(|rule_file_tuple| rule::create_rule(rule_file_tuple.0, rule_file_tuple.1)) .filter_map(return_if_success) .collect(); + Detection::print_rule_load_info( + &rulefile_loader.rulecounter, + &parseerror_count, + &rulefile_loader.ignorerule_count, + ); + return ret; } // 複数のイベントレコードに対して、複数のルールを1個実行します。 @@ -141,6 +143,34 @@ impl Detection { } } + pub fn print_unique_results(&self) { + let rules = &self.rules; + let levellabel = Vec::from(["Critical", "High", "Medium", "Low", "Info", "Undeifned"]); + // levclcounts is [(Undeifned), (Info), (Low),(Medium),(High),(Critical)] + let mut levelcounts = Vec::from([0, 0, 0, 0, 0, 0]); + for rule in rules.into_iter() { + if rule.check_exist_countdata() { + let suffix = configs::LEVELMAP + .get( + &rule.yaml["level"] + .as_str() + .unwrap_or("") + .to_owned() + .to_uppercase(), + ) + .unwrap_or(&0); + levelcounts[*suffix as usize] += 1; + } + } + let mut total_unique = 0; + levelcounts.reverse(); + for (i, value) in levelcounts.iter().enumerate() { + println!("{} alerts {}", levellabel[i], value); + total_unique += value; + } + println!("Unique Events Detected: {}", total_unique); + } + // 複数のイベントレコードに対して、ルールを1個実行します。 fn execute_rule(mut rule: RuleNode, records: Arc>) -> RuleNode { let records = &*records; @@ -210,9 +240,9 @@ impl Detection { return ret; } pub fn print_rule_load_info( - rc: HashMap, - parseerror_count: u128, - ignore_count: u128, + rc: &HashMap, + parseerror_count: &u128, + ignore_count: &u128, ) { let mut total = parseerror_count + ignore_count; rc.into_iter().for_each(|(key, value)| { diff --git a/src/detections/print.rs b/src/detections/print.rs index 708f183f..95563ecc 100644 --- a/src/detections/print.rs +++ b/src/detections/print.rs @@ -161,7 +161,7 @@ impl Message { detect_count += detect_infos.len(); } println!(""); - println!("Events Detected:{:?}", detect_count); + println!("Total Events Detected:{:?}", detect_count); } pub fn iter(&self) -> &BTreeMap, Vec> { diff --git a/src/detections/rule/mod.rs b/src/detections/rule/mod.rs index b636bc10..11f2eda8 100644 --- a/src/detections/rule/mod.rs +++ b/src/detections/rule/mod.rs @@ -102,6 +102,9 @@ impl RuleNode { } return ret; } + pub fn check_exist_countdata(&self) -> bool { + self.countdata.len() > 0 + } } /// Ruleファイルのdetectionを表すノード diff --git a/src/main.rs b/src/main.rs index 9db674d1..081ff838 100644 --- a/src/main.rs +++ b/src/main.rs @@ -130,8 +130,8 @@ fn analysis_files(evtx_files: Vec) { } detection = analysis_file(evtx_file, detection); } - after_fact(); + detection.print_unique_results(); } // Windowsイベントログファイルを1ファイル分解析する。 diff --git a/src/yaml.rs b/src/yaml.rs index 47044bbb..792d7790 100644 --- a/src/yaml.rs +++ b/src/yaml.rs @@ -15,8 +15,8 @@ use yaml_rust::YamlLoader; pub struct ParseYaml { pub files: Vec<(String, yaml_rust::Yaml)>, pub rulecounter: HashMap, - pub ignore_count: u128, - pub parseerror_count: u128, + pub ignorerule_count: u128, + pub errorrule_count: u128, } impl ParseYaml { @@ -24,8 +24,8 @@ impl ParseYaml { ParseYaml { files: Vec::new(), rulecounter: HashMap::new(), - ignore_count: 0, - parseerror_count: 0, + ignorerule_count: 0, + errorrule_count: 0, } } @@ -73,7 +73,7 @@ impl ParseYaml { read_content.unwrap_err() ), )?; - self.parseerror_count += 1; + self.errorrule_count += 1; return io::Result::Ok(ret); } @@ -88,7 +88,7 @@ impl ParseYaml { yaml_contents.unwrap_err() ), )?; - self.parseerror_count += 1; + self.errorrule_count += 1; return io::Result::Ok(ret); } @@ -105,21 +105,13 @@ impl ParseYaml { .filter_map(|(filepath, yaml_doc)| { // ignoreフラグがONになっているルールは無視する。 if yaml_doc["ignore"].as_bool().unwrap_or(false) { - self.ignore_count += 1; + self.ignorerule_count += 1; return Option::None; } self.rulecounter.insert( - yaml_doc["rulesection"] - .as_str() - .unwrap_or("other") - .to_string(), + yaml_doc["ruletype"].as_str().unwrap_or("other").to_string(), self.rulecounter - .get( - &yaml_doc["rulesection"] - .as_str() - .unwrap_or("other") - .to_string(), - ) + .get(&yaml_doc["ruletype"].as_str().unwrap_or("other").to_string()) .unwrap_or(&0) + 1, );