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:
7
art/logo.txt
Normal file
7
art/logo.txt
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
██╗ ██╗ █████╗ ██╗ ██╗ █████╗ ██████╗ ██╗ ██╗███████╗ █████╗
|
||||||
|
██║ ██║██╔══██╗╚██╗ ██╔╝██╔══██╗██╔══██╗██║ ██║██╔════╝██╔══██╗
|
||||||
|
███████║███████║ ╚████╔╝ ███████║██████╔╝██║ ██║███████╗███████║
|
||||||
|
██╔══██║██╔══██║ ╚██╔╝ ██╔══██║██╔══██╗██║ ██║╚════██║██╔══██║
|
||||||
|
██║ ██║██║ ██║ ██║ ██║ ██║██████╔╝╚██████╔╝███████║██║ ██║
|
||||||
|
╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚═════╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝
|
||||||
|
by Yamato Security
|
||||||
@@ -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)'
|
||||||
|
|||||||
@@ -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]
|
||||||
|
|||||||
11
src/main.rs
11
src/main.rs
@@ -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;
|
||||||
|
|||||||
30
src/yaml.rs
30
src/yaml.rs
@@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user