diff --git a/src/detections/detection.rs b/src/detections/detection.rs index 013e44fa..90d9cc25 100644 --- a/src/detections/detection.rs +++ b/src/detections/detection.rs @@ -1,7 +1,9 @@ +extern crate csv; extern crate quick_xml; use crate::detections::application; use crate::detections::common; +use crate::detections::powershell; use crate::detections::security; use crate::detections::sysmon; use crate::detections::system; @@ -9,6 +11,8 @@ use crate::models::event; use evtx::EvtxParser; use quick_xml::de::DeError; use std::collections::BTreeMap; +use std::fs::File; +use std::io::prelude::*; #[derive(Debug)] pub struct Detection { @@ -28,6 +32,13 @@ impl Detection { let mut system = system::System::new(); let mut application = application::Application::new(); let mut sysmon = sysmon::Sysmon::new(); + let mut powershell = powershell::PowerShell::new(); + + let mut f = File::open("whitelist.txt").expect("file not found"); + let mut contents = String::new(); + let _ = f.read_to_string(&mut contents); + + let mut rdr = csv::Reader::from_reader(contents.as_bytes()); for record in parser.records() { match record { @@ -45,6 +56,8 @@ impl Detection { &system.detection(event_id, &event.system, event_data); } else if channel == "Application" { &application.detection(event_id, &event.system, event_data); + } else if channel == "Microsoft-Windows-PowerShell/Operational" { + &powershell.detection(event_id, &event.system, event_data, &mut rdr); } else if channel == "Microsoft-Windows-Sysmon/Operational" { &sysmon.detection(event_id, &event.system, event_data); } else { diff --git a/src/detections/mod.rs b/src/detections/mod.rs index 344ab59a..d2012ac3 100644 --- a/src/detections/mod.rs +++ b/src/detections/mod.rs @@ -1,6 +1,7 @@ mod application; mod common; pub mod detection; +mod powershell; mod security; mod sysmon; mod system; diff --git a/src/detections/powershell.rs b/src/detections/powershell.rs new file mode 100644 index 00000000..df9edf53 --- /dev/null +++ b/src/detections/powershell.rs @@ -0,0 +1,67 @@ +use crate::detections::utils; +use crate::models::event; +use regex::Regex; +use std::collections::HashMap; +extern crate csv; + +pub struct PowerShell {} + +impl PowerShell { + pub fn new() -> PowerShell { + PowerShell {} + } + + pub fn detection( + &mut self, + event_id: String, + _system: &event::System, + event_data: HashMap, + rdr: &mut csv::Reader<&[u8]>, + ) { + if event_id == "4103" { + &self.execute_pipeline(&event_data, rdr); + } else if event_id == "4104" { + &self.execute_remote_command(&event_data, rdr); + } + } + + fn execute_pipeline( + &mut self, + event_data: &HashMap, + rdr: &mut csv::Reader<&[u8]>, + ) { + // パイプライン実行をしています + let default = String::from(""); + let commandline = event_data.get("ContextInfo").unwrap_or(&default); + + if commandline.contains("Host Application") + || commandline.contains("ホスト アプリケーション") + { + let rm_before = + Regex::new("(?ms)^.*(ホスト アプリケーション|Host Application) = ").unwrap(); + let rm_after = Regex::new("(?ms)\n.*$").unwrap(); + + let temp_command_with_extra = rm_before.replace_all(commandline, ""); + let command = rm_after.replace_all(&temp_command_with_extra, ""); + + if command != "" { + utils::check_command(4103, &command, 1000, 0, &default, &default, rdr); + } + } + } + + fn execute_remote_command( + &mut self, + event_data: &HashMap, + rdr: &mut csv::Reader<&[u8]>, + ) { + // リモートコマンドを実行します + let default = String::from(""); + let message_num = event_data.get("MessageNumber"); + let commandline = event_data.get("ScriptBlockText").unwrap_or(&default); + + if let Some(_) = message_num { + utils::check_command(4104, &commandline, 1000, 0, &default, &default, rdr); + } + } +} diff --git a/src/detections/utils.rs b/src/detections/utils.rs index 9a2ffdc3..ba9aaf39 100644 --- a/src/detections/utils.rs +++ b/src/detections/utils.rs @@ -16,7 +16,7 @@ pub fn check_command( servicecmd: usize, servicename: &str, creator: &str, - mut rdr: csv::Reader<&[u8]>, + rdr: &mut csv::Reader<&[u8]>, ) { let mut text = "".to_string(); let mut base64 = "".to_string(); @@ -148,7 +148,10 @@ fn check_obfu(string: &str) -> std::string::String { fn check_regex(string: &str, r#type: usize) -> std::string::String { let mut f = File::open("regexes.txt").expect("file not found"); let mut contents = String::new(); - f.read_to_string(&mut contents); + let ret = f.read_to_string(&mut contents); + if let Err(_) = ret { + return "".to_string(); + } let mut rdr = csv::Reader::from_reader(contents.as_bytes()); @@ -222,10 +225,9 @@ mod tests { let mut contents = String::new(); f.read_to_string(&mut contents); - let rdr = csv::Reader::from_reader(contents.as_bytes()); - utils::check_command(1, "dir", 100, 100, "dir", "dir", rdr); + let mut rdr = csv::Reader::from_reader(contents.as_bytes()); + utils::check_command(1, "dir", 100, 100, "dir", "dir", &mut rdr); - let rdr = csv::Reader::from_reader(contents.as_bytes()); //test return with whitelist. utils::check_command( 1, @@ -234,7 +236,7 @@ mod tests { 100, "dir", "dir", - rdr, + &mut rdr, ); } }