Merge branch 'main' into 689-new-feature-html-summary-output
This commit is contained in:
@@ -188,9 +188,9 @@ pub struct Config {
|
||||
#[clap(help_heading = Some("ADVANCED"), short, long = "thread-number", value_name = "NUMBER")]
|
||||
pub thread_number: Option<usize>,
|
||||
|
||||
/// Print statistics of event IDs
|
||||
#[clap(help_heading = Some("OTHER-ACTIONS"), short, long)]
|
||||
pub statistics: bool,
|
||||
/// Print event ID metrics
|
||||
#[clap(help_heading = Some("OTHER-ACTIONS"), short='M', long)]
|
||||
pub metrics: bool,
|
||||
|
||||
/// Print a summary of successful and failed logons
|
||||
#[clap(help_heading = Some("OTHER-ACTIONS"), short = 'L', long = "logon-summary")]
|
||||
@@ -270,11 +270,11 @@ impl ConfigReader<'_> {
|
||||
args: parse.clone(),
|
||||
headless_help: String::default(),
|
||||
event_timeline_config: load_eventcode_info(
|
||||
utils::check_setting_path(&parse.config, "statistics_event_info.txt", false)
|
||||
utils::check_setting_path(&parse.config, "event_id_info.txt", false)
|
||||
.unwrap_or_else(|| {
|
||||
utils::check_setting_path(
|
||||
&CURRENT_EXE_PATH.to_path_buf(),
|
||||
"rules/config/statistics_event_info.txt",
|
||||
"rules/config/event_id_info.txt",
|
||||
true,
|
||||
)
|
||||
.unwrap()
|
||||
@@ -585,7 +585,7 @@ fn load_eventcode_info(path: &str) -> EventInfoConfig {
|
||||
return config;
|
||||
}
|
||||
|
||||
// statistics_event_infoが読み込めなかったらエラーで終了とする。
|
||||
// event_id_info.txtが読み込めなかったらエラーで終了とする。
|
||||
read_result.unwrap().into_iter().for_each(|line| {
|
||||
if line.len() != 2 {
|
||||
return;
|
||||
|
||||
@@ -14,7 +14,7 @@ use crate::detections::message::DetectInfo;
|
||||
use crate::detections::message::ERROR_LOG_STACK;
|
||||
use crate::detections::message::{CH_CONFIG, DEFAULT_DETAILS, TAGS_CONFIG};
|
||||
use crate::detections::message::{
|
||||
LOGONSUMMARY_FLAG, PIVOT_KEYWORD_LIST_FLAG, QUIET_ERRORS_FLAG, STATISTICS_FLAG,
|
||||
LOGONSUMMARY_FLAG, METRICS_FLAG, PIVOT_KEYWORD_LIST_FLAG, QUIET_ERRORS_FLAG,
|
||||
};
|
||||
use crate::detections::pivot::insert_pivot_keyword;
|
||||
use crate::detections::rule;
|
||||
@@ -600,7 +600,7 @@ impl Detection {
|
||||
st_rc: &HashMap<String, u128>,
|
||||
err_rc: &u128,
|
||||
) {
|
||||
if *STATISTICS_FLAG {
|
||||
if *METRICS_FLAG {
|
||||
return;
|
||||
}
|
||||
let mut sorted_ld_rc: Vec<(&String, &u128)> = ld_rc.iter().collect();
|
||||
|
||||
@@ -46,7 +46,7 @@ lazy_static! {
|
||||
);
|
||||
pub static ref QUIET_ERRORS_FLAG: bool = configs::CONFIG.read().unwrap().args.quiet_errors;
|
||||
pub static ref ERROR_LOG_STACK: Mutex<Vec<String>> = Mutex::new(Vec::new());
|
||||
pub static ref STATISTICS_FLAG: bool = configs::CONFIG.read().unwrap().args.statistics;
|
||||
pub static ref METRICS_FLAG: bool = configs::CONFIG.read().unwrap().args.metrics;
|
||||
pub static ref LOGONSUMMARY_FLAG: bool = configs::CONFIG.read().unwrap().args.logon_summary;
|
||||
pub static ref TAGS_CONFIG: HashMap<String, String> = create_output_filter_config(
|
||||
utils::check_setting_path(&CURRENT_EXE_PATH.to_path_buf(), "config/mitre_tactics.txt", true)
|
||||
|
||||
@@ -410,7 +410,7 @@ pub fn check_rule_config() -> Result<(), String> {
|
||||
"target_event_IDs.txt",
|
||||
"default_details.txt",
|
||||
"level_tuning.txt",
|
||||
"statistics_event_info.txt",
|
||||
"event_id_info.txt",
|
||||
"eventkey_alias.txt",
|
||||
];
|
||||
let mut not_exist_file = vec![];
|
||||
|
||||
+47
-10
@@ -11,8 +11,8 @@ use hayabusa::detections::configs::{load_pivot_keywords, TargetEventTime, TARGET
|
||||
use hayabusa::detections::configs::{CONFIG, CURRENT_EXE_PATH};
|
||||
use hayabusa::detections::detection::{self, EvtxRecordInfo};
|
||||
use hayabusa::detections::message::{
|
||||
AlertMessage, ERROR_LOG_PATH, ERROR_LOG_STACK, LOGONSUMMARY_FLAG, PIVOT_KEYWORD_LIST_FLAG,
|
||||
QUIET_ERRORS_FLAG, STATISTICS_FLAG,
|
||||
AlertMessage, ERROR_LOG_PATH, ERROR_LOG_STACK, LOGONSUMMARY_FLAG, METRICS_FLAG,
|
||||
PIVOT_KEYWORD_LIST_FLAG, QUIET_ERRORS_FLAG,
|
||||
};
|
||||
use hayabusa::detections::pivot::PivotKeyword;
|
||||
use hayabusa::detections::pivot::PIVOT_KEYWORD;
|
||||
@@ -20,7 +20,7 @@ use hayabusa::detections::rule::{get_detection_keys, RuleNode};
|
||||
use hayabusa::omikuji::Omikuji;
|
||||
use hayabusa::options::htmlreport::{self, HTML_REPORTER};
|
||||
use hayabusa::options::profile::PROFILES;
|
||||
use hayabusa::options::{level_tuning::LevelTuning, update_rules::UpdateRules};
|
||||
use hayabusa::options::{level_tuning::LevelTuning, update::Update};
|
||||
use hayabusa::{afterfact::after_fact, detections::utils};
|
||||
use hayabusa::{detections::configs, timeline::timelines::Timeline};
|
||||
use hayabusa::{detections::utils::write_color_buffer, filter};
|
||||
@@ -128,9 +128,19 @@ impl App {
|
||||
}
|
||||
|
||||
if configs::CONFIG.read().unwrap().args.update_rules {
|
||||
match UpdateRules::update_rules(
|
||||
configs::CONFIG.read().unwrap().args.rules.to_str().unwrap(),
|
||||
) {
|
||||
// エラーが出た場合はインターネット接続がそもそもできないなどの問題点もあるためエラー等の出力は行わない
|
||||
let latest_version_data = if let Ok(data) = Update::get_latest_hayabusa_version() {
|
||||
data
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let now_version = &format!(
|
||||
"v{}",
|
||||
configs::CONFIG.read().unwrap().app.get_version().unwrap()
|
||||
);
|
||||
|
||||
match Update::update_rules(configs::CONFIG.read().unwrap().args.rules.to_str().unwrap())
|
||||
{
|
||||
Ok(output) => {
|
||||
if output != "You currently have the latest rules." {
|
||||
write_color_buffer(
|
||||
@@ -147,6 +157,33 @@ impl App {
|
||||
}
|
||||
}
|
||||
println!();
|
||||
if latest_version_data.is_some()
|
||||
&& now_version
|
||||
!= &latest_version_data
|
||||
.as_ref()
|
||||
.unwrap_or(now_version)
|
||||
.replace('\"', "")
|
||||
{
|
||||
write_color_buffer(
|
||||
&BufferWriter::stdout(ColorChoice::Always),
|
||||
None,
|
||||
&format!(
|
||||
"There is a new version of Hayabusa: {}",
|
||||
latest_version_data.unwrap().replace('\"', "")
|
||||
),
|
||||
true,
|
||||
)
|
||||
.ok();
|
||||
write_color_buffer(
|
||||
&BufferWriter::stdout(ColorChoice::Always),
|
||||
None,
|
||||
"You can download it at https://github.com/Yamato-Security/hayabusa/releases",
|
||||
true,
|
||||
)
|
||||
.ok();
|
||||
}
|
||||
println!();
|
||||
|
||||
return;
|
||||
}
|
||||
// 実行時のexeファイルのパスをベースに変更する必要があるためデフォルトの値であった場合はそのexeファイルと同一階層を探すようにする
|
||||
@@ -203,11 +240,11 @@ impl App {
|
||||
return;
|
||||
}
|
||||
|
||||
if *STATISTICS_FLAG {
|
||||
if *METRICS_FLAG {
|
||||
write_color_buffer(
|
||||
&BufferWriter::stdout(ColorChoice::Always),
|
||||
None,
|
||||
"Generating Event ID Statistics",
|
||||
"Generating Event ID Metrics",
|
||||
true,
|
||||
)
|
||||
.ok();
|
||||
@@ -613,7 +650,7 @@ impl App {
|
||||
}
|
||||
println!();
|
||||
detection.add_aggcondition_msges(&self.rt);
|
||||
if !(*STATISTICS_FLAG || *LOGONSUMMARY_FLAG || *PIVOT_KEYWORD_LIST_FLAG) {
|
||||
if !(*METRICS_FLAG || *LOGONSUMMARY_FLAG || *PIVOT_KEYWORD_LIST_FLAG) {
|
||||
after_fact(total_records);
|
||||
}
|
||||
}
|
||||
@@ -695,7 +732,7 @@ impl App {
|
||||
// timeline機能の実行
|
||||
tl.start(&records_per_detect);
|
||||
|
||||
if !(*STATISTICS_FLAG || *LOGONSUMMARY_FLAG) {
|
||||
if !(*METRICS_FLAG || *LOGONSUMMARY_FLAG) {
|
||||
// ruleファイルの検知
|
||||
detection = detection.start(&self.rt, records_per_detect);
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
pub mod htmlreport;
|
||||
pub mod level_tuning;
|
||||
pub mod profile;
|
||||
pub mod update_rules;
|
||||
pub mod update;
|
||||
|
||||
@@ -4,6 +4,7 @@ use crate::filter;
|
||||
use crate::yaml::ParseYaml;
|
||||
use chrono::{DateTime, Local, TimeZone};
|
||||
use git2::Repository;
|
||||
use serde_json::Value;
|
||||
use std::fs::{self};
|
||||
use std::path::Path;
|
||||
|
||||
@@ -16,9 +17,26 @@ use std::fs::create_dir;
|
||||
|
||||
use termcolor::{BufferWriter, ColorChoice};
|
||||
|
||||
pub struct UpdateRules {}
|
||||
pub struct Update {}
|
||||
|
||||
impl Update {
|
||||
/// get latest hayabusa version number.
|
||||
pub fn get_latest_hayabusa_version() -> Result<Option<String>, Box<dyn std::error::Error>> {
|
||||
let res = reqwest::blocking::Client::new()
|
||||
.get("https://api.github.com/repos/Yamato-Security/hayabusa/releases/latest")
|
||||
.header("User-Agent", "HayabusaUpdateChecker")
|
||||
.header("Accept", "application/vnd.github.v3+json")
|
||||
.send()?;
|
||||
let text = res.text()?;
|
||||
let json_res: Value = serde_json::from_str(&text)?;
|
||||
|
||||
if json_res["tag_name"].is_null() {
|
||||
Ok(None)
|
||||
} else {
|
||||
Ok(Some(json_res["tag_name"].to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
impl UpdateRules {
|
||||
/// update rules(hayabusa-rules subrepository)
|
||||
pub fn update_rules(rule_path: &str) -> Result<String, git2::Error> {
|
||||
let mut result;
|
||||
@@ -35,14 +53,14 @@ impl UpdateRules {
|
||||
)
|
||||
.ok();
|
||||
// execution git clone of hayabusa-rules repository when failed open hayabusa repository.
|
||||
result = UpdateRules::clone_rules(Path::new(rule_path));
|
||||
result = Update::clone_rules(Path::new(rule_path));
|
||||
} else if hayabusa_rule_repo.is_ok() {
|
||||
// case of exist hayabusa-rules repository
|
||||
UpdateRules::_repo_main_reset_hard(hayabusa_rule_repo.as_ref().unwrap())?;
|
||||
Update::_repo_main_reset_hard(hayabusa_rule_repo.as_ref().unwrap())?;
|
||||
// case of failed fetching origin/main, git clone is not executed so network error has occurred possibly.
|
||||
prev_modified_rules = UpdateRules::get_updated_rules(rule_path, &prev_modified_time);
|
||||
prev_modified_rules = Update::get_updated_rules(rule_path, &prev_modified_time);
|
||||
prev_modified_time = fs::metadata(rule_path).unwrap().modified().unwrap();
|
||||
result = UpdateRules::pull_repository(&hayabusa_rule_repo.unwrap());
|
||||
result = Update::pull_repository(&hayabusa_rule_repo.unwrap());
|
||||
} else {
|
||||
// case of no exist hayabusa-rules repository in rules.
|
||||
// execute update because submodule information exists if hayabusa repository exists submodule information.
|
||||
@@ -61,7 +79,7 @@ impl UpdateRules {
|
||||
for mut submodule in submodules {
|
||||
submodule.update(true, None)?;
|
||||
let submodule_repo = submodule.open()?;
|
||||
if let Err(e) = UpdateRules::pull_repository(&submodule_repo) {
|
||||
if let Err(e) = Update::pull_repository(&submodule_repo) {
|
||||
AlertMessage::alert(&format!("Failed submodule update. {}", e)).ok();
|
||||
is_success_submodule_update = false;
|
||||
}
|
||||
@@ -80,16 +98,13 @@ impl UpdateRules {
|
||||
)
|
||||
.ok();
|
||||
// execution git clone of hayabusa-rules repository when failed open hayabusa repository.
|
||||
result = UpdateRules::clone_rules(rules_path);
|
||||
result = Update::clone_rules(rules_path);
|
||||
}
|
||||
}
|
||||
if result.is_ok() {
|
||||
let updated_modified_rules =
|
||||
UpdateRules::get_updated_rules(rule_path, &prev_modified_time);
|
||||
result = UpdateRules::print_diff_modified_rule_dates(
|
||||
prev_modified_rules,
|
||||
updated_modified_rules,
|
||||
);
|
||||
let updated_modified_rules = Update::get_updated_rules(rule_path, &prev_modified_time);
|
||||
result =
|
||||
Update::print_diff_modified_rule_dates(prev_modified_rules, updated_modified_rules);
|
||||
}
|
||||
result
|
||||
}
|
||||
@@ -254,7 +269,7 @@ impl UpdateRules {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::options::update_rules::UpdateRules;
|
||||
use crate::options::update::Update;
|
||||
use std::time::SystemTime;
|
||||
|
||||
#[test]
|
||||
@@ -262,12 +277,12 @@ mod tests {
|
||||
let prev_modified_time: SystemTime = SystemTime::UNIX_EPOCH;
|
||||
|
||||
let prev_modified_rules =
|
||||
UpdateRules::get_updated_rules("test_files/rules/level_yaml", &prev_modified_time);
|
||||
Update::get_updated_rules("test_files/rules/level_yaml", &prev_modified_time);
|
||||
assert_eq!(prev_modified_rules.len(), 5);
|
||||
|
||||
let target_time: SystemTime = SystemTime::now();
|
||||
let prev_modified_rules2 =
|
||||
UpdateRules::get_updated_rules("test_files/rules/level_yaml", &target_time);
|
||||
Update::get_updated_rules("test_files/rules/level_yaml", &target_time);
|
||||
assert_eq!(prev_modified_rules2.len(), 0);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
use crate::detections::message::{LOGONSUMMARY_FLAG, STATISTICS_FLAG};
|
||||
use crate::detections::message::{LOGONSUMMARY_FLAG, METRICS_FLAG};
|
||||
use crate::detections::{detection::EvtxRecordInfo, utils};
|
||||
use hashbrown::HashMap;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct EventStatistics {
|
||||
pub struct EventMetrics {
|
||||
pub total: usize,
|
||||
pub filepath: String,
|
||||
pub start_time: String,
|
||||
@@ -14,7 +14,7 @@ pub struct EventStatistics {
|
||||
/**
|
||||
* Windows Event Logの統計情報を出力する
|
||||
*/
|
||||
impl EventStatistics {
|
||||
impl EventMetrics {
|
||||
pub fn new(
|
||||
total: usize,
|
||||
filepath: String,
|
||||
@@ -22,8 +22,8 @@ impl EventStatistics {
|
||||
end_time: String,
|
||||
stats_list: HashMap<String, usize>,
|
||||
stats_login_list: HashMap<String, [usize; 2]>,
|
||||
) -> EventStatistics {
|
||||
EventStatistics {
|
||||
) -> EventMetrics {
|
||||
EventMetrics {
|
||||
total,
|
||||
filepath,
|
||||
start_time,
|
||||
@@ -34,8 +34,8 @@ impl EventStatistics {
|
||||
}
|
||||
|
||||
pub fn evt_stats_start(&mut self, records: &[EvtxRecordInfo]) {
|
||||
// 引数でstatisticsオプションが指定されている時だけ、統計情報を出力する。
|
||||
if !*STATISTICS_FLAG {
|
||||
// 引数でmetricsオプションが指定されている時だけ、統計情報を出力する。
|
||||
if !*METRICS_FLAG {
|
||||
return;
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,2 +1,2 @@
|
||||
pub mod statistics;
|
||||
pub mod metrics;
|
||||
pub mod timelines;
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
use crate::detections::message::{LOGONSUMMARY_FLAG, STATISTICS_FLAG};
|
||||
use crate::detections::message::{LOGONSUMMARY_FLAG, METRICS_FLAG};
|
||||
use crate::detections::{configs::CONFIG, detection::EvtxRecordInfo};
|
||||
use prettytable::{Cell, Row, Table};
|
||||
|
||||
use super::statistics::EventStatistics;
|
||||
use super::metrics::EventMetrics;
|
||||
use hashbrown::HashMap;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Timeline {
|
||||
pub stats: EventStatistics,
|
||||
pub stats: EventMetrics,
|
||||
}
|
||||
|
||||
impl Default for Timeline {
|
||||
@@ -26,7 +26,7 @@ impl Timeline {
|
||||
let statsloginlst = HashMap::new();
|
||||
|
||||
let statistic =
|
||||
EventStatistics::new(totalcnt, filepath, starttm, endtm, statslst, statsloginlst);
|
||||
EventMetrics::new(totalcnt, filepath, starttm, endtm, statslst, statsloginlst);
|
||||
Timeline { stats: statistic }
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ impl Timeline {
|
||||
}
|
||||
|
||||
pub fn tm_stats_dsp_msg(&mut self) {
|
||||
if !*STATISTICS_FLAG {
|
||||
if !*METRICS_FLAG {
|
||||
return;
|
||||
}
|
||||
// 出力メッセージ作成
|
||||
@@ -98,7 +98,7 @@ impl Timeline {
|
||||
.event_timeline_config
|
||||
.get_event_id(*event_id)
|
||||
.is_some();
|
||||
// statistics_event_info.txtに登録あるものは情報設定
|
||||
// event_id_info.txtに登録あるものは情報設定
|
||||
if conf {
|
||||
// 出力メッセージ1行作成
|
||||
msges.push(format!(
|
||||
|
||||
Reference in New Issue
Block a user