From 7933b2027127da6f174bf5c6074301ae4cc0e49d Mon Sep 17 00:00:00 2001 From: kazuminn Date: Wed, 25 Nov 2020 21:37:34 +0900 Subject: [PATCH 1/5] add credits template --- credits.txt | 1 + src/main.rs | 14 +++++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 credits.txt diff --git a/credits.txt b/credits.txt new file mode 100644 index 00000000..553b4928 --- /dev/null +++ b/credits.txt @@ -0,0 +1 @@ +Zach Mathis (田中ザック)Yamato Security Yea! Project Leader \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 96239b23..ffd95f31 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,7 @@ extern crate serde; use clap::{App, AppSettings, Arg}; use evtx::EvtxParser; use quick_xml::de::DeError; +use std::fs; use std::{path::PathBuf, process}; use yamato_event_analyzer::detections::detection; use yamato_event_analyzer::toml; @@ -32,7 +33,7 @@ fn build_app() -> clap::App<'static, 'static> { .arg(Arg::from_usage("-d --directory 'event log files directory'")) .arg(Arg::from_usage("-s --statistics 'event statistics'")) .arg(Arg::from_usage("-u --update 'signature update'")) - .arg(Arg::from_usage("--credits 'Zachary Mathis, Akira Nishikawa'")) + .arg(Arg::from_usage("-c --credits 'print credits infomation'")) } fn main() -> Result<(), DeError> { @@ -43,9 +44,20 @@ fn main() -> Result<(), DeError> { parse_file(filepath); } + if args.is_present("credits") { + print_credits(); + } + Ok(()) } +fn print_credits() { + match fs::read_to_string("./credits.txt") { + Ok(contents) => println!("{}", contents), + Err(err) => println!("{}", err), + } +} + fn parse_file(filepath: &str) { let fp = PathBuf::from(filepath); let parser = match EvtxParser::from_path(fp) { From acd226edc6f219378fa5d1b06e15f8da18bfbab5 Mon Sep 17 00:00:00 2001 From: kazuminn Date: Wed, 25 Nov 2020 21:42:30 +0900 Subject: [PATCH 2/5] refactor --- src/main.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main.rs b/src/main.rs index ffd95f31..f1bd2b63 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,8 +4,7 @@ extern crate serde; use clap::{App, AppSettings, Arg}; use evtx::EvtxParser; use quick_xml::de::DeError; -use std::fs; -use std::{path::PathBuf, process}; +use std::{fs, path::PathBuf, process}; use yamato_event_analyzer::detections::detection; use yamato_event_analyzer::toml; From b6c89c754b7d1561fc6cb4f4d0e4a7e0e425ac25 Mon Sep 17 00:00:00 2001 From: ichiichi11 Date: Sat, 5 Dec 2020 23:30:09 +0900 Subject: [PATCH 3/5] implement directory option --- config/eventkey_alias.txt | 2 +- src/detections/configs.rs | 2 +- src/detections/detection.rs | 107 ++++++++++++++++++++--------- src/main.rs | 74 ++++++++++++++++---- test_files/evtx/sub/test.txt | 0 test_files/evtx/sub/test2.evtx | 0 test_files/evtx/sub/testtest4.evtx | 0 test_files/evtx/test.txt | 0 test_files/evtx/test1.evtx | 0 9 files changed, 134 insertions(+), 51 deletions(-) create mode 100644 test_files/evtx/sub/test.txt create mode 100644 test_files/evtx/sub/test2.evtx create mode 100644 test_files/evtx/sub/testtest4.evtx create mode 100644 test_files/evtx/test.txt create mode 100644 test_files/evtx/test1.evtx diff --git a/config/eventkey_alias.txt b/config/eventkey_alias.txt index 12fb0ef3..ca54c10f 100644 --- a/config/eventkey_alias.txt +++ b/config/eventkey_alias.txt @@ -13,7 +13,7 @@ ServiceName,Event.EventData.ServiceName ImagePath,Event.EventData.ImagePath ContextInfo,Event.EventData.ContextInfo Path,Event.EventData.Path -ScriptBlockText,Event.EventData.ScriptBlockText#Name +ScriptBlockText,Event.EventData.ScriptBlockText MemberName,Event.EventData.SubjectUserName MemberSid,Event.EventData.SubjectUserSid TargetSid,Event.EventData.TargetSid diff --git a/src/detections/configs.rs b/src/detections/configs.rs index d4879f12..d77fbc03 100644 --- a/src/detections/configs.rs +++ b/src/detections/configs.rs @@ -47,7 +47,7 @@ fn build_app() -> clap::App<'static, 'static> { .arg(Arg::from_usage("--human-readable-timeline=[HUMAN_READABLE_TIMELINE] 'human readable timeline'")) .arg(Arg::from_usage("-l --lang=[LANG] 'output language'")) .arg(Arg::from_usage("-t --timezone=[TIMEZONE] 'timezone setting'")) - .arg(Arg::from_usage("-d --directory 'event log files directory'")) + .arg(Arg::from_usage("-d --directory=[DIRECTORY] 'event log files directory'")) .arg(Arg::from_usage("-s --statistics 'event statistics'")) .arg(Arg::from_usage("-u --update 'signature update'")) .arg(Arg::from_usage("--credits 'Zachary Mathis, Akira Nishikawa'")) diff --git a/src/detections/detection.rs b/src/detections/detection.rs index 20977de4..ff02f665 100644 --- a/src/detections/detection.rs +++ b/src/detections/detection.rs @@ -1,13 +1,15 @@ extern crate chrono; extern crate csv; +use std::path::PathBuf; + use crate::detections::print::Message; use crate::detections::rule; use crate::detections::rule::RuleNode; use crate::yaml::ParseYaml; -use chrono::{DateTime, FixedOffset, TimeZone, Utc}; -use evtx::EvtxParser; +use evtx::err; +use evtx::{EvtxParser, SerializedEvtxRecord}; use serde_json::{Error, Value}; const DIRPATH_RULES: &str = "rules"; @@ -21,37 +23,92 @@ impl Detection { Detection {} } - pub fn start(&mut self, mut parser: EvtxParser) { - // serialize from .etvx to jsons - let event_records: Vec = parser - .records_json() - .filter_map(|result_record| { - if result_record.is_err() { - eprintln!("{}", result_record.unwrap_err()); - return Option::None; + pub fn start(&mut self, evtx_files: Vec) { + if evtx_files.is_empty() { + return; + } + + // parse rule files + let mut selection_rules = self.parse_rule_files(); + if selection_rules.is_empty() { + return; + } + + // serialize from evtx files to json + let evtx_records = self.serialize_evtx_to_jsons(evtx_files); + + // select rule files and collect message + let mut message = Message::new(); + selection_rules.iter_mut().for_each(|rule| { + evtx_records.iter().for_each(|event_record| { + if !rule.select(event_record) { + return; } - //// https://rust-lang-nursery.github.io/rust-cookbook/encoding/complex.html - let result_json: Result = - serde_json::from_str(&result_record.unwrap().data); + message.insert( + event_record, + rule.yaml["output"].as_str().unwrap_or("").to_string(), + ) + }); + }); + + // output message + message.print(); + } + + // serialize evtx files to json + fn serialize_evtx_to_jsons(&self, evtx_files: Vec) -> Vec { + return evtx_files + .iter() + .filter_map(|evtx_file| { + // convert to evtx parser + match EvtxParser::from_path(evtx_file) { + Ok(parser) => Option::Some(parser), + Err(e) => { + eprintln!("{}", e); + return Option::None; + } + } + }) + .map(|mut cur| { + let ret: Vec>> = + cur.records_json().collect(); + return ret; + }) + .flatten() + .filter_map(|json_record| { + // convert from evtx parser to evtx json string records + if json_record.is_ok() { + return Option::Some(json_record.unwrap()); + } else { + eprintln!("{}", json_record.unwrap_err()); + return Option::None; + } + }) + .filter_map(|json_record| { + // serialize json from json string + let result_json: Result = serde_json::from_str(&json_record.data); //// https://rust-lang-nursery.github.io/rust-cookbook/encoding/complex.html if result_json.is_err() { eprintln!("{}", result_json.unwrap_err()); return Option::None; + } else { + return result_json.ok(); } - return result_json.ok(); }) .collect(); + } + fn parse_rule_files(&self) -> Vec { // load rule files let mut rulefile_loader = ParseYaml::new(); let resutl_readdir = rulefile_loader.read_dir(DIRPATH_RULES); if resutl_readdir.is_err() { eprintln!("{}", resutl_readdir.unwrap_err()); - return; + return vec![]; } // parse rule files - let mut selection_rules: Vec = rulefile_loader + return rulefile_loader .files .into_iter() .map(|rule_file| rule::parse_rule(rule_file)) @@ -79,23 +136,5 @@ impl Detection { return Option::None; }) .collect(); - - // selection rule files and collect message - let mut message = Message::new(); - selection_rules.iter_mut().for_each(|rule| { - event_records.iter().for_each(|event_record| { - if !rule.select(event_record) { - return; - } - - message.insert( - event_record, - rule.yaml["output"].as_str().unwrap_or("").to_string(), - ) - }); - }); - - // output message - message.print(); } } diff --git a/src/main.rs b/src/main.rs index 0a66e2e7..8eec1241 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,9 +2,8 @@ extern crate serde; #[macro_use] extern crate serde_derive; -use evtx::EvtxParser; use quick_xml::de::DeError; -use std::{fs, path::PathBuf, process}; +use std::{fs, path::PathBuf}; use yamato_event_analyzer::afterfact::after_fact; use yamato_event_analyzer::detections::configs; use yamato_event_analyzer::detections::detection; @@ -12,7 +11,10 @@ use yamato_event_analyzer::omikuji::Omikuji; fn main() -> Result<(), DeError> { if let Some(filepath) = configs::singleton().args.value_of("filepath") { - parse_file(&filepath); + detect_files(vec![PathBuf::from(filepath)]); + } else if let Some(directory) = configs::singleton().args.value_of("directory") { + let evtx_files = collect_evtxfiles(&directory); + detect_files(evtx_files); } after_fact(); @@ -20,22 +22,64 @@ fn main() -> Result<(), DeError> { Ok(()) } -fn parse_file(filepath: &str) { - let fp = PathBuf::from(filepath); - let parser = match EvtxParser::from_path(fp) { - Ok(pointer) => pointer, - Err(e) => { - eprintln!("{}", e); - process::exit(1); - } - }; +fn collect_evtxfiles(dirpath: &str) -> Vec { + let entries = fs::read_dir(dirpath); + if entries.is_err() { + eprintln!("{}", entries.unwrap_err()); + return vec![]; + } - let mut detection = detection::Detection::new(); - &detection.start(parser); + let mut ret = vec![]; + for e in entries.unwrap() { + if e.is_err() { + continue; + } + + let path = e.unwrap().path(); + if path.is_dir() { + path.to_str().and_then(|path_str| { + let subdir_ret = collect_evtxfiles(path_str); + ret.extend(subdir_ret); + return Option::Some(()); + }); + } else { + let path_str = path.to_str().unwrap_or(""); + if path_str.ends_with(".evtx") { + ret.push(path); + } + } + } + + return ret; } -fn output_with_omikuji(omikuji: Omikuji) { +fn detect_files(evtx_files: Vec) { + let mut detection = detection::Detection::new(); + &detection.start(evtx_files); +} + +fn _output_with_omikuji(omikuji: Omikuji) { let fp = &format!("art/omikuji/{}", omikuji); let content = fs::read_to_string(fp).unwrap(); println!("{}", content); } + +#[cfg(test)] +mod tests { + use crate::collect_evtxfiles; + + #[test] + fn test_collect_evtxfiles() { + let files = collect_evtxfiles("test_files/evtx"); + assert_eq!(3, files.len()); + + files.iter().for_each(|file| { + let is_contains = &vec!["test1.evtx", "test2.evtx", "testtest4.evtx"] + .into_iter() + .any(|filepath_str| { + return file.file_name().unwrap().to_str().unwrap_or("") == filepath_str; + }); + assert_eq!(is_contains, &true); + }) + } +} diff --git a/test_files/evtx/sub/test.txt b/test_files/evtx/sub/test.txt new file mode 100644 index 00000000..e69de29b diff --git a/test_files/evtx/sub/test2.evtx b/test_files/evtx/sub/test2.evtx new file mode 100644 index 00000000..e69de29b diff --git a/test_files/evtx/sub/testtest4.evtx b/test_files/evtx/sub/testtest4.evtx new file mode 100644 index 00000000..e69de29b diff --git a/test_files/evtx/test.txt b/test_files/evtx/test.txt new file mode 100644 index 00000000..e69de29b diff --git a/test_files/evtx/test1.evtx b/test_files/evtx/test1.evtx new file mode 100644 index 00000000..e69de29b From b9189f8e3116b582052a9c305d12710fa6570cf8 Mon Sep 17 00:00:00 2001 From: kazuminn Date: Sun, 6 Dec 2020 22:28:00 +0900 Subject: [PATCH 4/5] refactor --- src/detections/detection.rs | 1 - src/main.rs | 6 +----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/detections/detection.rs b/src/detections/detection.rs index ff02f665..0dd617b8 100644 --- a/src/detections/detection.rs +++ b/src/detections/detection.rs @@ -1,4 +1,3 @@ -extern crate chrono; extern crate csv; use std::path::PathBuf; diff --git a/src/main.rs b/src/main.rs index 8eec1241..7796b406 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,15 +1,13 @@ extern crate serde; -#[macro_use] extern crate serde_derive; -use quick_xml::de::DeError; use std::{fs, path::PathBuf}; use yamato_event_analyzer::afterfact::after_fact; use yamato_event_analyzer::detections::configs; use yamato_event_analyzer::detections::detection; use yamato_event_analyzer::omikuji::Omikuji; -fn main() -> Result<(), DeError> { +fn main() { if let Some(filepath) = configs::singleton().args.value_of("filepath") { detect_files(vec![PathBuf::from(filepath)]); } else if let Some(directory) = configs::singleton().args.value_of("directory") { @@ -18,8 +16,6 @@ fn main() -> Result<(), DeError> { } after_fact(); - - Ok(()) } fn collect_evtxfiles(dirpath: &str) -> Vec { From d94d18f9cd1c8291f985e519786138104f1557e8 Mon Sep 17 00:00:00 2001 From: kazuminn Date: Sun, 6 Dec 2020 22:50:20 +0900 Subject: [PATCH 5/5] refactor --- src/yaml.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/yaml.rs b/src/yaml.rs index 781a5100..43a84a52 100644 --- a/src/yaml.rs +++ b/src/yaml.rs @@ -47,7 +47,7 @@ impl ParseYaml { }; } if entry.file_type().ok()?.is_dir() { - self.read_dir(entry.path()); + let _ = self.read_dir(entry.path()); } Some("") })