diff --git a/Cargo.lock b/Cargo.lock index c3e1647b..ba27fb23 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -76,6 +76,18 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +[[package]] +name = "bstr" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31accafdb70df7871592c058eca3985b71104e15ac32f64706022c58867da931" +dependencies = [ + "lazy_static", + "memchr", + "regex-automata", + "serde", +] + [[package]] name = "build_const" version = "0.2.1" @@ -219,6 +231,28 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "csv" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00affe7f6ab566df61b4be3ce8cf16bc2576bca0963ceb0955e45d514bf9a279" +dependencies = [ + "bstr", + "csv-core", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" +dependencies = [ + "memchr", +] + [[package]] name = "dialoguer" version = "0.6.2" @@ -747,6 +781,15 @@ dependencies = [ "thread_local", ] +[[package]] +name = "regex-automata" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae1ded71d66a4a97f5e961fd0cb25a5f366a42a41570d16a763a69c092c26ae4" +dependencies = [ + "byteorder", +] + [[package]] name = "regex-syntax" version = "0.6.18" @@ -1108,6 +1151,7 @@ name = "yamato_event_analyzer" version = "0.1.0" dependencies = [ "clap", + "csv", "evtx", "quick-xml 0.17.2", "regex", diff --git a/Cargo.toml b/Cargo.toml index 04818b2c..406ca26c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,3 +13,4 @@ serde = { version = "1.0", features = ["derive"] } serde_json = { version = "1.0"} clap = "*" regex = "1" +csv = "1.1" diff --git a/regexes.txt b/regexes.txt new file mode 100644 index 00000000..f59a3792 --- /dev/null +++ b/regexes.txt @@ -0,0 +1,19 @@ +Type,regex,string +0,^cmd.exe /c echo [a-z]{6} > \\\\.\\pipe\\[a-z]{6}$,Metasploit-style cmd with pipe (possible use of Meterpreter 'getsystem') +0,^%SYSTEMROOT%\\[a-zA-Z]{8}\.exe$,Metasploit-style %SYSTEMROOT% image path (possible use of Metasploit 'Native upload' exploit payload) +0,powershell.*FromBase64String.*IO.Compression.GzipStream,Metasploit-style base64 encoded/compressed PowerShell function (possible use of Metasploit PowerShell exploit payload) +0,DownloadString\(.http,Download via Net.WebClient DownloadString +0,mimikatz,Command referencing Mimikatz +0,Invoke-Mimikatz.ps,PowerSploit Invoke-Mimikatz.ps1 +0,PowerSploit.*ps1,Use of PowerSploit +0,User-Agent,User-Agent set via command line +0,[a-zA-Z0-9/+=]{500},500+ consecutive Base64 characters +0,powershell.exe.*Hidden.*Enc,Base64 encoded and hidden PowerShell command +# Generic csc.exe alert, comment out if experiencing false positives +0,\\csc\.exe,Use of C Sharp compiler csc.exe +0,\\csc\.exe.*\\Appdata\\Local\\Temp\\[a-z0-9]{8}\.cmdline,PSAttack-style command via csc.exe +# Generic cvtres.exe alert, comment out if experiencing false positives +0,\\cvtres\.exe.*,Resource File To COFF Object Conversion Utility cvtres.exe +0,\\cvtres\.exe.*\\AppData\\Local\\Temp\\[A-Z0-9]{7}\.tmp,PSAttack-style command via cvtres.exe +1,^[a-zA-Z]{22}$,Metasploit-style service name: 22 characters, [A-Za-z] +1,^[a-zA-Z]{16}$,Metasploit-style service name: 16 characters, [A-Za-z] \ No newline at end of file diff --git a/src/detections/mod.rs b/src/detections/mod.rs index 7238b4aa..ba8b0f90 100644 --- a/src/detections/mod.rs +++ b/src/detections/mod.rs @@ -3,3 +3,4 @@ mod common; pub mod detection; mod security; mod system; +mod utils; diff --git a/src/detections/security.rs b/src/detections/security.rs index 82e23f71..16426937 100644 --- a/src/detections/security.rs +++ b/src/detections/security.rs @@ -42,7 +42,6 @@ impl Security { // Special privileges assigned to new logon (possible admin access) // fn se_debug_privilege(&mut self, event_data: HashMap) { - if let Some(privileage_list) = event_data.get("PrivilegeList") { if let Some(_data) = privileage_list.find("SeDebugPrivilege") { // alert_all_adminが有効であれば、標準出力して知らせる @@ -72,10 +71,8 @@ impl Security { event_data["SubjectUserSid"].to_string(), sid[&event_data["SubjectUserSid"]] + 1, ); - self.admin_logons.insert( - event_data["SubjectUserName"].to_string(), - count_hash, - ); + self.admin_logons + .insert(event_data["SubjectUserName"].to_string(), count_hash); } } None => { diff --git a/src/detections/utils.rs b/src/detections/utils.rs new file mode 100644 index 00000000..608e9010 --- /dev/null +++ b/src/detections/utils.rs @@ -0,0 +1,57 @@ +extern crate csv; +use std::env; +use std::fs::File; +use std::io::prelude::*; +use std::string::String; + +pub fn check_command() {} + +fn check_regex(string: &str, r#type: &str) -> 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 mut rdr = csv::Reader::from_reader(contents.as_bytes()); + + let mut regextext = "".to_string(); + for regex in rdr.records() { + match regex { + /* + data[0] is type. + data[1] is regex. + data[2] is string. + */ + Ok(_data) => { + if &_data[0] == r#type && &_data[1] == string { + regextext.push_str(&_data[2]); + regextext.push_str("\n"); + } + } + Err(_data) => (), + } + } + return regextext; +} + +fn check_creator(command: &str, creator: &str) -> std::string::String { + let mut creatortext = "".to_string(); + if (!creator.is_empty()) { + if (command == "powershell") { + if (creator == "PSEXESVC") { + creatortext.push_str("PowerShell launched via PsExec: $creator\n"); + } else if (creator == "WmiPrvSE") { + creatortext.push_str("PowerShell launched via WMI: $creator\n"); + } + } + } + return creatortext; +} + +#[cfg(test)] +mod tests { + use crate::detections::utils; + #[test] + fn test_check_regex() { + let result = utils::check_regex("test", "0"); + } +}