From 8b3ce3e0717512c0e311d80b104bc56f8ba4aa85 Mon Sep 17 00:00:00 2001 From: Kazuminn Date: Fri, 25 Sep 2020 21:46:13 +0900 Subject: [PATCH 1/5] first commit --- Cargo.toml | 1 + src/detections/application.rs | 48 ++++++++++++++++++++++++++++++----- src/models/event.rs | 43 +++++++++++++++---------------- 3 files changed, 64 insertions(+), 28 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index fd190183..04818b2c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,3 +12,4 @@ quick-xml = {version = "0.17", features = ["serialize"] } serde = { version = "1.0", features = ["derive"] } serde_json = { version = "1.0"} clap = "*" +regex = "1" diff --git a/src/detections/application.rs b/src/detections/application.rs index 7676faab..9622b359 100644 --- a/src/detections/application.rs +++ b/src/detections/application.rs @@ -1,15 +1,51 @@ +extern crate regex; -pub struct Application { - -} +use crate::models::event; +use regex::Regex; +use std::collections::HashMap; + +pub struct Application {} impl Application { - pub fn new() -> Application { - Application{} + Application {} } - pub fn detection(&self) { + pub fn detection( + &mut self, + event_id: String, + system: &event::System, + event_data: HashMap, + ) { + let _emet = String::from("EMET"); + if event_id == "2" { + match &system.provider.name { + Some(_emet) => { + &self.emet(system, event_data); + } + None => (), + } + } + } + fn emet(&mut self, system: &event::System, event_data: HashMap) { + match &system.message { + Some(message) => { + let message_split: Vec<&str> = message.split("\n").collect(); + let text = message_split[0]; + let application = message_split[3]; + let re = Regex::new(r"^Application: ").unwrap(); + let command = re.replace_all(application, ""); + let username = message_split[4]; + + println!("Message EMET Block"); + println!("Command {}", command); + println!("Results {}", text); + println!("Results {}", username); + } + None => { + println!("Warning: EMET Message field is blank. Install EMET locally to see full details of this alert"); + } + } } } diff --git a/src/models/event.rs b/src/models/event.rs index 65afe514..2a06e6bd 100644 --- a/src/models/event.rs +++ b/src/models/event.rs @@ -25,9 +25,9 @@ struct Execution { } #[derive(Debug, Deserialize, PartialEq)] -struct Provider { +pub struct Provider { #[serde(rename = "Name")] - name: Option, + pub name: Option, #[serde(rename = "Guid")] guid: Option, } @@ -35,7 +35,7 @@ struct Provider { #[derive(Debug, Deserialize, PartialEq)] pub struct System { #[serde(rename = "Provider")] - provider: Provider, + pub provider: Provider, #[serde(rename = "EventID")] pub event_id: String, #[serde(rename = "Version")] @@ -62,6 +62,8 @@ pub struct System { computer: String, #[serde(rename = "Security")] security: String, + #[serde(rename = "Message")] + pub message: Option, } #[derive(Debug, Deserialize, PartialEq)] @@ -79,44 +81,41 @@ pub struct Evtx { } impl Evtx { - // // 文字列データを取得する // fn get_string(v: &Data) -> String { - match &v.text { Some(text) => { return text.to_string(); - }, + } _ => return "".to_string(), } } - + // // EventDataをHashMapとして取得する // - pub fn parse_event_data(&self) -> HashMap { + pub fn parse_event_data(&self) -> HashMap { let mut values = HashMap::new(); - + match &self.event_data { - Some(event_data) => - match &event_data.data { - Some(data) => { - for v in data.iter() { - match &v.name { - Some(name) => { - values.insert(name.to_string(), Evtx::get_string(v)); - }, - None => (), + Some(event_data) => match &event_data.data { + Some(data) => { + for v in data.iter() { + match &v.name { + Some(name) => { + values.insert(name.to_string(), Evtx::get_string(v)); } + None => (), } - }, - None => (), - }, + } + } + None => (), + }, None => (), } - + values } } From d42276ada91216f6cf051a896599ca886d65c070 Mon Sep 17 00:00:00 2001 From: Kazuminn Date: Fri, 25 Sep 2020 21:46:40 +0900 Subject: [PATCH 2/5] cargo fmt --all --- Cargo.lock | 1 + src/detections/common.rs | 18 ++++++------- src/detections/detection.rs | 32 +++++++++++------------- src/detections/mod.rs | 4 +-- src/detections/security.rs | 50 +++++++++++++++++++++---------------- src/detections/system.rs | 14 +++-------- src/lib.rs | 2 +- src/main.rs | 26 +++++++++---------- 8 files changed, 69 insertions(+), 78 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 09e48d8c..c3e1647b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1110,6 +1110,7 @@ dependencies = [ "clap", "evtx", "quick-xml 0.17.2", + "regex", "serde", "serde_json", ] diff --git a/src/detections/common.rs b/src/detections/common.rs index e2ad12b9..a9611b5d 100644 --- a/src/detections/common.rs +++ b/src/detections/common.rs @@ -1,15 +1,14 @@ -use std::collections::HashMap; use crate::models::event; +use std::collections::HashMap; #[derive(Debug)] pub struct Common { record_id: u64, date: String, - record_id_list : HashMap, + record_id_list: HashMap, } impl Common { - pub fn new() -> Common { Common { record_id: 0, @@ -19,30 +18,27 @@ impl Common { } pub fn disp(&self) { - for (record_id, date) in self.record_id_list.iter() { + for (record_id, date) in self.record_id_list.iter() { println!("date:{:?} record-id: {:?}", date, record_id); } } pub fn detection(&mut self, system: &event::System, event_data: &HashMap) { - &self.check_record_id(system); - } // // Record IDがシーケンスになっているかチェック // fn check_record_id(&mut self, system: &event::System) { - let event_record_id: u64 = system.event_record_id.parse().unwrap(); if self.record_id > 0 && event_record_id - self.record_id > 1 { - self.record_id_list.insert(self.record_id.to_string() + " - " + &system.event_record_id.to_string(), - self.date.to_string() + " - " + &system.time_created.system_time.to_string()); + self.record_id_list.insert( + self.record_id.to_string() + " - " + &system.event_record_id.to_string(), + self.date.to_string() + " - " + &system.time_created.system_time.to_string(), + ); } self.record_id = event_record_id; self.date = system.time_created.system_time.to_string(); } - } - diff --git a/src/detections/detection.rs b/src/detections/detection.rs index 66647349..81431af3 100644 --- a/src/detections/detection.rs +++ b/src/detections/detection.rs @@ -1,22 +1,21 @@ extern crate quick_xml; -use std::collections::BTreeMap; -use std::collections::HashMap; -use crate::models::event; -use evtx::EvtxParser; +use crate::detections::application; use crate::detections::common; use crate::detections::security; use crate::detections::system; -use crate::detections::application; -use quick_xml::de::{DeError}; +use crate::models::event; +use evtx::EvtxParser; +use quick_xml::de::DeError; +use std::collections::BTreeMap; +use std::collections::HashMap; #[derive(Debug)] pub struct Detection { - timeline_list : BTreeMap, + timeline_list: BTreeMap, } impl Detection { - pub fn new() -> Detection { Detection { timeline_list: BTreeMap::new(), @@ -24,12 +23,11 @@ impl Detection { } pub fn start(&mut self, mut parser: EvtxParser) -> Result<(), DeError> { - let mut common: common::Common = common::Common::new(); let mut security = security::Security::new(); let mut system = system::System::new(); let mut application = application::Application::new(); - + for record in parser.records() { match record { Ok(r) => { @@ -37,19 +35,19 @@ impl Detection { let event_id = event.system.event_id.to_string(); let channel = event.system.channel.to_string(); let event_data = event.parse_event_data(); - + &common.detection(&event.system, &event_data); - //&common.detection(&event.system, &event_data); + //&common.detection(&event.system, &event_data); if channel == "Security" { &security.detection(event_id, &event.system, event_data); } else if channel == "System" { &system.detection(); } else if channel == "Application" { - &application.detection(); + &application.detection(event_id, &event.system, event_data); } else { //&other.detection(); } - }, + } Err(e) => eprintln!("{}", e), } } @@ -59,9 +57,7 @@ impl Detection { //////////////////////////// common.disp(); security.disp(); - - return Ok(()) + + return Ok(()); } - } - diff --git a/src/detections/mod.rs b/src/detections/mod.rs index 52c40328..7238b4aa 100644 --- a/src/detections/mod.rs +++ b/src/detections/mod.rs @@ -1,5 +1,5 @@ +mod application; mod common; +pub mod detection; mod security; mod system; -mod application; -pub mod detection; diff --git a/src/detections/security.rs b/src/detections/security.rs index 8d55dfa3..f43d347a 100644 --- a/src/detections/security.rs +++ b/src/detections/security.rs @@ -1,5 +1,5 @@ -use std::collections::HashMap; use crate::models::event; +use std::collections::HashMap; #[derive(Debug)] pub struct Security { @@ -11,7 +11,7 @@ pub struct Security { impl Security { pub fn new() -> Security { - Security{ + Security { alert_all_admin: 0, total_admin_logons: 0, admin_logons: HashMap::new(), @@ -27,8 +27,12 @@ impl Security { } } - pub fn detection(&mut self, event_id: String, system: &event::System, event_data: HashMap) { - + pub fn detection( + &mut self, + event_id: String, + system: &event::System, + event_data: HashMap, + ) { if event_id == "4672" { &self.se_debug_privilege(event_data); } @@ -38,12 +42,10 @@ impl Security { // Special privileges assigned to new logon (possible admin access) // fn se_debug_privilege(&mut self, event_data: HashMap) { - match event_data.get("PrivilegeList") { Some(privileage_list) => { match privileage_list.find("SeDebugPrivilege") { Some(_data) => { - // alert_all_adminが有効であれば、標準出力して知らせる // DeepBlueCLIでは必ず0になっていて、基本的には表示されない。 if self.alert_all_admin == 1 { @@ -53,39 +55,43 @@ impl Security { println!("User SID:{}", event_data["SubjectUserSid"]); println!("Domain:{}", event_data["PrivilegeList"]); } - + self.total_admin_logons += 1; - + // admin_logons配列にusernameが含まれているか確認 match self.admin_logons.get(&event_data["SubjectUserName"]) { Some(sid) => { // 含まれていれば、マルチユーザが管理者としてログインしているか確認 // マルチログオンのデータをセット - if event_data["SubjectUserName"] != event_data["SubjectUserSid"] { // One username with multiple admin logon SIDs - self.multiple_admin_logons.insert(event_data["SubjectUserName"].to_string(),1); - + if event_data["SubjectUserName"] != event_data["SubjectUserSid"] { + // One username with multiple admin logon SIDs + self.multiple_admin_logons + .insert(event_data["SubjectUserName"].to_string(), 1); + let mut count_hash: HashMap = HashMap::new(); - count_hash.insert(event_data["SubjectUserSid"].to_string(), sid[&event_data["SubjectUserSid"]] + 1); - self.admin_logons.insert(event_data["SubjectUserName"].to_string(), count_hash); + count_hash.insert( + event_data["SubjectUserSid"].to_string(), + sid[&event_data["SubjectUserSid"]] + 1, + ); + self.admin_logons.insert( + event_data["SubjectUserName"].to_string(), + count_hash, + ); } - }, + } None => { // admin_logons配列にセットUserNameとSIDとカウンタをセット let mut count_hash: HashMap = HashMap::new(); count_hash.insert(event_data["SubjectUserSid"].to_string(), 1); - self.admin_logons.insert(event_data["SubjectUserName"].to_string(), count_hash); - + self.admin_logons + .insert(event_data["SubjectUserName"].to_string(), count_hash); } } - }, + } None => (), } - }, + } None => (), - } - } - } - diff --git a/src/detections/system.rs b/src/detections/system.rs index da7b3ee5..3c5b6401 100644 --- a/src/detections/system.rs +++ b/src/detections/system.rs @@ -1,15 +1,9 @@ - -pub struct System { - -} +pub struct System {} impl System { - pub fn new() -> System { - System{} + System {} } - pub fn detection(&self) { - - } -} \ No newline at end of file + pub fn detection(&self) {} +} diff --git a/src/lib.rs b/src/lib.rs index d91d16b9..2579ad53 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,2 +1,2 @@ -pub mod models; pub mod detections; +pub mod models; diff --git a/src/main.rs b/src/main.rs index 359c43f0..0777aad0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,19 +1,19 @@ -extern crate serde; extern crate clap; +extern crate serde; -use evtx::EvtxParser; -use std::{env, process, path::PathBuf}; -use quick_xml::de::{DeError}; -use yamato_event_analyzer::detections::detection; use clap::{App, AppSettings, Arg}; +use evtx::EvtxParser; +use quick_xml::de::DeError; +use std::{env, path::PathBuf, process}; +use yamato_event_analyzer::detections::detection; fn build_app() -> clap::App<'static, 'static> { let program = std::env::args() .nth(0) .and_then(|s| { std::path::PathBuf::from(s) - .file_stem() - .map(|s| s.to_string_lossy().into_owned()) + .file_stem() + .map(|s| s.to_string_lossy().into_owned()) }) .unwrap(); @@ -32,19 +32,17 @@ fn build_app() -> clap::App<'static, 'static> { .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'")) - } fn main() -> Result<(), DeError> { - let args = build_app().get_matches(); - let filepath : Option<&str> = args.value_of("filepath"); - + let filepath: Option<&str> = args.value_of("filepath"); + match filepath { Some(filepath) => parse_file(filepath), None => (), } - + Ok(()) } @@ -55,9 +53,9 @@ fn parse_file(filepath: &str) { Err(e) => { eprintln!("{}", e); process::exit(1); - }, + } }; - + let mut detection = detection::Detection::new(); &detection.start(parser); } From af1843b8a95ec01925225a5908dce2914137e533 Mon Sep 17 00:00:00 2001 From: Kazuminn Date: Sat, 26 Sep 2020 22:07:47 +0900 Subject: [PATCH 3/5] fix --- src/detections/application.rs | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/detections/application.rs b/src/detections/application.rs index 9622b359..a73b9300 100644 --- a/src/detections/application.rs +++ b/src/detections/application.rs @@ -17,11 +17,12 @@ impl Application { system: &event::System, event_data: HashMap, ) { - let _emet = String::from("EMET"); if event_id == "2" { match &system.provider.name { - Some(_emet) => { - &self.emet(system, event_data); + Some(name) => { + if (name == "EMET") { + &self.emet(system, event_data); + } } None => (), } @@ -32,16 +33,18 @@ impl Application { match &system.message { Some(message) => { let message_split: Vec<&str> = message.split("\n").collect(); - let text = message_split[0]; - let application = message_split[3]; - let re = Regex::new(r"^Application: ").unwrap(); - let command = re.replace_all(application, ""); - let username = message_split[4]; + if !message_split.is_empty() { + let text = message_split[0]; + let application = message_split[3]; + let re = Regex::new(r"^Application: ").unwrap(); + let command = re.replace_all(application, ""); + let username = message_split[4]; - println!("Message EMET Block"); - println!("Command {}", command); - println!("Results {}", text); - println!("Results {}", username); + println!("Message EMET Block"); + println!("Command {}", command); + println!("Results {}", text); + println!("Results {}", username); + } } None => { println!("Warning: EMET Message field is blank. Install EMET locally to see full details of this alert"); From 9a906d4c23948294b899d968c2db1b11b8e71f98 Mon Sep 17 00:00:00 2001 From: Kazuminn Date: Sat, 26 Sep 2020 22:26:30 +0900 Subject: [PATCH 4/5] refactor --- src/detections/application.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/detections/application.rs b/src/detections/application.rs index a73b9300..3de9e333 100644 --- a/src/detections/application.rs +++ b/src/detections/application.rs @@ -41,9 +41,9 @@ impl Application { let username = message_split[4]; println!("Message EMET Block"); - println!("Command {}", command); - println!("Results {}", text); - println!("Results {}", username); + println!("Command : {}", command); + println!("Results : {}", text); + println!("Results : {}", username); } } None => { From 2f03e502d14f033b9e83a068471e770f98a40dfd Mon Sep 17 00:00:00 2001 From: Kazuminn Date: Mon, 28 Sep 2020 13:07:50 +0900 Subject: [PATCH 5/5] fix --- src/detections/application.rs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/detections/application.rs b/src/detections/application.rs index 3de9e333..0ba374a3 100644 --- a/src/detections/application.rs +++ b/src/detections/application.rs @@ -18,22 +18,23 @@ impl Application { event_data: HashMap, ) { if event_id == "2" { - match &system.provider.name { - Some(name) => { - if (name == "EMET") { - &self.emet(system, event_data); - } - } - None => (), - } + &self.emet(system, event_data); } } fn emet(&mut self, system: &event::System, event_data: HashMap) { + match &system.provider.name { + Some(name) => { + if (name != "EMET") { + return; + } + } + None => return, + } match &system.message { Some(message) => { let message_split: Vec<&str> = message.split("\n").collect(); - if !message_split.is_empty() { + if !message_split.is_empty() && message_split.len() >= 5 { let text = message_split[0]; let application = message_split[3]; let re = Regex::new(r"^Application: ").unwrap();