This commit is contained in:
akiranishikawa
2020-09-18 18:48:23 +09:00
parent 1748aa1d2e
commit c9143dc7b6
13 changed files with 1357 additions and 1 deletions

3
.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
/target
/samples
*.test

1114
Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

14
Cargo.toml Normal file
View File

@@ -0,0 +1,14 @@
[package]
name = "yamato_event_analyzer"
version = "0.1.0"
authors = ["akiranishikawa <nishikawa@kagosec.net>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
evtx = { git = "https://github.com/omerbenamram/evtx.git" }
quick-xml = {version = "0.17", features = ["serialize"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = { version = "1.0"}

View File

@@ -1,2 +1,2 @@
# YamatoEventAnalyzer
Yea! (Yamato Event Analyzer). Aiming to be the world's greatest Windows event log analysis tool!
Yea! (Yamato Event Analyzer). Aiming to be the world's greatest Windows event log analysis tool!

0
config/signature.json Normal file
View File

View File

4
src/detections/mod.rs Normal file
View File

@@ -0,0 +1,4 @@
pub mod security;
pub mod system;
pub mod application;

View File

@@ -0,0 +1,58 @@
use std::collections::HashMap;
//
// Special privileges assigned to new logon (possible admin access)
//
pub fn se_debug_privilege(event_data: HashMap<String, String>,
alert_all_admin: i32, total_admin_logons: &mut i32,
admin_logons: &mut HashMap<String, HashMap<String, i32>>,
multiple_admin_logons: &mut HashMap<String, i32>) {
match event_data.get("PrivilegeList") {
Some(privileage_list) => {
match privileage_list.find("SeDebugPrivilege") {
Some(data) => {
// alert_all_adminが有効であれば、標準出力して知らせる
// DeepBlueCLIでは必ず0になっていて、基本的には表示されない。
if (alert_all_admin == 1) {
println!("Logon with SeDebugPrivilege (admin access)");
println!("Username:{}", event_data["SubjectUserName"]);
println!("Domain:{}", event_data["SubjectDomainName"]);
println!("User SID:{}", event_data["SubjectUserSid"]);
println!("Domain:{}", event_data["PrivilegeList"]);
}
*total_admin_logons += 1;
// admin_logons配列にusernameが含まれているか確認
match admin_logons.get(&event_data["SubjectUserName"]) {
Some(sid) => {
// 含まれていれば、マルチユーザが管理者としてログインしているか確認
// マルチログオンのデータをセット
if (event_data["SubjectUserName"] != event_data["SubjectUserSid"]) { // One username with multiple admin logon SIDs
multiple_admin_logons.insert(event_data["SubjectUserName"].to_string(),1);
let mut count_hash: HashMap<String, i32> = HashMap::new();
count_hash.insert(event_data["SubjectUserSid"].to_string(), sid[&event_data["SubjectUserSid"]] + 1);
admin_logons.insert(event_data["SubjectUserName"].to_string(), count_hash);
}
},
None => {
// admin_logons配列にセットUserNameとSIDとカウンタをセット
let mut count_hash: HashMap<String, i32> = HashMap::new();
count_hash.insert(event_data["SubjectUserSid"].to_string(), 1);
admin_logons.insert(event_data["SubjectUserName"].to_string(), count_hash);
}
}
},
None => (),
}
},
None => (),
}
}

0
src/detections/system.rs Normal file
View File

2
src/lib.rs Normal file
View File

@@ -0,0 +1,2 @@
pub mod models;
pub mod detections;

61
src/main.rs Normal file
View File

@@ -0,0 +1,61 @@
extern crate serde;
extern crate quick_xml;
use evtx::EvtxParser;
use std::env;
use std::process;
use std::path::PathBuf;
use std::collections::HashMap;
use quick_xml::de::{DeError};
use yamato_event_analyzer::models::event;
use yamato_event_analyzer::detections::security;
fn main() -> Result<(), DeError> {
let args: Vec<String> = env::args().collect();
let fp: PathBuf;
if (args.len() > 1) {
fp = PathBuf::from(args[1].to_string());
} else {
fp = PathBuf::from(format!("./samples/security.evtx"));
}
let alert_all_admin = 0;
let mut total_admin_logons = 0;
let mut admin_logons: HashMap<String, HashMap<String, i32>> = HashMap::new();
let mut multiple_admin_logons: HashMap<String, i32> = HashMap::new();
let mut parser = match EvtxParser::from_path(fp) {
Ok(pointer) => pointer,
Err(e) => {
eprintln!("{}", e);
process::exit(1);
},
};
for record in parser.records() {
match record {
Ok(r) => {
let event: event::Evtx = quick_xml::de::from_str(&r.data)?;
// ログがSecurity.evtxなら
if (event.System.Channel == "Security") {
if (event.System.EventID == "4672") {
let event_data = event.parse_event_data();
security::se_debug_privilege(event_data, alert_all_admin, &mut total_admin_logons,
&mut admin_logons, &mut multiple_admin_logons);
}
}
},
Err(e) => eprintln!("{}", e),
}
}
if (total_admin_logons > 0) {
println!("total_admin_logons:{}", total_admin_logons);
println!("admin_logons:{:?}", admin_logons);
println!("multiple_admin_logons:{:?}", multiple_admin_logons);
}
Ok(())
}

99
src/models/event.rs Normal file
View File

@@ -0,0 +1,99 @@
extern crate serde;
use serde::Deserialize;
use std::collections::HashMap;
#[derive(Debug, Deserialize, PartialEq)]
pub struct Data {
pub Name: Option<String>,
#[serde(rename = "$value")]
pub Text: Option<String>,
}
#[derive(Debug, Deserialize, PartialEq)]
struct TimeCreated {
SystemTime: String,
}
#[derive(Debug, Deserialize, PartialEq)]
struct Execution {
ProcessID: i32,
ThreadID: i32,
}
#[derive(Debug, Deserialize, PartialEq)]
struct Provider {
Name: Option<String>,
Guid: Option<String>,
}
#[derive(Debug, Deserialize, PartialEq)]
pub struct System {
Provider: Provider,
pub EventID: String,
Version: Option<String>,
Level: String,
Task: String,
Opcode: Option<String>,
Keywords: String,
TimeCreated: TimeCreated,
EventRecordID: String,
Correlation: Option<String>,
Execution: Option<Execution>,
pub Channel: String, // Security, System, Application ...etc
Computer: String,
Security: String,
}
#[derive(Debug, Deserialize, PartialEq)]
pub struct EventData {
pub Data: Option<Vec<Data>>,
}
#[derive(Debug, Deserialize, PartialEq)]
pub struct Evtx {
pub System: System,
pub EventData: Option<EventData>,
}
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<String,String> {
let mut values = HashMap::new();
match self.EventData {
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 => (),
}
values
}
}

1
src/models/mod.rs Normal file
View File

@@ -0,0 +1 @@
pub mod event;