message print

This commit is contained in:
akiranishikawa
2020-11-29 10:16:08 +09:00
parent 540eb8f4f5
commit 43cfd814a5
10 changed files with 130 additions and 214 deletions

View File

@@ -2,6 +2,7 @@ alias,event_key
EventID,Event.System.EventID EventID,Event.System.EventID
Channel,Event.System.Channel Channel,Event.System.Channel
CommandLine,Event.EventData.CommandLine CommandLine,Event.EventData.CommandLine
ParentProcessName,Event.EventData.ParentProcessName
Signed,Event.EventData.Signed Signed,Event.EventData.Signed
ProcessName,Event.EventData.ProcessName ProcessName,Event.EventData.ProcessName
AccessMask,Event.EventData.AccessMask AccessMask,Event.EventData.AccessMask
@@ -12,4 +13,7 @@ ServiceName,Event.EventData.ServiceName
ImagePath,Event.EventData.ImagePath ImagePath,Event.EventData.ImagePath
ContextInfo,Event.EventData.ContextInfo ContextInfo,Event.EventData.ContextInfo
Path,Event.EventData.Path Path,Event.EventData.Path
ScriptBlockText,Event.EventData.ScriptBlockText#Name ScriptBlockText,Event.EventData.ScriptBlockText#Name
MemberName,Event.EventData.SubjectUserName
MemberSid,Event.EventData.SubjectUserSid
TargetSid,Event.EventData.TargetSid

View File

@@ -1,44 +0,0 @@
use crate::models::event;
use std::collections::HashMap;
#[derive(Debug)]
pub struct Common {
record_id: u64,
date: String,
record_id_list: HashMap<String, String>,
}
impl Common {
pub fn new() -> Common {
Common {
record_id: 0,
date: "".to_string(),
record_id_list: HashMap::new(),
}
}
pub fn disp(&self) {
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<String, String>) {
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 = event_record_id;
self.date = system.time_created.system_time.to_string();
}
}

View File

@@ -53,7 +53,7 @@ fn build_app() -> clap::App<'static, 'static> {
.arg(Arg::from_usage("--credits 'Zachary Mathis, Akira Nishikawa'")) .arg(Arg::from_usage("--credits 'Zachary Mathis, Akira Nishikawa'"))
} }
#[derive(Clone)] #[derive(Debug, Clone)]
pub struct EventKeyAliasConfig { pub struct EventKeyAliasConfig {
key_to_eventkey: HashMap<String, String>, key_to_eventkey: HashMap<String, String>,
} }

View File

@@ -83,29 +83,28 @@ impl Detection {
// selection rule files and collect message // selection rule files and collect message
let mut message = Message::new(); let mut message = Message::new();
selection_rules.iter_mut().for_each(|rule| { selection_rules.iter_mut().for_each(|rule| {
&event_records event_records.iter().for_each(|event_record| {
.iter() if !rule.select(event_record) {
.filter(|event_record| rule.select(event_record)) return;
.for_each(|event_record| { }
let event_time = Detection::get_event_time(event_record);
// TODO ログから日付がとれない場合に本当は時刻不明という感じで表示したい。
// しかし、Messageクラスのinsertメソッドが、UTCクラスのインスタンスを必ず渡すようなインタフェースになっているので、
// やむなくUtc.ymd(1970, 1, 1).and_hms(0, 0, 0)を渡している。
// Messageクラスのinsertメソッドの引数をDateTime<UTC>からOption<DateTime<UTC>>に変更して、 let event_time = Detection::get_event_time(event_record);
// insertメソッドでOption::Noneが渡された場合に時刻不明だと分かるように表示させるような実装にした方がいいかも let utc_event_time = event_time
let utc_event_time = event_time .and_then(|datetime| {
.and_then(|datetime| { let utc = Utc.from_local_datetime(&datetime.naive_utc()).unwrap();
let utc = Utc.from_local_datetime(&datetime.naive_utc()).unwrap(); return Option::Some(utc);
return Option::Some(utc); })
}) .or(Option::None);
.or(Option::Some(Utc.ymd(1970, 1, 1).and_hms(0, 0, 0))); message.insert(
message.insert(utc_event_time.unwrap(), event_record.to_string()) utc_event_time,
}); event_record,
Some(rule.yaml["output"].as_str().unwrap().to_string()),
)
});
}); });
// output message // output message
message.debug(); message.print();
} }
fn get_event_time(event_record: &Value) -> Option<DateTime<FixedOffset>> { fn get_event_time(event_record: &Value) -> Option<DateTime<FixedOffset>> {

View File

@@ -1,4 +1,3 @@
mod common;
pub mod configs; pub mod configs;
pub mod detection; pub mod detection;
pub mod print; pub mod print;

View File

@@ -1,8 +1,12 @@
extern crate chrono; extern crate chrono;
extern crate lazy_static; extern crate lazy_static;
use crate::detections::configs;
use chrono::{DateTime, TimeZone, Utc}; use chrono::{DateTime, TimeZone, Utc};
use lazy_static::lazy_static; use lazy_static::lazy_static;
use regex::Regex;
use serde_json::Value;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::collections::HashMap;
use std::sync::Mutex; use std::sync::Mutex;
#[derive(Debug)] #[derive(Debug)]
@@ -21,18 +25,75 @@ impl Message {
} }
/// メッセージを設定 /// メッセージを設定
pub fn insert(&mut self, time: DateTime<Utc>, message: String) { pub fn insert(
match self.map.get_mut(&time) { &mut self,
mut time: Option<DateTime<Utc>>,
event_record: &Value,
output: Option<String>,
) {
if Option::None == output {
return;
}
let message = &self.parse_message(event_record, output);
if Option::None == time {
time = Option::Some(Utc.ymd(1970, 1, 1).and_hms(0, 0, 0));
}
match self.map.get_mut(&time.unwrap()) {
Some(v) => { Some(v) => {
v.push(message.to_string()); v.push(message.to_string());
} }
None => { None => {
let m = vec![message.to_string(); 1]; let m = vec![message.to_string(); 1];
self.map.insert(time, m); self.map.insert(time.unwrap(), m);
} }
} }
} }
fn parse_message(&mut self, event_record: &Value, output: Option<String>) -> String {
if Option::None == output {
return "".to_string();
}
let mut return_message: String = output.unwrap();
let mut hash_map: HashMap<String, String> = HashMap::new();
let re = Regex::new(r"%[a-zA-Z0-9-_]+%").unwrap();
for caps in re.captures_iter(&return_message) {
let full_target_str = &caps[0];
let target_length = full_target_str.chars().count() - 2; // The meaning of 2 is two percent
let target_str = full_target_str
.chars()
.skip(1)
.take(target_length)
.collect::<String>();
if let Some(array_str) = configs::singleton()
.event_key_alias_config
.get_event_key(target_str.to_string())
{
let split: Vec<&str> = array_str.split(".").collect();
let mut tmp_event_record: &Value = event_record.into();
for s in split {
if let Some(record) = tmp_event_record.get(s) {
tmp_event_record = record;
}
}
hash_map.insert(
full_target_str.to_string(),
tmp_event_record.as_str().unwrap_or("").to_string(),
);
}
}
for (k, v) in &hash_map {
return_message = return_message.replace(k, v);
}
return_message
}
/// メッセージを返す /// メッセージを返す
pub fn get(&self, time: DateTime<Utc>) -> Vec<String> { pub fn get(&self, time: DateTime<Utc>) -> Vec<String> {
match self.map.get(&time) { match self.map.get(&time) {
@@ -45,6 +106,15 @@ impl Message {
pub fn debug(&self) { pub fn debug(&self) {
println!("{:?}", self.map); println!("{:?}", self.map);
} }
/// 最後に表示を行う
pub fn print(&self) {
for (key, values) in self.map.iter() {
for value in values.iter() {
println!("{} : {}", key, value);
}
}
}
} }
#[test] #[test]
@@ -53,11 +123,39 @@ fn test_create_and_append_message() {
let poke = Utc.ymd(1996, 2, 27).and_hms(1, 5, 1); let poke = Utc.ymd(1996, 2, 27).and_hms(1, 5, 1);
let taka = Utc.ymd(2000, 1, 21).and_hms(9, 6, 1); let taka = Utc.ymd(2000, 1, 21).and_hms(9, 6, 1);
message.insert(poke, "TEST".to_string()); let json_str = r#"
message.insert(poke, "TEST2".to_string()); {
message.insert(taka, "TEST3".to_string()); "Event": {
"EventData": {
"CommandLine": "hoge"
}
}
}
"#;
let event_record: Value = serde_json::from_str(json_str).unwrap();
message.insert(
Some(poke),
&event_record,
Some("CommandLine1: %CommandLine%".to_string()),
);
message.insert(
Some(poke),
&event_record,
Some("CommandLine2: %CommandLine%".to_string()),
);
message.insert(
Some(taka),
&event_record,
Some("CommandLine3: %CommandLine%".to_string()),
);
message.insert(
Option::None,
&event_record,
Some("CommandLine4: %CommandLine%".to_string()),
);
let display = format!("{}", format_args!("{:?}", message)); let display = format!("{}", format_args!("{:?}", message));
let expect = "Message { map: {1996-02-27T01:05:01Z: [\"TEST\", \"TEST2\"], 2000-01-21T09:06:01Z: [\"TEST3\"]} }"; let expect = "Message { map: {1970-01-01T00:00:00Z: [\"CommandLine4: hoge\"], 1996-02-27T01:05:01Z: [\"CommandLine1: hoge\", \"CommandLine2: hoge\"], 2000-01-21T09:06:01Z: [\"CommandLine3: hoge\"]} }";
assert_eq!(display, expect); assert_eq!(display, expect);
} }

View File

@@ -1,4 +1,3 @@
pub mod detections; pub mod detections;
pub mod models;
pub mod omikuji; pub mod omikuji;
pub mod yaml; pub mod yaml;

View File

@@ -8,12 +8,7 @@ use yamato_event_analyzer::detections::detection;
use yamato_event_analyzer::omikuji::Omikuji; use yamato_event_analyzer::omikuji::Omikuji;
fn main() -> Result<(), DeError> { fn main() -> Result<(), DeError> {
let filepath: String = configs::singleton() if let Some(filepath) = configs::singleton().args.value_of("filepath") {
.args
.value_of("filepath")
.unwrap_or("")
.to_string();
if filepath != "" {
parse_file(&filepath); parse_file(&filepath);
} }

View File

@@ -1,133 +0,0 @@
extern crate serde;
use serde::Deserialize;
use std::collections::HashMap;
#[derive(Debug, Deserialize, PartialEq)]
pub struct Data {
#[serde(rename = "Name")]
pub name: Option<String>,
#[serde(rename = "$value")]
pub text: Option<String>,
}
#[derive(Debug, Deserialize, PartialEq)]
pub struct TimeCreated {
#[serde(rename = "SystemTime")]
pub system_time: String,
}
#[derive(Debug, Deserialize, PartialEq)]
struct Execution {
#[serde(rename = "ProcessID")]
process_id: i32,
#[serde(rename = "ThreadID")]
thread_id: i32,
}
#[derive(Debug, Deserialize, PartialEq)]
pub struct Provider {
#[serde(rename = "Name")]
pub name: Option<String>,
#[serde(rename = "Guid")]
guid: Option<String>,
}
#[derive(Debug, Deserialize, PartialEq)]
pub struct System {
#[serde(rename = "Provider")]
pub provider: Provider,
#[serde(rename = "EventID")]
pub event_id: String,
#[serde(rename = "Version")]
version: Option<String>,
#[serde(rename = "Level")]
level: String,
#[serde(rename = "Task")]
task: String,
#[serde(rename = "Opcode")]
opcode: Option<String>,
#[serde(rename = "Keywords")]
keywords: String,
#[serde(rename = "TimeCreated")]
pub time_created: TimeCreated,
#[serde(rename = "EventRecordID")]
pub event_record_id: String,
#[serde(rename = "Correlation")]
correlation: Option<String>,
#[serde(rename = "Execution")]
execution: Option<Execution>,
#[serde(rename = "Channel")]
pub channel: String, // Security, System, Application ...etc
#[serde(rename = "Computer")]
computer: String,
#[serde(rename = "Security")]
security: String,
#[serde(rename = "Message")]
pub message: Option<String>,
}
#[derive(Debug, Deserialize, PartialEq)]
pub struct EventData {
#[serde(rename = "Data")]
pub data: Option<Vec<Data>>,
}
#[derive(Debug, Deserialize, PartialEq)]
pub struct UserData {
#[serde(rename = "LogFileCleared")]
pub log_file_cleared: Option<LogFileCleared>,
}
#[derive(Debug, Deserialize, PartialEq)]
pub struct LogFileCleared {
#[serde(rename = "SubjectUserSid")]
pub subject_user_sid: Option<String>,
#[serde(rename = "SubjectUserName")]
pub subject_user_name: Option<String>,
#[serde(rename = "SubjectDomainName")]
pub subject_domain_name: Option<String>,
#[serde(rename = "SubjectLogonId")]
pub subject_logon_id: Option<String>,
}
#[derive(Debug, Deserialize, PartialEq)]
pub struct Evtx {
#[serde(rename = "System")]
pub system: System,
#[serde(rename = "EventData")]
pub event_data: Option<EventData>,
#[serde(rename = "UserData")]
pub user_data: Option<UserData>,
}
impl Evtx {
//
// 文字列データを取得する
//
fn get_string(v: &Data) -> String {
let mut ret = "".to_string();
if let Some(text) = &v.text {
ret = text.to_string();
}
return ret;
}
//
// EventDataをHashMapとして取得する
//
pub fn parse_event_data(&self) -> HashMap<String, String> {
let mut values = HashMap::new();
if let Some(event_data) = &self.event_data {
if let Some(data) = &event_data.data {
for v in data.iter() {
if let Some(name) = &v.name {
values.insert(name.to_string(), Evtx::get_string(v));
}
}
}
}
values
}
}

View File

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