merge feature/yaml
This commit is contained in:
8
Cargo.lock
generated
8
Cargo.lock
generated
@@ -139,14 +139,16 @@ checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "chrono"
|
name = "chrono"
|
||||||
version = "0.4.15"
|
version = "0.4.19"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "942f72db697d8767c22d46a598e01f2d3b475501ea43d0db4f16d90259182d0b"
|
checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"libc",
|
||||||
"num-integer",
|
"num-integer",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"serde",
|
"serde",
|
||||||
"time",
|
"time",
|
||||||
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1184,10 +1186,12 @@ name = "yamato_event_analyzer"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64",
|
"base64",
|
||||||
|
"chrono",
|
||||||
"clap",
|
"clap",
|
||||||
"csv",
|
"csv",
|
||||||
"evtx",
|
"evtx",
|
||||||
"flate2",
|
"flate2",
|
||||||
|
"lazy_static",
|
||||||
"quick-xml 0.17.2",
|
"quick-xml 0.17.2",
|
||||||
"regex",
|
"regex",
|
||||||
"serde",
|
"serde",
|
||||||
|
|||||||
@@ -17,4 +17,12 @@ regex = "1"
|
|||||||
csv = "1.1"
|
csv = "1.1"
|
||||||
base64 = "*"
|
base64 = "*"
|
||||||
flate2 = "1.0"
|
flate2 = "1.0"
|
||||||
|
lazy_static = "1.4.0"
|
||||||
|
chrono = "0.4.19"
|
||||||
yaml-rust = "0.4"
|
yaml-rust = "0.4"
|
||||||
|
|
||||||
|
[target.x86_64-pc-windows-gnu]
|
||||||
|
linker = "x86_64-w64-mingw32-gcc"
|
||||||
|
|
||||||
|
[target.i686-pc-windows-gnu]
|
||||||
|
linker = "i686-w64-mingw32-gcc"
|
||||||
|
|||||||
4
rules/deep_blue_cli/powershell/powershell4103.toml
Normal file
4
rules/deep_blue_cli/powershell/powershell4103.toml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
[rule]
|
||||||
|
severity = "high"
|
||||||
|
name = "4103"
|
||||||
|
message = "Execute Pipeline"
|
||||||
4
rules/deep_blue_cli/powershell/powershell4104.toml
Normal file
4
rules/deep_blue_cli/powershell/powershell4104.toml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
[rule]
|
||||||
|
severity = "high"
|
||||||
|
name = "4104"
|
||||||
|
message = "Excute Remote Command"
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use clap::{App, AppSettings, Arg, ArgMatches};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
use std::sync::Once;
|
use std::sync::Once;
|
||||||
@@ -6,6 +7,7 @@ use std::sync::Once;
|
|||||||
pub struct SingletonReader {
|
pub struct SingletonReader {
|
||||||
pub regex: Vec<Vec<String>>,
|
pub regex: Vec<Vec<String>>,
|
||||||
pub whitelist: Vec<Vec<String>>,
|
pub whitelist: Vec<Vec<String>>,
|
||||||
|
pub args: ArgMatches<'static>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn singleton() -> Box<SingletonReader> {
|
pub fn singleton() -> Box<SingletonReader> {
|
||||||
@@ -17,6 +19,7 @@ pub fn singleton() -> Box<SingletonReader> {
|
|||||||
let singleton = SingletonReader {
|
let singleton = SingletonReader {
|
||||||
regex: read_csv("regexes.txt"),
|
regex: read_csv("regexes.txt"),
|
||||||
whitelist: read_csv("whitelist.txt"),
|
whitelist: read_csv("whitelist.txt"),
|
||||||
|
args: build_app().get_matches(),
|
||||||
};
|
};
|
||||||
|
|
||||||
SINGLETON = Some(Box::new(singleton));
|
SINGLETON = Some(Box::new(singleton));
|
||||||
@@ -26,6 +29,33 @@ pub fn singleton() -> Box<SingletonReader> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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())
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
App::new(program)
|
||||||
|
.about("Yea! (Yamato Event Analyzer). Aiming to be the world's greatest Windows event log analysis tool!")
|
||||||
|
.version("0.0.1")
|
||||||
|
.author("Author name <author@example.com>")
|
||||||
|
.setting(AppSettings::VersionlessSubcommands)
|
||||||
|
.arg(Arg::from_usage("-f --filepath=[FILEPATH] 'event file path'"))
|
||||||
|
.arg(Arg::from_usage("--attackhunt=[ATTACK_HUNT] 'Attack Hunt'"))
|
||||||
|
.arg(Arg::from_usage("--csv-timeline=[CSV_TIMELINE] 'csv output timeline'"))
|
||||||
|
.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("-s --statistics 'event statistics'"))
|
||||||
|
.arg(Arg::from_usage("-u --update 'signature update'"))
|
||||||
|
.arg(Arg::from_usage("--credits 'Zachary Mathis, Akira Nishikawa'"))
|
||||||
|
}
|
||||||
|
|
||||||
fn read_csv(filename: &str) -> Vec<Vec<String>> {
|
fn read_csv(filename: &str) -> Vec<Vec<String>> {
|
||||||
let mut f = File::open(filename).expect("file not found!!!");
|
let mut f = File::open(filename).expect("file not found!!!");
|
||||||
let mut contents: String = String::new();
|
let mut contents: String = String::new();
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
mod application;
|
mod application;
|
||||||
mod applocker;
|
mod applocker;
|
||||||
mod common;
|
mod common;
|
||||||
mod configs;
|
pub mod configs;
|
||||||
pub mod detection;
|
pub mod detection;
|
||||||
mod powershell;
|
mod powershell;
|
||||||
|
pub mod print;
|
||||||
mod security;
|
mod security;
|
||||||
mod sysmon;
|
mod sysmon;
|
||||||
mod system;
|
mod system;
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ use crate::detections::utils;
|
|||||||
use crate::models::event;
|
use crate::models::event;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
extern crate csv;
|
|
||||||
|
|
||||||
pub struct PowerShell {}
|
pub struct PowerShell {}
|
||||||
|
|
||||||
@@ -25,6 +24,7 @@ impl PowerShell {
|
|||||||
if event_id != "4103" {
|
if event_id != "4103" {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let default = String::from("");
|
let default = String::from("");
|
||||||
let commandline = event_data.get("ContextInfo").unwrap_or(&default);
|
let commandline = event_data.get("ContextInfo").unwrap_or(&default);
|
||||||
|
|
||||||
@@ -48,6 +48,7 @@ impl PowerShell {
|
|||||||
if event_id != "4104" {
|
if event_id != "4104" {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let default = String::from("");
|
let default = String::from("");
|
||||||
let path = event_data.get("Path").unwrap().to_string();
|
let path = event_data.get("Path").unwrap().to_string();
|
||||||
if path == "".to_string() {
|
if path == "".to_string() {
|
||||||
|
|||||||
63
src/detections/print.rs
Normal file
63
src/detections/print.rs
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
extern crate chrono;
|
||||||
|
extern crate lazy_static;
|
||||||
|
use chrono::{DateTime, TimeZone, Utc};
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
use std::sync::Mutex;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Message {
|
||||||
|
map: BTreeMap<DateTime<Utc>, Vec<String>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
pub static ref MESSAGES: Mutex<Message> = Mutex::new(Message::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Message {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let messages: BTreeMap<DateTime<Utc>, Vec<String>> = BTreeMap::new();
|
||||||
|
Message { map: messages }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// メッセージを設定
|
||||||
|
pub fn insert(&mut self, time: DateTime<Utc>, message: String) {
|
||||||
|
match self.map.get_mut(&time) {
|
||||||
|
Some(v) => {
|
||||||
|
v.push(message.to_string());
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
let m = vec![message.to_string(); 1];
|
||||||
|
self.map.insert(time, m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// メッセージを返す
|
||||||
|
pub fn get(&self, time: DateTime<Utc>) -> Vec<String> {
|
||||||
|
match self.map.get(&time) {
|
||||||
|
Some(v) => (&v).to_vec(),
|
||||||
|
None => Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Messageのなかに入っているメッセージすべてを表示する
|
||||||
|
pub fn debug(&self) {
|
||||||
|
println!("{:?}", self.map);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_create_and_append_message() {
|
||||||
|
let mut message = Message::new();
|
||||||
|
let poke = Utc.ymd(1996, 2, 27).and_hms(1, 5, 1);
|
||||||
|
let taka = Utc.ymd(2000, 1, 21).and_hms(9, 6, 1);
|
||||||
|
|
||||||
|
message.insert(poke, "TEST".to_string());
|
||||||
|
message.insert(poke, "TEST2".to_string());
|
||||||
|
message.insert(taka, "TEST3".to_string());
|
||||||
|
|
||||||
|
let display = format!("{}", format_args!("{:?}", message));
|
||||||
|
let expect = "Message { map: {1996-02-27T01:05:01Z: [\"TEST\", \"TEST2\"], 2000-01-21T09:06:01Z: [\"TEST3\"]} }";
|
||||||
|
assert_eq!(display, expect);
|
||||||
|
}
|
||||||
@@ -56,29 +56,25 @@ pub fn check_command(
|
|||||||
let re = Regex::new(r"'.*$").unwrap();
|
let re = Regex::new(r"'.*$").unwrap();
|
||||||
base64.push_str(&re.replace_all(&base64.to_string(), ""));
|
base64.push_str(&re.replace_all(&base64.to_string(), ""));
|
||||||
}
|
}
|
||||||
|
if let Ok(decoded) = base64::decode(&base64) {
|
||||||
if !base64.is_empty() {
|
if !base64.is_empty() {
|
||||||
if Regex::new(r"Compression.GzipStream.*Decompress")
|
if Regex::new(r"Compression.GzipStream.*Decompress")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.is_match(commandline)
|
.is_match(commandline)
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
if let decoded = base64::decode(&base64) {
|
|
||||||
let mut d = GzDecoder::new(decoded.as_slice());
|
let mut d = GzDecoder::new(decoded.as_slice());
|
||||||
let mut uncompressed = String::new();
|
let mut uncompressed = String::new();
|
||||||
d.read_to_string(&mut uncompressed).unwrap();
|
d.read_to_string(&mut uncompressed).unwrap();
|
||||||
println!("Decoded : {}", uncompressed);
|
println!("Decoded : {}", uncompressed);
|
||||||
text.push_str("Base64-encoded and compressed function\n");
|
text.push_str("Base64-encoded and compressed function\n");
|
||||||
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
} else {
|
} else {
|
||||||
let decoded = base64::decode(base64).unwrap();
|
|
||||||
println!("Decoded : {}", str::from_utf8(decoded.as_slice()).unwrap());
|
println!("Decoded : {}", str::from_utf8(decoded.as_slice()).unwrap());
|
||||||
text.push_str("Base64-encoded function\n");
|
text.push_str("Base64-encoded function\n");
|
||||||
text.push_str(&check_obfu(str::from_utf8(decoded.as_slice()).unwrap()));
|
text.push_str(&check_obfu(str::from_utf8(decoded.as_slice()).unwrap()));
|
||||||
text.push_str(&check_regex(str::from_utf8(decoded.as_slice()).unwrap(), 0));
|
text.push_str(&check_regex(str::from_utf8(decoded.as_slice()).unwrap(), 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if !text.is_empty() {
|
if !text.is_empty() {
|
||||||
println!("EventID : {}", event_id);
|
println!("EventID : {}", event_id);
|
||||||
if servicecmd != 0 {
|
if servicecmd != 0 {
|
||||||
|
|||||||
44
src/main.rs
44
src/main.rs
@@ -1,48 +1,20 @@
|
|||||||
extern crate clap;
|
|
||||||
extern crate serde;
|
extern crate serde;
|
||||||
|
|
||||||
use clap::{App, AppSettings, Arg};
|
|
||||||
use evtx::EvtxParser;
|
use evtx::EvtxParser;
|
||||||
use quick_xml::de::DeError;
|
use quick_xml::de::DeError;
|
||||||
use std::{fs, path::PathBuf, process};
|
use std::{fs, path::PathBuf, process};
|
||||||
|
use yamato_event_analyzer::detections::configs;
|
||||||
use yamato_event_analyzer::detections::detection;
|
use yamato_event_analyzer::detections::detection;
|
||||||
use yamato_event_analyzer::omikuji::Omikuji;
|
use yamato_event_analyzer::omikuji::Omikuji;
|
||||||
use yamato_event_analyzer::yaml;
|
|
||||||
|
|
||||||
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())
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
App::new(program)
|
|
||||||
.about("Yea! (Yamato Event Analyzer). Aiming to be the world's greatest Windows event log analysis tool!")
|
|
||||||
.version("0.0.1")
|
|
||||||
.author("Author name <author@example.com>")
|
|
||||||
.setting(AppSettings::VersionlessSubcommands)
|
|
||||||
.arg(Arg::from_usage("-f --filepath=[FILEPATH] 'event file path'"))
|
|
||||||
.arg(Arg::from_usage("--attackhunt=[ATTACK_HUNT] 'Attack Hunt'"))
|
|
||||||
.arg(Arg::from_usage("--csv-timeline=[CSV_TIMELINE] 'csv output timeline'"))
|
|
||||||
.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("-s --statistics 'event statistics'"))
|
|
||||||
.arg(Arg::from_usage("-u --update 'signature update'"))
|
|
||||||
.arg(Arg::from_usage("-o --omikuji 'output with omikuji'"))
|
|
||||||
.arg(Arg::from_usage("--credits 'Zachary Mathis, Akira Nishikawa'"))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() -> Result<(), DeError> {
|
fn main() -> Result<(), DeError> {
|
||||||
let args = build_app().get_matches();
|
let filepath: String = configs::singleton()
|
||||||
let filepath: Option<&str> = args.value_of("filepath");
|
.args
|
||||||
|
.value_of("filepath")
|
||||||
if let Some(filepath) = filepath {
|
.unwrap_or("")
|
||||||
parse_file(filepath);
|
.to_string();
|
||||||
|
if filepath != "" {
|
||||||
|
parse_file(&filepath);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
Reference in New Issue
Block a user