Merge branch 'main' into 603-bug-non-utf-8-byte-sequences-error-with-color-output
This commit is contained in:
@@ -12,6 +12,7 @@
|
|||||||
- ルール内に`details`フィールドがないときに、`rules/config/default_details.txt`に設定されたデフォルトの出力を行えるようにした。 (#359) (@hitenkoku)
|
- ルール内に`details`フィールドがないときに、`rules/config/default_details.txt`に設定されたデフォルトの出力を行えるようにした。 (#359) (@hitenkoku)
|
||||||
- Clap Crateパッケージの更新 (#413) (@hitenkoku)
|
- Clap Crateパッケージの更新 (#413) (@hitenkoku)
|
||||||
- オプションの指定がないときに、`--help`と同じ画面出力を行うように変更した。(#387) (@hitenkoku)
|
- オプションの指定がないときに、`--help`と同じ画面出力を行うように変更した。(#387) (@hitenkoku)
|
||||||
|
- hayabusa.exeをカレントワーキングディレクトリ以外から動作できるようにした。 (#592) (@hitenkoku)
|
||||||
- `output` オプションで指定されファイルのサイズを出力するようにした。 (#595) (@hitenkoku)
|
- `output` オプションで指定されファイルのサイズを出力するようにした。 (#595) (@hitenkoku)
|
||||||
|
|
||||||
**バグ修正:**
|
**バグ修正:**
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
- Added default details output based on `rules/config/default_details.txt` when no `details` field in a rule is specified. (i.e. Sigma rules) (#359) (@hitenkoku)
|
- Added default details output based on `rules/config/default_details.txt` when no `details` field in a rule is specified. (i.e. Sigma rules) (#359) (@hitenkoku)
|
||||||
- Updated clap crate package to version 3. (#413) (@hitnekoku)
|
- Updated clap crate package to version 3. (#413) (@hitnekoku)
|
||||||
- Updated the default usage and help menu. (#387) (@hitenkoku)
|
- Updated the default usage and help menu. (#387) (@hitenkoku)
|
||||||
|
- Hayabusa can be run from any directory, not just from the current directory. (#592) (@hitenkoku)
|
||||||
- Added saved file size output when `output` is specified. (#595) (@hitenkoku)
|
- Added saved file size output when `output` is specified. (#595) (@hitenkoku)
|
||||||
|
|
||||||
**Bug Fixes:**
|
**Bug Fixes:**
|
||||||
|
|||||||
@@ -323,42 +323,42 @@ USAGE:
|
|||||||
hayabusa.exe -f file.evtx [OPTIONS] / hayabusa.exe -d evtx-directory [OPTIONS]
|
hayabusa.exe -f file.evtx [OPTIONS] / hayabusa.exe -d evtx-directory [OPTIONS]
|
||||||
|
|
||||||
OPTIONS:
|
OPTIONS:
|
||||||
--European-time ヨーロッパ形式で日付と時刻を出力する (例: 22-02-2022 22:00:00.123 +02:00)
|
--European-time ヨーロッパ形式で日付と時刻を出力する (例: 22-02-2022 22:00:00.123 +02:00)
|
||||||
--RFC-2822 RFC 2822形式で日付と時刻を出力する (例: Fri, 22 Feb 2022 22:00:00 -0600)
|
--RFC-2822 RFC 2822形式で日付と時刻を出力する (例: Fri, 22 Feb 2022 22:00:00 -0600)
|
||||||
--RFC-3339 RFC 3339形式で日付と時刻を出力する (例: 2022-02-22 22:00:00.123456-06:00)
|
--RFC-3339 RFC 3339形式で日付と時刻を出力する (例: 2022-02-22 22:00:00.123456-06:00)
|
||||||
--US-military-time 24時間制(ミリタリータイム)のアメリカ形式で日付と時刻を出力する (例: 02-22-2022 22:00:00.123 -06:00)
|
--US-military-time 24時間制(ミリタリータイム)のアメリカ形式で日付と時刻を出力する (例: 02-22-2022 22:00:00.123 -06:00)
|
||||||
--US-time アメリカ形式で日付と時刻を出力する (例: 02-22-2022 10:00:00.123 PM -06:00)
|
--US-time アメリカ形式で日付と時刻を出力する (例: 02-22-2022 10:00:00.123 PM -06:00)
|
||||||
--target-file-ext <EVTX_FILE_EXT>... evtx以外の拡張子を解析対象に追加する。 (例1: evtx_data 例2:evtx1 evtx2)
|
--target-file-ext <EVTX_FILE_EXT>... evtx以外の拡張子を解析対象に追加する。 (例1: evtx_data 例2:evtx1 evtx2)
|
||||||
--all-tags 出力したCSVファイルにルール内のタグ情報を全て出力する
|
--all-tags 出力したCSVファイルにルール内のタグ情報を全て出力する
|
||||||
-c, --config <RULE_CONFIG_DIRECTORY> ルールフォルダのコンフィグディレクトリ (デフォルト: ./rules/config)
|
-c, --rules-config <RULE_CONFIG_DIRECTORY> ルールフォルダのコンフィグディレクトリ (デフォルト: ./rules/config)
|
||||||
--contributors コントリビュータの一覧表示
|
--contributors コントリビュータの一覧表示
|
||||||
-d, --directory <DIRECTORY> .evtxファイルを持つディレクトリのパス
|
-d, --directory <DIRECTORY> .evtxファイルを持つディレクトリのパス
|
||||||
-D, --enable-deprecated-rules Deprecatedルールを有効にする
|
-D, --enable-deprecated-rules Deprecatedルールを有効にする
|
||||||
--end-timeline <END_TIMELINE> 解析対象とするイベントログの終了時刻 (例: "2022-02-22 23:59:59 +09:00")
|
--end-timeline <END_TIMELINE> 解析対象とするイベントログの終了時刻 (例: "2022-02-22 23:59:59 +09:00")
|
||||||
--exclude-status <EXCLUDE_STATUS>... 読み込み対象外とするルール内でのステータス (ex: experimental) (ex: stable test)
|
--exclude-status <EXCLUDE_STATUS>... 読み込み対象外とするルール内でのステータス (ex: experimental) (ex: stable test)
|
||||||
-f, --filepath <FILE_PATH> 1つの.evtxファイルに対して解析を行う
|
-f, --filepath <FILE_PATH> 1つの.evtxファイルに対して解析を行う
|
||||||
-F, --full-data 全てのフィールド情報を出力する
|
-F, --full-data 全てのフィールド情報を出力する
|
||||||
-h, --help ヘルプ情報を表示する
|
-h, --help ヘルプ情報を表示する
|
||||||
-l, --live-analysis ローカル端末のC:\Windows\System32\winevt\Logsフォルダを解析する
|
-l, --live-analysis ローカル端末のC:\Windows\System32\winevt\Logsフォルダを解析する
|
||||||
-L, --logon-summary 成功と失敗したログオン情報の要約を出力する
|
-L, --logon-summary 成功と失敗したログオン情報の要約を出力する
|
||||||
--level-tuning <LEVEL_TUNING_FILE> ルールlevelのチューニング (デフォルト: ./rules/config/level_tuning.txt)
|
--level-tuning <LEVEL_TUNING_FILE> ルールlevelのチューニング (デフォルト: ./rules/config/level_tuning.txt)
|
||||||
-m, --min-level <LEVEL> 結果出力をするルールの最低レベル (デフォルト: informational)
|
-m, --min-level <LEVEL> 結果出力をするルールの最低レベル (デフォルト: informational)
|
||||||
-n, --enable-noisy-rules Noisyルールを有効にする
|
-n, --enable-noisy-rules Noisyルールを有効にする
|
||||||
--no_color カラー出力を無効にする
|
--no_color カラー出力を無効にする
|
||||||
-o, --output <CSV_TIMELINE> タイムラインをCSV形式で保存する (例: results.csv)
|
-o, --output <CSV_TIMELINE> タイムラインをCSV形式で保存する (例: results.csv)
|
||||||
-p, --pivot-keywords-list ピボットキーワードの一覧作成
|
-p, --pivot-keywords-list ピボットキーワードの一覧作成
|
||||||
-q, --quiet Quietモード: 起動バナーを表示しない
|
-q, --quiet Quietモード: 起動バナーを表示しない
|
||||||
-Q, --quiet-errors Quiet errorsモード: エラーログを保存しない
|
-Q, --quiet-errors Quiet errorsモード: エラーログを保存しない
|
||||||
-r, --rules <RULE_DIRECTORY/RULE_FILE> ルールファイルまたはルールファイルを持つディレクトリ (デフォルト: ./rules)
|
-r, --rules <RULE_DIRECTORY/RULE_FILE> ルールファイルまたはルールファイルを持つディレクトリ (デフォルト: ./rules)
|
||||||
-R, --hide-record-id イベントレコードIDを表示しない
|
-R, --hide-record-id イベントレコードIDを表示しない
|
||||||
-s, --statistics イベントIDの統計情報を表示する
|
-s, --statistics イベントIDの統計情報を表示する
|
||||||
--start-timeline <START_TIMELINE> 解析対象とするイベントログの開始時刻 (例: "2020-02-22 00:00:00 +09:00")
|
--start-timeline <START_TIMELINE> 解析対象とするイベントログの開始時刻 (例: "2020-02-22 00:00:00 +09:00")
|
||||||
-t, --thread-number <NUMBER> スレッド数 (デフォルト: パフォーマンスに最適な数値)
|
-t, --thread-number <NUMBER> スレッド数 (デフォルト: パフォーマンスに最適な数値)
|
||||||
-u, --update-rules rulesフォルダをhayabusa-rulesのgithubリポジトリの最新版に更新する
|
-u, --update-rules rulesフォルダをhayabusa-rulesのgithubリポジトリの最新版に更新する
|
||||||
-U, --UTC UTC形式で日付と時刻を出力する (デフォルト: 現地時間)
|
-U, --UTC UTC形式で日付と時刻を出力する (デフォルト: 現地時間)
|
||||||
-v, --verbose 詳細な情報を出力する
|
-v, --verbose 詳細な情報を出力する
|
||||||
-V, --visualize-timeline イベント頻度タイムラインを出力する
|
-V, --visualize-timeline イベント頻度タイムラインを出力する
|
||||||
--version バージョン情報を表示する
|
--version バージョン情報を表示する
|
||||||
```
|
```
|
||||||
|
|
||||||
## 使用例
|
## 使用例
|
||||||
|
|||||||
72
README.md
72
README.md
@@ -319,42 +319,42 @@ USAGE:
|
|||||||
hayabusa.exe -f file.evtx [OPTIONS] / hayabusa.exe -d evtx-directory [OPTIONS]
|
hayabusa.exe -f file.evtx [OPTIONS] / hayabusa.exe -d evtx-directory [OPTIONS]
|
||||||
|
|
||||||
OPTIONS:
|
OPTIONS:
|
||||||
--European-time Output timestamp in European time format (ex: 22-02-2022 22:00:00.123 +02:00)
|
--European-time Output timestamp in European time format (ex: 22-02-2022 22:00:00.123 +02:00)
|
||||||
--RFC-2822 Output timestamp in RFC 2822 format (ex: Fri, 22 Feb 2022 22:00:00 -0600)
|
--RFC-2822 Output timestamp in RFC 2822 format (ex: Fri, 22 Feb 2022 22:00:00 -0600)
|
||||||
--RFC-3339 Output timestamp in RFC 3339 format (ex: 2022-02-22 22:00:00.123456-06:00)
|
--RFC-3339 Output timestamp in RFC 3339 format (ex: 2022-02-22 22:00:00.123456-06:00)
|
||||||
--US-military-time Output timestamp in US military time format (ex: 02-22-2022 22:00:00.123 -06:00)
|
--US-military-time Output timestamp in US military time format (ex: 02-22-2022 22:00:00.123 -06:00)
|
||||||
--US-time Output timestamp in US time format (ex: 02-22-2022 10:00:00.123 PM -06:00)
|
--US-time Output timestamp in US time format (ex: 02-22-2022 10:00:00.123 PM -06:00)
|
||||||
--target-file-ext <EVTX_FILE_EXT>... Specify additional target file extensions (ex: evtx_data) (ex: evtx1 evtx2)
|
--target-file-ext <EVTX_FILE_EXT>... Specify additional target file extensions (ex: evtx_data) (ex: evtx1 evtx2)
|
||||||
--all-tags Output all tags when saving to a CSV file
|
--all-tags Output all tags when saving to a CSV file
|
||||||
-c, --config <RULE_CONFIG_DIRECTORY> Specify custom rule config folder (default: ./rules/config)
|
-c, --rules-config <RULE_CONFIG_DIRECTORY> Specify custom rule config folder (default: ./rules/config)
|
||||||
--contributors Print the list of contributors
|
--contributors Print the list of contributors
|
||||||
-d, --directory <DIRECTORY> Directory of multiple .evtx files
|
-d, --directory <DIRECTORY> Directory of multiple .evtx files
|
||||||
-D, --enable-deprecated-rules Enable rules marked as deprecated
|
-D, --enable-deprecated-rules Enable rules marked as deprecated
|
||||||
--end-timeline <END_TIMELINE> End time of the event logs to load (ex: "2022-02-22 23:59:59 +09:00")
|
--end-timeline <END_TIMELINE> End time of the event logs to load (ex: "2022-02-22 23:59:59 +09:00")
|
||||||
--exclude-status <EXCLUDE_STATUS>... Ignore rules according to status (ex: experimental) (ex: stable test)
|
--exclude-status <EXCLUDE_STATUS>... Ignore rules according to status (ex: experimental) (ex: stable test)
|
||||||
-f, --filepath <FILE_PATH> File path to one .evtx file
|
-f, --filepath <FILE_PATH> File path to one .evtx file
|
||||||
-F, --full-data Print all field information
|
-F, --full-data Print all field information
|
||||||
-h, --help Print help information
|
-h, --help Print help information
|
||||||
-l, --live-analysis Analyze the local C:\Windows\System32\winevt\Logs folder
|
-l, --live-analysis Analyze the local C:\Windows\System32\winevt\Logs folder
|
||||||
-L, --logon-summary Print a summary of successful and failed logons
|
-L, --logon-summary Print a summary of successful and failed logons
|
||||||
--level-tuning <LEVEL_TUNING_FILE> Tune alert levels (default: ./rules/config/level_tuning.txt)
|
--level-tuning <LEVEL_TUNING_FILE> Tune alert levels (default: ./rules/config/level_tuning.txt)
|
||||||
-m, --min-level <LEVEL> Minimum level for rules (default: informational)
|
-m, --min-level <LEVEL> Minimum level for rules (default: informational)
|
||||||
-n, --enable-noisy-rules Enable rules marked as noisy
|
-n, --enable-noisy-rules Enable rules marked as noisy
|
||||||
--no-color Disable color output
|
--no-color Disable color output
|
||||||
-o, --output <CSV_TIMELINE> Save the timeline in CSV format (ex: results.csv)
|
-o, --output <CSV_TIMELINE> Save the timeline in CSV format (ex: results.csv)
|
||||||
-p, --pivot-keywords-list Create a list of pivot keywords
|
-p, --pivot-keywords-list Create a list of pivot keywords
|
||||||
-q, --quiet Quiet mode: do not display the launch banner
|
-q, --quiet Quiet mode: do not display the launch banner
|
||||||
-Q, --quiet-errors Quiet errors mode: do not save error logs
|
-Q, --quiet-errors Quiet errors mode: do not save error logs
|
||||||
-r, --rules <RULE_DIRECTORY/RULE_FILE> Specify a rule directory or file (default: ./rules)
|
-r, --rules <RULE_DIRECTORY/RULE_FILE> Specify a rule directory or file (default: ./rules)
|
||||||
-R, --hide-record-ID Do not display EventRecordID numbers
|
-R, --hide-record-ID Do not display EventRecordID numbers
|
||||||
-s, --statistics Print statistics of event IDs
|
-s, --statistics Print statistics of event IDs
|
||||||
--start-timeline <START_TIMELINE> Start time of the event logs to load (ex: "2020-02-22 00:00:00 +09:00")
|
--start-timeline <START_TIMELINE> Start time of the event logs to load (ex: "2020-02-22 00:00:00 +09:00")
|
||||||
-t, --thread-number <NUMBER> Thread number (default: optimal number for performance)
|
-t, --thread-number <NUMBER> Thread number (default: optimal number for performance)
|
||||||
-u, --update-rules Update to the latest rules in the hayabusa-rules github repository
|
-u, --update-rules Update to the latest rules in the hayabusa-rules github repository
|
||||||
-U, --UTC Output time in UTC format (default: local time)
|
-U, --UTC Output time in UTC format (default: local time)
|
||||||
-v, --verbose Output verbose information
|
-v, --verbose Output verbose information
|
||||||
-V, --visualize-timeline Output event frequency timeline
|
-V, --visualize-timeline Output event frequency timeline
|
||||||
--version Print version information
|
--version Print version information
|
||||||
```
|
```
|
||||||
|
|
||||||
## Usage Examples
|
## Usage Examples
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use crate::detections::configs;
|
use crate::detections::configs;
|
||||||
use crate::detections::configs::TERM_SIZE;
|
use crate::detections::configs::{CURRENT_EXE_PATH, TERM_SIZE};
|
||||||
use crate::detections::print;
|
use crate::detections::print;
|
||||||
use crate::detections::print::{AlertMessage, IS_HIDE_RECORD_ID};
|
use crate::detections::print::{AlertMessage, IS_HIDE_RECORD_ID};
|
||||||
use crate::detections::utils;
|
use crate::detections::utils;
|
||||||
@@ -64,7 +64,12 @@ lazy_static! {
|
|||||||
|
|
||||||
/// level_color.txtファイルを読み込み対応する文字色のマッピングを返却する関数
|
/// level_color.txtファイルを読み込み対応する文字色のマッピングを返却する関数
|
||||||
pub fn set_output_color() -> HashMap<String, Color> {
|
pub fn set_output_color() -> HashMap<String, Color> {
|
||||||
let read_result = utils::read_csv("config/level_color.txt");
|
let read_result = utils::read_csv(
|
||||||
|
CURRENT_EXE_PATH
|
||||||
|
.join("config/level_color.txt")
|
||||||
|
.to_str()
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
let mut color_map: HashMap<String, Color> = HashMap::new();
|
let mut color_map: HashMap<String, Color> = HashMap::new();
|
||||||
if configs::CONFIG.read().unwrap().args.no_color {
|
if configs::CONFIG.read().unwrap().args.no_color {
|
||||||
return color_map;
|
return color_map;
|
||||||
@@ -701,8 +706,7 @@ mod tests {
|
|||||||
use crate::afterfact::emit_csv;
|
use crate::afterfact::emit_csv;
|
||||||
use crate::afterfact::format_time;
|
use crate::afterfact::format_time;
|
||||||
use crate::detections::print;
|
use crate::detections::print;
|
||||||
use crate::detections::print::DetectInfo;
|
use crate::detections::print::{DetectInfo, Message};
|
||||||
use crate::detections::print::CH_CONFIG;
|
|
||||||
use chrono::{Local, TimeZone, Utc};
|
use chrono::{Local, TimeZone, Utc};
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
@@ -718,6 +722,8 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn test_emit_csv_output() {
|
fn test_emit_csv_output() {
|
||||||
|
let mock_ch_filter =
|
||||||
|
Message::create_output_filter_config("config/channel_abbreviations.txt", true, false);
|
||||||
let test_filepath: &str = "test.evtx";
|
let test_filepath: &str = "test.evtx";
|
||||||
let test_rulepath: &str = "test-rule.yml";
|
let test_rulepath: &str = "test-rule.yml";
|
||||||
let test_title = "test_title";
|
let test_title = "test_title";
|
||||||
@@ -756,7 +762,7 @@ mod tests {
|
|||||||
level: test_level.to_string(),
|
level: test_level.to_string(),
|
||||||
computername: test_computername.to_string(),
|
computername: test_computername.to_string(),
|
||||||
eventid: test_eventid.to_string(),
|
eventid: test_eventid.to_string(),
|
||||||
channel: CH_CONFIG
|
channel: mock_ch_filter
|
||||||
.get("Security")
|
.get("Security")
|
||||||
.unwrap_or(&String::default())
|
.unwrap_or(&String::default())
|
||||||
.to_string(),
|
.to_string(),
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ use hashbrown::HashMap;
|
|||||||
use hashbrown::HashSet;
|
use hashbrown::HashSet;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
use std::env::current_exe;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::RwLock;
|
use std::sync::RwLock;
|
||||||
use terminal_size::{terminal_size, Height, Width};
|
use terminal_size::{terminal_size, Height, Width};
|
||||||
@@ -32,6 +33,8 @@ lazy_static! {
|
|||||||
pub static ref TERM_SIZE: Option<(Width, Height)> = terminal_size();
|
pub static ref TERM_SIZE: Option<(Width, Height)> = terminal_size();
|
||||||
pub static ref TARGET_EXTENSIONS: HashSet<String> =
|
pub static ref TARGET_EXTENSIONS: HashSet<String> =
|
||||||
get_target_extensions(CONFIG.read().unwrap().args.evtx_file_ext.as_ref());
|
get_target_extensions(CONFIG.read().unwrap().args.evtx_file_ext.as_ref());
|
||||||
|
pub static ref CURRENT_EXE_PATH: PathBuf =
|
||||||
|
current_exe().unwrap().parent().unwrap().to_path_buf();
|
||||||
pub static ref EXCLUDE_STATUS: HashSet<String> =
|
pub static ref EXCLUDE_STATUS: HashSet<String> =
|
||||||
convert_option_vecs_to_hs(CONFIG.read().unwrap().args.exclude_status.as_ref());
|
convert_option_vecs_to_hs(CONFIG.read().unwrap().args.exclude_status.as_ref());
|
||||||
}
|
}
|
||||||
@@ -84,7 +87,7 @@ pub struct Config {
|
|||||||
/// Specify custom rule config folder (default: ./rules/config)
|
/// Specify custom rule config folder (default: ./rules/config)
|
||||||
#[clap(
|
#[clap(
|
||||||
short = 'c',
|
short = 'c',
|
||||||
long,
|
long = "rules-config",
|
||||||
default_value = "./rules/config",
|
default_value = "./rules/config",
|
||||||
hide_default_value = true,
|
hide_default_value = true,
|
||||||
value_name = "RULE_CONFIG_DIRECTORY"
|
value_name = "RULE_CONFIG_DIRECTORY"
|
||||||
@@ -234,8 +237,18 @@ impl ConfigReader<'_> {
|
|||||||
app: build_cmd,
|
app: build_cmd,
|
||||||
args: parse,
|
args: parse,
|
||||||
headless_help: String::default(),
|
headless_help: String::default(),
|
||||||
event_timeline_config: load_eventcode_info("config/statistics_event_info.txt"),
|
event_timeline_config: load_eventcode_info(
|
||||||
target_eventids: load_target_ids("config/target_eventids.txt"),
|
CURRENT_EXE_PATH
|
||||||
|
.join("config/statistics_event_info.txt")
|
||||||
|
.to_str()
|
||||||
|
.unwrap(),
|
||||||
|
),
|
||||||
|
target_eventids: load_target_ids(
|
||||||
|
CURRENT_EXE_PATH
|
||||||
|
.join("config/target_eventids.txt")
|
||||||
|
.to_str()
|
||||||
|
.unwrap(),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
use crate::detections::configs;
|
use crate::detections::configs;
|
||||||
|
use crate::detections::configs::CURRENT_EXE_PATH;
|
||||||
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 crate::detections::utils::write_color_buffer;
|
use crate::detections::utils::write_color_buffer;
|
||||||
@@ -53,12 +54,18 @@ lazy_static! {
|
|||||||
pub static ref STATISTICS_FLAG: bool = configs::CONFIG.read().unwrap().args.statistics;
|
pub static ref STATISTICS_FLAG: bool = configs::CONFIG.read().unwrap().args.statistics;
|
||||||
pub static ref LOGONSUMMARY_FLAG: bool = configs::CONFIG.read().unwrap().args.logon_summary;
|
pub static ref LOGONSUMMARY_FLAG: bool = configs::CONFIG.read().unwrap().args.logon_summary;
|
||||||
pub static ref TAGS_CONFIG: HashMap<String, String> = Message::create_output_filter_config(
|
pub static ref TAGS_CONFIG: HashMap<String, String> = Message::create_output_filter_config(
|
||||||
"config/output_tag.txt",
|
CURRENT_EXE_PATH
|
||||||
|
.join("config/output_tag.txt")
|
||||||
|
.to_str()
|
||||||
|
.unwrap(),
|
||||||
true,
|
true,
|
||||||
configs::CONFIG.read().unwrap().args.all_tags
|
configs::CONFIG.read().unwrap().args.all_tags
|
||||||
);
|
);
|
||||||
pub static ref CH_CONFIG: HashMap<String, String> = Message::create_output_filter_config(
|
pub static ref CH_CONFIG: HashMap<String, String> = Message::create_output_filter_config(
|
||||||
"config/channel_abbreviations.txt",
|
CURRENT_EXE_PATH
|
||||||
|
.join("config/channel_abbreviations.txt")
|
||||||
|
.to_str()
|
||||||
|
.unwrap(),
|
||||||
false,
|
false,
|
||||||
configs::CONFIG.read().unwrap().args.all_tags
|
configs::CONFIG.read().unwrap().args.all_tags
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -523,8 +523,8 @@ mod tests {
|
|||||||
- ホスト アプリケーション
|
- ホスト アプリケーション
|
||||||
ImagePath:
|
ImagePath:
|
||||||
min_length: 1234321
|
min_length: 1234321
|
||||||
regexes: ./rules/config/regex/detectlist_suspicous_services.txt
|
regexes: ./../../../rules/config/regex/detectlist_suspicous_services.txt
|
||||||
allowlist: ./rules/config/regex/allowlist_legitimate_services.txt
|
allowlist: ./../../../rules/config/regex/allowlist_legitimate_services.txt
|
||||||
falsepositives:
|
falsepositives:
|
||||||
- unknown
|
- unknown
|
||||||
level: medium
|
level: medium
|
||||||
@@ -1111,7 +1111,7 @@ mod tests {
|
|||||||
selection:
|
selection:
|
||||||
EventID: 4103
|
EventID: 4103
|
||||||
Channel:
|
Channel:
|
||||||
- allowlist: ./rules/config/regex/allowlist_legitimate_services.txt
|
- allowlist: ./../../../rules/config/regex/allowlist_legitimate_services.txt
|
||||||
details: 'command=%CommandLine%'
|
details: 'command=%CommandLine%'
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
@@ -1145,7 +1145,7 @@ mod tests {
|
|||||||
selection:
|
selection:
|
||||||
EventID: 4103
|
EventID: 4103
|
||||||
Channel:
|
Channel:
|
||||||
- allowlist: ./rules/config/regex/allowlist_legitimate_services.txt
|
- allowlist: ./../../../rules/config/regex/allowlist_legitimate_services.txt
|
||||||
details: 'command=%CommandLine%'
|
details: 'command=%CommandLine%'
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
@@ -1179,7 +1179,7 @@ mod tests {
|
|||||||
selection:
|
selection:
|
||||||
EventID: 4103
|
EventID: 4103
|
||||||
Channel:
|
Channel:
|
||||||
- allowlist: ./rules/config/regex/allowlist_legitimate_services.txt
|
- allowlist: ./../../../rules/config/regex/allowlist_legitimate_services.txt
|
||||||
details: 'command=%CommandLine%'
|
details: 'command=%CommandLine%'
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ extern crate csv;
|
|||||||
extern crate regex;
|
extern crate regex;
|
||||||
|
|
||||||
use crate::detections::configs;
|
use crate::detections::configs;
|
||||||
|
use crate::detections::configs::CURRENT_EXE_PATH;
|
||||||
|
|
||||||
use termcolor::Color;
|
use termcolor::Color;
|
||||||
|
|
||||||
use tokio::runtime::Builder;
|
use tokio::runtime::Builder;
|
||||||
@@ -66,7 +68,16 @@ pub fn value_to_string(value: &Value) -> Option<String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_txt(filename: &str) -> Result<Vec<String>, String> {
|
pub fn read_txt(filename: &str) -> Result<Vec<String>, String> {
|
||||||
let f = File::open(filename);
|
let filepath = if filename.starts_with("./") {
|
||||||
|
CURRENT_EXE_PATH
|
||||||
|
.join(filename)
|
||||||
|
.to_str()
|
||||||
|
.unwrap()
|
||||||
|
.to_string()
|
||||||
|
} else {
|
||||||
|
filename.to_string()
|
||||||
|
};
|
||||||
|
let f = File::open(filepath);
|
||||||
if f.is_err() {
|
if f.is_err() {
|
||||||
let errmsg = format!("Cannot open file. [file:{}]", filename);
|
let errmsg = format!("Cannot open file. [file:{}]", filename);
|
||||||
return Result::Err(errmsg);
|
return Result::Err(errmsg);
|
||||||
@@ -437,7 +448,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_check_regex() {
|
fn test_check_regex() {
|
||||||
let regexes: Vec<Regex> =
|
let regexes: Vec<Regex> =
|
||||||
utils::read_txt("./rules/config/regex/detectlist_suspicous_services.txt")
|
utils::read_txt("./../../../rules/config/regex/detectlist_suspicous_services.txt")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|regex_str| Regex::new(®ex_str).unwrap())
|
.map(|regex_str| Regex::new(®ex_str).unwrap())
|
||||||
@@ -453,7 +464,7 @@ mod tests {
|
|||||||
fn test_check_allowlist() {
|
fn test_check_allowlist() {
|
||||||
let commandline = "\"C:\\Program Files\\Google\\Update\\GoogleUpdate.exe\"";
|
let commandline = "\"C:\\Program Files\\Google\\Update\\GoogleUpdate.exe\"";
|
||||||
let allowlist: Vec<Regex> =
|
let allowlist: Vec<Regex> =
|
||||||
utils::read_txt("./rules/config/regex/allowlist_legitimate_services.txt")
|
utils::read_txt("./../../../rules/config/regex/allowlist_legitimate_services.txt")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|allow_str| Regex::new(&allow_str).unwrap())
|
.map(|allow_str| Regex::new(&allow_str).unwrap())
|
||||||
|
|||||||
61
src/main.rs
61
src/main.rs
@@ -11,6 +11,7 @@ use chrono::{DateTime, Datelike, Local, TimeZone};
|
|||||||
use evtx::{EvtxParser, ParserSettings};
|
use evtx::{EvtxParser, ParserSettings};
|
||||||
use git2::Repository;
|
use git2::Repository;
|
||||||
use hashbrown::{HashMap, HashSet};
|
use hashbrown::{HashMap, HashSet};
|
||||||
|
use hayabusa::detections::configs::CURRENT_EXE_PATH;
|
||||||
use hayabusa::detections::configs::{load_pivot_keywords, TargetEventTime, TARGET_EXTENSIONS};
|
use hayabusa::detections::configs::{load_pivot_keywords, TargetEventTime, TARGET_EXTENSIONS};
|
||||||
use hayabusa::detections::detection::{self, EvtxRecordInfo};
|
use hayabusa::detections::detection::{self, EvtxRecordInfo};
|
||||||
use hayabusa::detections::pivot::PivotKeyword;
|
use hayabusa::detections::pivot::PivotKeyword;
|
||||||
@@ -82,7 +83,12 @@ impl App {
|
|||||||
|
|
||||||
fn exec(&mut self) {
|
fn exec(&mut self) {
|
||||||
if *PIVOT_KEYWORD_LIST_FLAG {
|
if *PIVOT_KEYWORD_LIST_FLAG {
|
||||||
load_pivot_keywords("config/pivot_keywords.txt");
|
load_pivot_keywords(
|
||||||
|
CURRENT_EXE_PATH
|
||||||
|
.join("config/pivot_keywords.txt")
|
||||||
|
.to_str()
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let analysis_start_time: DateTime<Local> = Local::now();
|
let analysis_start_time: DateTime<Local> = Local::now();
|
||||||
@@ -132,14 +138,30 @@ impl App {
|
|||||||
println!();
|
println!();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// 実行時のexeファイルのパスをベースに変更する必要があるためデフォルトの値であった場合はそのexeファイルと同一階層を探すようにする
|
||||||
if !Path::new("./config").exists() {
|
if !CURRENT_EXE_PATH.join("config").exists() {
|
||||||
AlertMessage::alert(
|
AlertMessage::alert(
|
||||||
"Hayabusa could not find the config directory.\nPlease run it from the Hayabusa root directory.\nExample: ./hayabusa-1.0.0-windows-x64.exe"
|
"Hayabusa could not find the config directory.\nPlease make sure that it is in the same directory as the hayabusa executable."
|
||||||
)
|
)
|
||||||
.ok();
|
.ok();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// ワーキングディレクトリ以外からの実行の際にrules-configオプションの指定がないとエラーが発生することを防ぐための処理
|
||||||
|
if configs::CONFIG
|
||||||
|
.read()
|
||||||
|
.unwrap()
|
||||||
|
.args
|
||||||
|
.config
|
||||||
|
.to_str()
|
||||||
|
.unwrap()
|
||||||
|
== "./rules/config"
|
||||||
|
{
|
||||||
|
configs::CONFIG.write().unwrap().args.config = CURRENT_EXE_PATH.join("rules/config");
|
||||||
|
}
|
||||||
|
// ワーキングディレクトリ以外からの実行の際にrules-configオプションの指定がないとエラーが発生することを防ぐための処理
|
||||||
|
if configs::CONFIG.read().unwrap().args.rules.to_str().unwrap() == "./rules" {
|
||||||
|
configs::CONFIG.write().unwrap().args.rules = CURRENT_EXE_PATH.join("rules");
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(csv_path) = &configs::CONFIG.read().unwrap().args.output {
|
if let Some(csv_path) = &configs::CONFIG.read().unwrap().args.output {
|
||||||
let pivot_key_unions = PIVOT_KEYWORD.read().unwrap();
|
let pivot_key_unions = PIVOT_KEYWORD.read().unwrap();
|
||||||
@@ -441,7 +463,7 @@ impl App {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn print_contributors(&self) {
|
fn print_contributors(&self) {
|
||||||
match fs::read_to_string("./contributors.txt") {
|
match fs::read_to_string(CURRENT_EXE_PATH.join("contributors.txt")) {
|
||||||
Ok(contents) => {
|
Ok(contents) => {
|
||||||
write_color_buffer(
|
write_color_buffer(
|
||||||
&BufferWriter::stdout(ColorChoice::Always),
|
&BufferWriter::stdout(ColorChoice::Always),
|
||||||
@@ -684,7 +706,7 @@ impl App {
|
|||||||
|
|
||||||
/// output logo
|
/// output logo
|
||||||
fn output_logo(&self) {
|
fn output_logo(&self) {
|
||||||
let fp = &"art/logo.txt".to_string();
|
let fp = CURRENT_EXE_PATH.join("art/logo.txt");
|
||||||
let content = fs::read_to_string(fp).unwrap_or_default();
|
let content = fs::read_to_string(fp).unwrap_or_default();
|
||||||
let output_color = if configs::CONFIG.read().unwrap().args.no_color {
|
let output_color = if configs::CONFIG.read().unwrap().args.no_color {
|
||||||
None
|
None
|
||||||
@@ -711,7 +733,8 @@ impl App {
|
|||||||
match eggs.get(exec_datestr) {
|
match eggs.get(exec_datestr) {
|
||||||
None => {}
|
None => {}
|
||||||
Some(path) => {
|
Some(path) => {
|
||||||
let content = fs::read_to_string(path).unwrap_or_default();
|
let egg_path = CURRENT_EXE_PATH.join(path);
|
||||||
|
let content = fs::read_to_string(egg_path).unwrap_or_default();
|
||||||
write_color_buffer(
|
write_color_buffer(
|
||||||
&BufferWriter::stdout(ColorChoice::Always),
|
&BufferWriter::stdout(ColorChoice::Always),
|
||||||
None,
|
None,
|
||||||
@@ -728,8 +751,9 @@ impl App {
|
|||||||
let mut result;
|
let mut result;
|
||||||
let mut prev_modified_time: SystemTime = SystemTime::UNIX_EPOCH;
|
let mut prev_modified_time: SystemTime = SystemTime::UNIX_EPOCH;
|
||||||
let mut prev_modified_rules: HashSet<String> = HashSet::default();
|
let mut prev_modified_rules: HashSet<String> = HashSet::default();
|
||||||
let hayabusa_repo = Repository::open(Path::new("."));
|
let hayabusa_repo = Repository::open(CURRENT_EXE_PATH.as_path());
|
||||||
let hayabusa_rule_repo = Repository::open(Path::new("rules"));
|
let rules_path = CURRENT_EXE_PATH.join("rules");
|
||||||
|
let hayabusa_rule_repo = Repository::open(&rules_path);
|
||||||
if hayabusa_repo.is_err() && hayabusa_rule_repo.is_err() {
|
if hayabusa_repo.is_err() && hayabusa_rule_repo.is_err() {
|
||||||
write_color_buffer(
|
write_color_buffer(
|
||||||
&BufferWriter::stdout(ColorChoice::Always),
|
&BufferWriter::stdout(ColorChoice::Always),
|
||||||
@@ -744,23 +768,23 @@ impl App {
|
|||||||
// case of exist hayabusa-rules repository
|
// case of exist hayabusa-rules repository
|
||||||
self._repo_main_reset_hard(hayabusa_rule_repo.as_ref().unwrap())?;
|
self._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.
|
// case of failed fetching origin/main, git clone is not executed so network error has occurred possibly.
|
||||||
prev_modified_rules = self.get_updated_rules("rules", &prev_modified_time);
|
prev_modified_rules =
|
||||||
prev_modified_time = fs::metadata("rules").unwrap().modified().unwrap();
|
self.get_updated_rules(rules_path.to_str().unwrap(), &prev_modified_time);
|
||||||
|
prev_modified_time = fs::metadata(&rules_path).unwrap().modified().unwrap();
|
||||||
result = self.pull_repository(&hayabusa_rule_repo.unwrap());
|
result = self.pull_repository(&hayabusa_rule_repo.unwrap());
|
||||||
} else {
|
} else {
|
||||||
// case of no exist hayabusa-rules repository in rules.
|
// case of no exist hayabusa-rules repository in rules.
|
||||||
// execute update because submodule information exists if hayabusa repository exists submodule information.
|
// execute update because submodule information exists if hayabusa repository exists submodule information.
|
||||||
|
|
||||||
prev_modified_time = fs::metadata("rules").unwrap().modified().unwrap();
|
prev_modified_time = fs::metadata(&rules_path).unwrap().modified().unwrap();
|
||||||
let rules_path = Path::new("rules");
|
if !&rules_path.exists() {
|
||||||
if !rules_path.exists() {
|
create_dir(&rules_path).ok();
|
||||||
create_dir(rules_path).ok();
|
|
||||||
}
|
}
|
||||||
let hayabusa_repo = hayabusa_repo.unwrap();
|
let hayabusa_repo = hayabusa_repo.unwrap();
|
||||||
let submodules = hayabusa_repo.submodules()?;
|
let submodules = hayabusa_repo.submodules()?;
|
||||||
let mut is_success_submodule_update = true;
|
let mut is_success_submodule_update = true;
|
||||||
// submodule rules erase path is hard coding to avoid unintentional remove folder.
|
// submodule rules erase path is hard coding to avoid unintentional remove folder.
|
||||||
fs::remove_dir_all(".git/.submodule/rules").ok();
|
fs::remove_dir_all(CURRENT_EXE_PATH.join(".git/.submodule/rules")).ok();
|
||||||
for mut submodule in submodules {
|
for mut submodule in submodules {
|
||||||
submodule.update(true, None)?;
|
submodule.update(true, None)?;
|
||||||
let submodule_repo = submodule.open()?;
|
let submodule_repo = submodule.open()?;
|
||||||
@@ -776,7 +800,8 @@ impl App {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if result.is_ok() {
|
if result.is_ok() {
|
||||||
let updated_modified_rules = self.get_updated_rules("rules", &prev_modified_time);
|
let updated_modified_rules =
|
||||||
|
self.get_updated_rules(rules_path.to_str().unwrap(), &prev_modified_time);
|
||||||
result =
|
result =
|
||||||
self.print_diff_modified_rule_dates(prev_modified_rules, updated_modified_rules);
|
self.print_diff_modified_rule_dates(prev_modified_rules, updated_modified_rules);
|
||||||
}
|
}
|
||||||
@@ -833,7 +858,7 @@ impl App {
|
|||||||
fn clone_rules(&self) -> Result<String, git2::Error> {
|
fn clone_rules(&self) -> Result<String, git2::Error> {
|
||||||
match Repository::clone(
|
match Repository::clone(
|
||||||
"https://github.com/Yamato-Security/hayabusa-rules.git",
|
"https://github.com/Yamato-Security/hayabusa-rules.git",
|
||||||
"rules",
|
CURRENT_EXE_PATH.join("rules"),
|
||||||
) {
|
) {
|
||||||
Ok(_repo) => {
|
Ok(_repo) => {
|
||||||
println!("Finished cloning the hayabusa-rules repository.");
|
println!("Finished cloning the hayabusa-rules repository.");
|
||||||
|
|||||||
Reference in New Issue
Block a user