Squashed commit of the following:
commit 617f12177fbf5066e141b5c1adf969b25c03fa3c
Author: DustInDark <nextsasasa@gmail.com>
Date: Tue Dec 21 00:57:13 2021 +0900
fix test typo and merge #301
commit 78926ebf55ae48566152c4097990ca1b1b536b53
Merge: c492ba1 83d891b
Author: DustInDark <nextsasasa@gmail.com>
Date: Tue Dec 21 00:22:55 2021 +0900
Merge branch 'main' into feature/output_errorlog_file#301
commit c492ba120a0d977d909b714c2506bd198200853b
Author: DustInDark <nextsasasa@gmail.com>
Date: Tue Dec 21 00:18:52 2021 +0900
renamed hayabusa-logs to logs
commit ac018917300e535c2bfc62b6a9df081d4beb1568
Author: DustInDark <nextsasasa@gmail.com>
Date: Mon Dec 20 23:48:48 2021 +0900
changed output file path deprecated #303
commit dcef677117555f2fac929b6d3b24ac18b5fb08fc
Author: DustInDark <nextsasasa@gmail.com>
Date: Mon Dec 20 23:47:42 2021 +0900
removed error file delete logic
commit b09dec2e4a5c679c3b3c242a655f01cb3b49d490
Author: DustInDark <nextsasasa@gmail.com>
Date: Mon Dec 20 23:46:49 2021 +0900
fixed -Q option flag #309
This commit is contained in:
@@ -140,7 +140,7 @@ impl TargetEventTime {
|
|||||||
Err(err) => {
|
Err(err) => {
|
||||||
AlertMessage::alert(
|
AlertMessage::alert(
|
||||||
&mut std::io::stderr().lock(),
|
&mut std::io::stderr().lock(),
|
||||||
format!("starttimeline field: {}", err),
|
format!("start-timeline field: {}", err),
|
||||||
)
|
)
|
||||||
.ok();
|
.ok();
|
||||||
None
|
None
|
||||||
@@ -157,7 +157,7 @@ impl TargetEventTime {
|
|||||||
Err(err) => {
|
Err(err) => {
|
||||||
AlertMessage::alert(
|
AlertMessage::alert(
|
||||||
&mut std::io::stderr().lock(),
|
&mut std::io::stderr().lock(),
|
||||||
format!("endtimeline field: {}", err),
|
format!("end-timeline field: {}", err),
|
||||||
)
|
)
|
||||||
.ok();
|
.ok();
|
||||||
None
|
None
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
extern crate csv;
|
extern crate csv;
|
||||||
|
|
||||||
use crate::detections::print::AlertMessage;
|
use crate::detections::print::AlertMessage;
|
||||||
|
use crate::detections::print::ERROR_LOG_PATH;
|
||||||
use crate::detections::print::MESSAGES;
|
use crate::detections::print::MESSAGES;
|
||||||
use crate::detections::rule;
|
use crate::detections::rule;
|
||||||
use crate::detections::rule::AggResult;
|
use crate::detections::rule::AggResult;
|
||||||
@@ -11,9 +12,10 @@ use crate::yaml::ParseYaml;
|
|||||||
use hashbrown;
|
use hashbrown;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use tokio::{runtime::Runtime, spawn, task::JoinHandle};
|
use std::fs::OpenOptions;
|
||||||
|
use std::io::BufWriter;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use tokio::{runtime::Runtime, spawn, task::JoinHandle};
|
||||||
|
|
||||||
const DIRPATH_RULES: &str = "rules";
|
const DIRPATH_RULES: &str = "rules";
|
||||||
|
|
||||||
@@ -58,7 +60,12 @@ impl Detection {
|
|||||||
rulefile_loader.read_dir(rulespath.unwrap_or(DIRPATH_RULES), &level, exclude_ids);
|
rulefile_loader.read_dir(rulespath.unwrap_or(DIRPATH_RULES), &level, exclude_ids);
|
||||||
if result_readdir.is_err() {
|
if result_readdir.is_err() {
|
||||||
AlertMessage::alert(
|
AlertMessage::alert(
|
||||||
&mut std::io::stderr().lock(),
|
&mut BufWriter::new(
|
||||||
|
OpenOptions::new()
|
||||||
|
.append(true)
|
||||||
|
.open(ERROR_LOG_PATH.to_string())
|
||||||
|
.unwrap(),
|
||||||
|
),
|
||||||
format!("{}", result_readdir.unwrap_err()),
|
format!("{}", result_readdir.unwrap_err()),
|
||||||
)
|
)
|
||||||
.ok();
|
.ok();
|
||||||
|
|||||||
@@ -2,13 +2,18 @@ extern crate lazy_static;
|
|||||||
use crate::detections::configs;
|
use crate::detections::configs;
|
||||||
use crate::detections::utils;
|
use crate::detections::utils;
|
||||||
use crate::detections::utils::get_serde_number_to_string;
|
use crate::detections::utils::get_serde_number_to_string;
|
||||||
use chrono::{DateTime, TimeZone, Utc};
|
use chrono::{DateTime, Local, TimeZone, Utc};
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::env;
|
||||||
|
use std::fs::create_dir;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::BufWriter;
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
|
use std::path::Path;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -32,6 +37,15 @@ pub struct AlertMessage {}
|
|||||||
lazy_static! {
|
lazy_static! {
|
||||||
pub static ref MESSAGES: Mutex<Message> = Mutex::new(Message::new());
|
pub static ref MESSAGES: Mutex<Message> = Mutex::new(Message::new());
|
||||||
pub static ref ALIASREGEX: Regex = Regex::new(r"%[a-zA-Z0-9-_]+%").unwrap();
|
pub static ref ALIASREGEX: Regex = Regex::new(r"%[a-zA-Z0-9-_]+%").unwrap();
|
||||||
|
pub static ref ERROR_LOG_PATH: String = format!(
|
||||||
|
"./logs/errorlog-{}.log",
|
||||||
|
Local::now().format("%Y%m%d_%H%M%S")
|
||||||
|
);
|
||||||
|
pub static ref QUIET_ERRORS_FLAG: bool = configs::CONFIG
|
||||||
|
.read()
|
||||||
|
.unwrap()
|
||||||
|
.args
|
||||||
|
.is_present("quiet-errors");
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Message {
|
impl Message {
|
||||||
@@ -180,11 +194,56 @@ impl Message {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AlertMessage {
|
impl AlertMessage {
|
||||||
pub fn alert<W: Write>(w: &mut W, contents: String) -> io::Result<()> {
|
///対象のディレクトリが存在することを確認後、最初の定型文を追加して、ファイルのbufwriterを返す関数
|
||||||
writeln!(w, "[ERROR] {}", contents)
|
pub fn create_error_log(path_str: String) {
|
||||||
|
let path = Path::new(&path_str);
|
||||||
|
if !path.parent().unwrap().exists() {
|
||||||
|
create_dir(path.parent().unwrap()).ok();
|
||||||
}
|
}
|
||||||
|
// 1行目は必ず実行したコマンド情報を入れておく。
|
||||||
|
let mut ret = BufWriter::new(File::create(path).unwrap());
|
||||||
|
|
||||||
|
ret.write(
|
||||||
|
format!(
|
||||||
|
"user input: {:?}\n",
|
||||||
|
format_args!(
|
||||||
|
"{}",
|
||||||
|
env::args()
|
||||||
|
.map(|arg| arg)
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join(" ")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.as_bytes(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
ret.flush().ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ERRORメッセージを表示する関数
|
||||||
|
pub fn alert<W: Write>(w: &mut W, contents: String) -> io::Result<()> {
|
||||||
|
if !*QUIET_ERRORS_FLAG {
|
||||||
|
writeln!(w, "[ERROR] {}", contents)
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// WARNメッセージを表示する関数
|
||||||
pub fn warn<W: Write>(w: &mut W, contents: String) -> io::Result<()> {
|
pub fn warn<W: Write>(w: &mut W, contents: String) -> io::Result<()> {
|
||||||
|
if !*QUIET_ERRORS_FLAG {
|
||||||
writeln!(w, "[WARN] {}", contents)
|
writeln!(w, "[WARN] {}", contents)
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// エラーログへのERRORメッセージの出力数を確認して、0であったらファイルを削除する。1以上あればエラーを書き出した旨を標準出力に表示する
|
||||||
|
pub fn output_error_log_exist() {
|
||||||
|
println!(
|
||||||
|
"Generated error was output to {}. Please see the file for details.",
|
||||||
|
ERROR_LOG_PATH.to_string()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -314,7 +373,7 @@ mod tests {
|
|||||||
let input = "TESTWarn!";
|
let input = "TESTWarn!";
|
||||||
let stdout = std::io::stdout();
|
let stdout = std::io::stdout();
|
||||||
let mut stdout = stdout.lock();
|
let mut stdout = stdout.lock();
|
||||||
AlertMessage::alert(&mut stdout, input.to_string()).expect("[WARN] TESTWarn!");
|
AlertMessage::warn(&mut stdout, input.to_string()).expect("[WARN] TESTWarn!");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use crate::detections::print::AlertMessage;
|
use crate::detections::print::AlertMessage;
|
||||||
|
use crate::detections::print::ERROR_LOG_PATH;
|
||||||
use crate::detections::rule::AggResult;
|
use crate::detections::rule::AggResult;
|
||||||
use crate::detections::rule::AggregationParseInfo;
|
use crate::detections::rule::AggregationParseInfo;
|
||||||
use crate::detections::rule::Message;
|
use crate::detections::rule::Message;
|
||||||
@@ -6,6 +7,8 @@ use crate::detections::rule::RuleNode;
|
|||||||
use chrono::{DateTime, TimeZone, Utc};
|
use chrono::{DateTime, TimeZone, Utc};
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
use std::fs::OpenOptions;
|
||||||
|
use std::io::BufWriter;
|
||||||
use std::num::ParseIntError;
|
use std::num::ParseIntError;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
@@ -183,7 +186,12 @@ impl TimeFrameInfo {
|
|||||||
tnum.retain(|c| c != 'd');
|
tnum.retain(|c| c != 'd');
|
||||||
} else {
|
} else {
|
||||||
AlertMessage::alert(
|
AlertMessage::alert(
|
||||||
&mut std::io::stderr().lock(),
|
&mut BufWriter::new(
|
||||||
|
OpenOptions::new()
|
||||||
|
.append(true)
|
||||||
|
.open(ERROR_LOG_PATH.to_string())
|
||||||
|
.unwrap(),
|
||||||
|
),
|
||||||
format!("Timeframe is invalid. Input value:{}", value),
|
format!("Timeframe is invalid. Input value:{}", value),
|
||||||
)
|
)
|
||||||
.ok();
|
.ok();
|
||||||
@@ -215,7 +223,12 @@ pub fn get_sec_timeframe(timeframe: &Option<TimeFrameInfo>) -> Option<i64> {
|
|||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
AlertMessage::alert(
|
AlertMessage::alert(
|
||||||
&mut std::io::stderr().lock(),
|
&mut BufWriter::new(
|
||||||
|
OpenOptions::new()
|
||||||
|
.append(true)
|
||||||
|
.open(ERROR_LOG_PATH.to_string())
|
||||||
|
.unwrap(),
|
||||||
|
),
|
||||||
format!("Timeframe number is invalid. timeframe.{}", err),
|
format!("Timeframe number is invalid. timeframe.{}", err),
|
||||||
)
|
)
|
||||||
.ok();
|
.ok();
|
||||||
|
|||||||
42
src/main.rs
42
src/main.rs
@@ -6,6 +6,7 @@ use chrono::{DateTime, Local};
|
|||||||
use evtx::{EvtxParser, ParserSettings};
|
use evtx::{EvtxParser, ParserSettings};
|
||||||
use hayabusa::detections::detection::{self, EvtxRecordInfo};
|
use hayabusa::detections::detection::{self, EvtxRecordInfo};
|
||||||
use hayabusa::detections::print::AlertMessage;
|
use hayabusa::detections::print::AlertMessage;
|
||||||
|
use hayabusa::detections::print::ERROR_LOG_PATH;
|
||||||
use hayabusa::detections::rule::{get_detection_keys, RuleNode};
|
use hayabusa::detections::rule::{get_detection_keys, RuleNode};
|
||||||
use hayabusa::filter;
|
use hayabusa::filter;
|
||||||
use hayabusa::omikuji::Omikuji;
|
use hayabusa::omikuji::Omikuji;
|
||||||
@@ -16,6 +17,9 @@ use pbr::ProgressBar;
|
|||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
use std::fs::OpenOptions;
|
||||||
|
use std::io::BufWriter;
|
||||||
|
use std::path::Path;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::{
|
use std::{
|
||||||
fs::{self, File},
|
fs::{self, File},
|
||||||
@@ -66,6 +70,19 @@ impl App {
|
|||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if let Some(csv_path) = configs::CONFIG.read().unwrap().args.value_of("output") {
|
||||||
|
if Path::new(csv_path).exists() {
|
||||||
|
AlertMessage::alert(
|
||||||
|
&mut std::io::stderr().lock(),
|
||||||
|
format!(
|
||||||
|
" The file {} already exists. Please specify a different filename.",
|
||||||
|
csv_path
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.ok();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
if let Some(filepath) = configs::CONFIG.read().unwrap().args.value_of("filepath") {
|
if let Some(filepath) = configs::CONFIG.read().unwrap().args.value_of("filepath") {
|
||||||
if !filepath.ends_with(".evtx") {
|
if !filepath.ends_with(".evtx") {
|
||||||
AlertMessage::alert(
|
AlertMessage::alert(
|
||||||
@@ -100,14 +117,22 @@ impl App {
|
|||||||
let analysis_duration = analysis_end_time.signed_duration_since(analysis_start_time);
|
let analysis_duration = analysis_end_time.signed_duration_since(analysis_start_time);
|
||||||
println!("Elapsed Time: {}", &analysis_duration.hhmmssxxx());
|
println!("Elapsed Time: {}", &analysis_duration.hhmmssxxx());
|
||||||
println!("");
|
println!("");
|
||||||
|
AlertMessage::output_error_log_exist();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_evtxfiles(&self, dirpath: &str) -> Vec<PathBuf> {
|
fn collect_evtxfiles(&self, dirpath: &str) -> Vec<PathBuf> {
|
||||||
let entries = fs::read_dir(dirpath);
|
let entries = fs::read_dir(dirpath);
|
||||||
if entries.is_err() {
|
if entries.is_err() {
|
||||||
let stderr = std::io::stderr();
|
AlertMessage::alert(
|
||||||
let mut stderr = stderr.lock();
|
&mut BufWriter::new(
|
||||||
AlertMessage::alert(&mut stderr, format!("{}", entries.unwrap_err())).ok();
|
OpenOptions::new()
|
||||||
|
.append(true)
|
||||||
|
.open(ERROR_LOG_PATH.to_string())
|
||||||
|
.unwrap(),
|
||||||
|
),
|
||||||
|
format!("{}", entries.unwrap_err()),
|
||||||
|
)
|
||||||
|
.ok();
|
||||||
return vec![];
|
return vec![];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,7 +231,16 @@ impl App {
|
|||||||
evtx_filepath,
|
evtx_filepath,
|
||||||
record_result.unwrap_err()
|
record_result.unwrap_err()
|
||||||
);
|
);
|
||||||
AlertMessage::alert(&mut std::io::stderr().lock(), errmsg).ok();
|
AlertMessage::alert(
|
||||||
|
&mut BufWriter::new(
|
||||||
|
OpenOptions::new()
|
||||||
|
.append(true)
|
||||||
|
.open(ERROR_LOG_PATH.to_string())
|
||||||
|
.unwrap(),
|
||||||
|
),
|
||||||
|
errmsg,
|
||||||
|
)
|
||||||
|
.ok();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
17
src/yaml.rs
17
src/yaml.rs
@@ -3,11 +3,14 @@ extern crate yaml_rust;
|
|||||||
|
|
||||||
use crate::detections::configs;
|
use crate::detections::configs;
|
||||||
use crate::detections::print::AlertMessage;
|
use crate::detections::print::AlertMessage;
|
||||||
|
use crate::detections::print::ERROR_LOG_PATH;
|
||||||
use crate::filter::RuleExclude;
|
use crate::filter::RuleExclude;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::ffi::OsStr;
|
use std::ffi::OsStr;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
use std::fs::OpenOptions;
|
||||||
use std::io;
|
use std::io;
|
||||||
|
use std::io::BufWriter;
|
||||||
use std::io::{BufReader, Read};
|
use std::io::{BufReader, Read};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use yaml_rust::Yaml;
|
use yaml_rust::Yaml;
|
||||||
@@ -72,7 +75,12 @@ impl ParseYaml {
|
|||||||
let read_content = self.read_file(path);
|
let read_content = self.read_file(path);
|
||||||
if read_content.is_err() {
|
if read_content.is_err() {
|
||||||
AlertMessage::warn(
|
AlertMessage::warn(
|
||||||
&mut std::io::stdout().lock(),
|
&mut BufWriter::new(
|
||||||
|
OpenOptions::new()
|
||||||
|
.append(true)
|
||||||
|
.open(ERROR_LOG_PATH.to_string())
|
||||||
|
.unwrap(),
|
||||||
|
),
|
||||||
format!(
|
format!(
|
||||||
"fail to read file: {}\n{} ",
|
"fail to read file: {}\n{} ",
|
||||||
entry.path().display(),
|
entry.path().display(),
|
||||||
@@ -87,7 +95,12 @@ impl ParseYaml {
|
|||||||
let yaml_contents = YamlLoader::load_from_str(&read_content.unwrap());
|
let yaml_contents = YamlLoader::load_from_str(&read_content.unwrap());
|
||||||
if yaml_contents.is_err() {
|
if yaml_contents.is_err() {
|
||||||
AlertMessage::warn(
|
AlertMessage::warn(
|
||||||
&mut std::io::stdout().lock(),
|
&mut BufWriter::new(
|
||||||
|
OpenOptions::new()
|
||||||
|
.append(true)
|
||||||
|
.open(ERROR_LOG_PATH.to_string())
|
||||||
|
.unwrap(),
|
||||||
|
),
|
||||||
format!(
|
format!(
|
||||||
"Failed to parse yml: {}\n{} ",
|
"Failed to parse yml: {}\n{} ",
|
||||||
entry.path().display(),
|
entry.path().display(),
|
||||||
|
|||||||
Reference in New Issue
Block a user