Feature/output logo#206 (#222)

* add output logo #206

* added newline and orgnization name #206

* add output rule count #200

* Changed yml summarize the totals for each folder hierarchy. #157

* added analyzing evtx file count output #157

* added loaded rule count output #157

* added quiet option #206
This commit is contained in:
DustInDark
2021-11-21 15:16:44 +09:00
committed by GitHub
parent 86321a4502
commit b53342218c
5 changed files with 68 additions and 2 deletions

7
art/logo.txt Normal file
View File

@@ -0,0 +1,7 @@
██╗ ██╗ █████╗ ██╗ ██╗ █████╗ ██████╗ ██╗ ██╗███████╗ █████╗
██║ ██║██╔══██╗╚██╗ ██╔╝██╔══██╗██╔══██╗██║ ██║██╔════╝██╔══██╗
███████║███████║ ╚████╔╝ ███████║██████╔╝██║ ██║███████╗███████║
██╔══██║██╔══██║ ╚██╔╝ ██╔══██║██╔══██╗██║ ██║╚════██║██╔══██║
██║ ██║██║ ██║ ██║ ██║ ██║██████╔╝╚██████╔╝███████║██║ ██║
╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚═════╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝
by Yamato Security

View File

@@ -52,6 +52,7 @@ fn build_app<'a>() -> ArgMatches<'a> {
--rfc-2822 'Output date and time in RFC 2822 format. Example: Mon, 07 Aug 2006 12:34:56 -0600' --rfc-2822 'Output date and time in RFC 2822 format. Example: Mon, 07 Aug 2006 12:34:56 -0600'
--rfc-3339 'Output date and time in RFC 3339 format. Example: 2006-08-07T12:34:56.485214 -06:00' --rfc-3339 'Output date and time in RFC 3339 format. Example: 2006-08-07T12:34:56.485214 -06:00'
--verbose 'Output check information to target event file path and rule file.' --verbose 'Output check information to target event file path and rule file.'
-q 'Quiet Output Logo'
-r --rules=[RULEDIRECTORY] 'using target of rule file directory' -r --rules=[RULEDIRECTORY] 'using target of rule file directory'
-L --level=[LEVEL] 'Specified execute rule level(default: LOW)' -L --level=[LEVEL] 'Specified execute rule level(default: LOW)'
-u --utc 'Output time in UTC format(default: local time)' -u --utc 'Output time in UTC format(default: local time)'

View File

@@ -2,6 +2,7 @@ extern crate csv;
use crate::detections::rule::AggResult; use crate::detections::rule::AggResult;
use serde_json::Value; use serde_json::Value;
use std::collections::HashMap;
use tokio::{runtime::Runtime, spawn, task::JoinHandle}; use tokio::{runtime::Runtime, spawn, task::JoinHandle};
use crate::detections::print::AlertMessage; use crate::detections::print::AlertMessage;
@@ -51,6 +52,11 @@ impl Detection {
// ルールファイルのパースを実行 // ルールファイルのパースを実行
let mut rulefile_loader = ParseYaml::new(); let mut rulefile_loader = ParseYaml::new();
let result_readdir = rulefile_loader.read_dir(rulespath.unwrap_or(DIRPATH_RULES), &level); 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() { if result_readdir.is_err() {
AlertMessage::alert( AlertMessage::alert(
&mut std::io::stderr().lock(), &mut std::io::stderr().lock(),
@@ -201,6 +207,21 @@ impl Detection {
)); ));
return ret; return ret;
} }
pub fn print_rule_load_info(
rc: HashMap<String, u128>,
parseerror_count: u128,
ignore_count: u128,
) {
let mut total = parseerror_count + ignore_count;
rc.into_iter().for_each(|(key, value)| {
println!("{} Rules: {}", key, value);
total += value;
});
println!("Ignored Rule Count: {}", ignore_count);
println!("Rule Parse Errors Count: {}", parseerror_count);
println!("Total Detection Rules: {}", total);
println!("");
}
} }
#[test] #[test]

View File

@@ -20,6 +20,10 @@ use std::{
const MAX_DETECT_RECORDS: usize = 40000; const MAX_DETECT_RECORDS: usize = 40000;
fn main() { fn main() {
if !configs::CONFIG.read().unwrap().args.is_present("q") {
output_logo();
println!("");
}
if configs::CONFIG.read().unwrap().args.args.len() == 0 { if configs::CONFIG.read().unwrap().args.args.len() == 0 {
println!( println!(
"{}", "{}",
@@ -114,6 +118,7 @@ fn analysis_files(evtx_files: Vec<PathBuf>) {
.value_of("level") .value_of("level")
.unwrap_or("INFO") .unwrap_or("INFO")
.to_uppercase(); .to_uppercase();
println!("Analyzing Event Files: {:?}", evtx_files.len());
let rule_files = detection::Detection::parse_rule_files( let rule_files = detection::Detection::parse_rule_files(
level, level,
configs::CONFIG.read().unwrap().args.value_of("rules"), configs::CONFIG.read().unwrap().args.value_of("rules"),
@@ -212,6 +217,12 @@ fn _output_with_omikuji(omikuji: Omikuji) {
println!("{}", content); println!("{}", content);
} }
fn output_logo() {
let fp = &format!("art/logo.txt");
let content = fs::read_to_string(fp).unwrap();
println!("{}", content);
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::collect_evtxfiles; use crate::collect_evtxfiles;

View File

@@ -3,6 +3,7 @@ extern crate yaml_rust;
use crate::detections::configs; use crate::detections::configs;
use crate::detections::print::AlertMessage; use crate::detections::print::AlertMessage;
use std::collections::HashMap;
use std::ffi::OsStr; use std::ffi::OsStr;
use std::fs; use std::fs;
use std::io; use std::io;
@@ -13,11 +14,19 @@ use yaml_rust::YamlLoader;
pub struct ParseYaml { pub struct ParseYaml {
pub files: Vec<(String, yaml_rust::Yaml)>, pub files: Vec<(String, yaml_rust::Yaml)>,
pub rulecounter: HashMap<String, u128>,
pub ignore_count: u128,
pub parseerror_count: u128,
} }
impl ParseYaml { impl ParseYaml {
pub fn new() -> ParseYaml { pub fn new() -> ParseYaml {
ParseYaml { files: Vec::new() } ParseYaml {
files: Vec::new(),
rulecounter: HashMap::new(),
ignore_count: 0,
parseerror_count: 0,
}
} }
pub fn read_file(&self, path: PathBuf) -> Result<String, String> { pub fn read_file(&self, path: PathBuf) -> Result<String, String> {
@@ -64,6 +73,7 @@ impl ParseYaml {
read_content.unwrap_err() read_content.unwrap_err()
), ),
)?; )?;
self.parseerror_count += 1;
return io::Result::Ok(ret); return io::Result::Ok(ret);
} }
@@ -78,6 +88,7 @@ impl ParseYaml {
yaml_contents.unwrap_err() yaml_contents.unwrap_err()
), ),
)?; )?;
self.parseerror_count += 1;
return io::Result::Ok(ret); return io::Result::Ok(ret);
} }
@@ -94,8 +105,24 @@ impl ParseYaml {
.filter_map(|(filepath, yaml_doc)| { .filter_map(|(filepath, yaml_doc)| {
// ignoreフラグがONになっているルールは無視する。 // ignoreフラグがONになっているルールは無視する。
if yaml_doc["ignore"].as_bool().unwrap_or(false) { if yaml_doc["ignore"].as_bool().unwrap_or(false) {
self.ignore_count += 1;
return Option::None; return Option::None;
} }
self.rulecounter.insert(
yaml_doc["rulesection"]
.as_str()
.unwrap_or("other")
.to_string(),
self.rulecounter
.get(
&yaml_doc["rulesection"]
.as_str()
.unwrap_or("other")
.to_string(),
)
.unwrap_or(&0)
+ 1,
);
if configs::CONFIG.read().unwrap().args.is_present("verbose") { if configs::CONFIG.read().unwrap().args.is_present("verbose") {
println!("Loaded yml FilePath: {}", filepath); println!("Loaded yml FilePath: {}", filepath);
} }
@@ -115,7 +142,6 @@ impl ParseYaml {
}) })
.collect(); .collect();
self.files.extend(files); self.files.extend(files);
return io::Result::Ok(String::default()); return io::Result::Ok(String::default());
} }
} }