From 684c8a9688f633409af3859e9f5d1d18e8222887 Mon Sep 17 00:00:00 2001 From: DustInDark Date: Mon, 23 May 2022 00:19:04 +0900 Subject: [PATCH] 525 show technique tags (#534) * added --all-tags optiojn #525 - exclude load output_tag.txt when --all-tags option is true * fixed output to MitreAttack column #525 * added test * added period * updated usage in readme * added test file * added all-tags option in readme * readme update * fixed all-tags option description in help option Co-authored-by: Tanaka Zakku <71482215+YamatoSecurity@users.noreply.github.com> --- README-Japanese.md | 6 +- README.md | 8 ++- src/detections/configs.rs | 3 +- src/detections/detection.rs | 27 ++++++--- src/detections/print.rs | 64 ++++++++++++++++++--- test_files/config/channel_abbreviations.txt | 3 + 6 files changed, 90 insertions(+), 21 deletions(-) create mode 100644 test_files/config/channel_abbreviations.txt diff --git a/README-Japanese.md b/README-Japanese.md index 4e402633..26e3a2ce 100644 --- a/README-Japanese.md +++ b/README-Japanese.md @@ -319,6 +319,7 @@ USAGE: -r --rules=[RULEFILE/RULEDIRECTORY] 'ルールファイルまたはルールファイルを持つディレクトリ。(デフォルト: ./rules)' -C --config=[RULECONFIGDIRECTORY] 'ルールフォルダのコンフィグディレクトリ(デフォルト: ./rules/config)' -o --output=[CSV_TIMELINE] 'タイムラインをCSV形式で保存する。(例: results.csv)' + --all-tags '出力したCSVファイルにルール内のタグ情報を全て出力する。' -v --verbose '詳細な情報を出力する。' -D --enable-deprecated-rules 'Deprecatedルールを有効にする。' -n --enable-noisy-rules 'Noisyルールを有効にする。' @@ -333,10 +334,10 @@ USAGE: --no-color 'カラー出力を無効にする。' -t --thread-number=[NUMBER] 'スレッド数。(デフォルト: パフォーマンスに最適な数値)' -s --statistics 'イベント ID の統計情報を表示する。' - -L --logon-summary '成功と失敗したログオン情報の要約を出力' + -L --logon-summary '成功と失敗したログオン情報の要約を出力する。' -q --quiet 'Quietモード。起動バナーを表示しない。' -Q --quiet-errors 'Quiet errorsモード。エラーログを保存しない。' - --level-tuning 'ルールlevelのチューニング [default: ./rules/config/level_tuning.txt]' + --level-tuning=[LEVEL_TUNING_FILE] 'ルールlevelのチューニング (default: ./rules/config/level_tuning.txt)' -p --pivot-keywords-list 'ピボットキーワードの一覧作成。' --contributors 'コントリビュータの一覧表示。' ``` @@ -498,6 +499,7 @@ CSVファイルとして保存する場合、以下の列が追加されます: 簡潔に出力するためにMITRE ATT&CKの戦術を以下のように省略しています。 `config/output_tag.txt`の設定ファイルで自由に編集できます。 +検知したデータの戦術を全て出力したい場合は、`--all-tags`オプションをつけてください。 * `Recon` : Reconnaissance (偵察) * `ResDev` : Resource Development (リソース開発) diff --git a/README.md b/README.md index 7034a811..73b9e095 100644 --- a/README.md +++ b/README.md @@ -315,6 +315,7 @@ USAGE: -r --rules=[RULEDIRECTORY/RULEFILE] 'Rule file or directory (default: ./rules)' -C --config=[RULECONFIGDIRECTORY] 'Rule config folder. (Default: ./rules/config)' -o --output=[CSV_TIMELINE] 'Save the timeline in CSV format. (Example: results.csv)' + --all-tags 'Output all tags when saving to a CSV file.' -v --verbose 'Output verbose information.' -D --enable-deprecated-rules 'Enable rules marked as deprecated.' -n --enable-noisy-rules 'Enable rules marked as noisy.' @@ -326,13 +327,13 @@ USAGE: --rfc-2822 'Output date and time in RFC 2822 format. (Example: Mon, 07 Aug 2006 12:34:56 -0600)' --rfc-3339 'Output date and time in RFC 3339 format. (Example: 2006-08-07T12:34:56.485214 -06:00)' -U --utc 'Output time in UTC format. (Default: local time)' - --no-color 'Disable color output' + --no-color 'Disable color output.' -t --thread-number=[NUMBER] 'Thread number. (Default: Optimal number for performance.)' -s --statistics 'Prints statistics of event IDs.' -L --logon-summary 'Successful and failed logons summary.' -q --quiet 'Quiet mode. Do not display the launch banner.' -Q --quiet-errors 'Quiet errors mode. Do not save error logs.' - --level-tuning 'Adjust rule level. [default: ./rules/config/level_tuning.txt]' + --level-tuning=[LEVEL_TUNING_FILE] 'Adjust rule level.(default: ./rules/config/level_tuning.txt) ' -p --pivot-keywords-list 'Create a list of pivot keywords.' --contributors 'Prints the list of contributors.' ``` @@ -493,8 +494,9 @@ If you add the `-F` or `--full-data` option, a new column with all field informa ## MITRE ATT&CK Tactics Abbreviations -In order to save space, we use the following abbreviations when displaying MITRE ATT&CK tactics. +In order to save space, we use the following abbreviations when displaying MITRE ATT&CK tactic tags. You can freely edit these abbreviations in the `config/output_tag.txt` configuration file. +If you want to output all the tags defined in a rule, please specify the `--all-tags` option. * `Recon` : Reconnaissance * `ResDev` : Resource Development diff --git a/src/detections/configs.rs b/src/detections/configs.rs index e208024a..23c99514 100644 --- a/src/detections/configs.rs +++ b/src/detections/configs.rs @@ -76,6 +76,7 @@ fn build_app<'a>() -> ArgMatches<'a> { -r --rules=[RULEDIRECTORY/RULEFILE] 'Rule file or directory (default: ./rules)' -C --config=[RULECONFIGDIRECTORY] 'Rule config folder. (Default: ./rules/config)' -o --output=[CSV_TIMELINE] 'Save the timeline in CSV format. (Example: results.csv)' + --all-tags 'Output all tags when saving to a CSV file.' -v --verbose 'Output verbose information.' -D --enable-deprecated-rules 'Enable rules marked as deprecated.' -n --enable-noisy-rules 'Enable rules marked as noisy.' @@ -87,7 +88,7 @@ fn build_app<'a>() -> ArgMatches<'a> { --rfc-2822 'Output date and time in RFC 2822 format. (Example: Mon, 07 Aug 2006 12:34:56 -0600)' --rfc-3339 'Output date and time in RFC 3339 format. (Example: 2006-08-07T12:34:56.485214 -06:00)' -U --utc 'Output time in UTC format. (Default: local time)' - --no-color 'Disable color output' + --no-color 'Disable color output.' -t --thread-number=[NUMBER] 'Thread number. (Default: Optimal number for performance.)' -s --statistics 'Prints statistics of event IDs.' -L --logon-summary 'Successful and failed logons summary.' diff --git a/src/detections/detection.rs b/src/detections/detection.rs index f020cb91..7e866adc 100644 --- a/src/detections/detection.rs +++ b/src/detections/detection.rs @@ -206,13 +206,26 @@ impl Detection { /// 条件に合致したレコードを表示するための関数 fn insert_message(rule: &RuleNode, record_info: &EvtxRecordInfo) { - let tag_info: Vec = rule.yaml["tags"] - .as_vec() - .unwrap_or(&Vec::default()) - .iter() - .filter_map(|info| TAGS_CONFIG.get(info.as_str().unwrap_or(&String::default()))) - .map(|str| str.to_owned()) - .collect(); + let tag_info: Vec = match TAGS_CONFIG.is_empty() { + false => rule.yaml["tags"] + .as_vec() + .unwrap_or(&Vec::default()) + .iter() + .filter_map(|info| TAGS_CONFIG.get(info.as_str().unwrap_or(&String::default()))) + .map(|str| str.to_owned()) + .collect(), + true => rule.yaml["tags"] + .as_vec() + .unwrap_or(&Vec::default()) + .iter() + .map( + |info| match TAGS_CONFIG.get(info.as_str().unwrap_or(&String::default())) { + Some(s) => s.to_owned(), + _ => info.as_str().unwrap_or("").replace("attack.", ""), + }, + ) + .collect(), + }; let recinfo = record_info .record_information diff --git a/src/detections/print.rs b/src/detections/print.rs index 8c8bf18d..18027808 100644 --- a/src/detections/print.rs +++ b/src/detections/print.rs @@ -60,10 +60,16 @@ lazy_static! { .unwrap() .args .is_present("logon-summary"); - pub static ref TAGS_CONFIG: HashMap = - Message::create_output_filter_config("config/output_tag.txt"); - pub static ref CH_CONFIG: HashMap = - Message::create_output_filter_config("config/channel_abbreviations.txt"); + pub static ref TAGS_CONFIG: HashMap = Message::create_output_filter_config( + "config/output_tag.txt", + true, + configs::CONFIG.read().unwrap().args.is_present("all-tags") + ); + pub static ref CH_CONFIG: HashMap = Message::create_output_filter_config( + "config/channel_abbreviations.txt", + false, + configs::CONFIG.read().unwrap().args.is_present("all-tags") + ); pub static ref PIVOT_KEYWORD_LIST_FLAG: bool = configs::CONFIG .read() .unwrap() @@ -85,7 +91,15 @@ impl Message { /// ファイルパスで記載されたtagでのフル名、表示の際に置き換えられる文字列のHashMapを作成する関数。tagではこのHashMapのキーに対応しない出力は出力しないものとする /// ex. attack.impact,Impact - pub fn create_output_filter_config(path: &str) -> HashMap { + pub fn create_output_filter_config( + path: &str, + read_tags: bool, + pass_flag: bool, + ) -> HashMap { + let mut ret: HashMap = HashMap::new(); + if read_tags && pass_flag { + return ret; + } let read_result = utils::read_csv(path); if read_result.is_err() { AlertMessage::alert( @@ -95,7 +109,6 @@ impl Message { .ok(); return HashMap::default(); } - let mut ret: HashMap = HashMap::new(); read_result.unwrap().into_iter().for_each(|line| { if line.len() != 2 { return; @@ -516,13 +529,48 @@ mod tests { #[test] /// test of loading output filter config by output_tag.txt fn test_load_output_tag() { - let actual = Message::create_output_filter_config("test_files/config/output_tag.txt"); + let actual = + Message::create_output_filter_config("test_files/config/output_tag.txt", true, false); let expected: HashMap = HashMap::from([ ("attack.impact".to_string(), "Impact".to_string()), ("xxx".to_string(), "yyy".to_string()), ]); + _check_hashmap_element(&expected, actual); + } - assert_eq!(actual.len(), expected.len()); + #[test] + /// test of loading pass by output_tag.txt + fn test_no_load_output_tag() { + let actual = + Message::create_output_filter_config("test_files/config/output_tag.txt", true, true); + let expected: HashMap = HashMap::new(); + _check_hashmap_element(&expected, actual); + } + + #[test] + /// loading test to channel_abbrevations.txt + fn test_load_abbrevations() { + let actual = Message::create_output_filter_config( + "test_files/config/channel_abbreviations.txt", + false, + true, + ); + let actual2 = Message::create_output_filter_config( + "test_files/config/channel_abbreviations.txt", + false, + false, + ); + let expected: HashMap = HashMap::from([ + ("Security".to_string(), "Sec".to_string()), + ("xxx".to_string(), "yyy".to_string()), + ]); + _check_hashmap_element(&expected, actual); + _check_hashmap_element(&expected, actual2); + } + + /// check two HashMap element length and value + fn _check_hashmap_element(expected: &HashMap, actual: HashMap) { + assert_eq!(expected.len(), actual.len()); for (k, v) in expected.iter() { assert!(actual.get(k).unwrap_or(&String::default()) == v); } diff --git a/test_files/config/channel_abbreviations.txt b/test_files/config/channel_abbreviations.txt new file mode 100644 index 00000000..3d969d43 --- /dev/null +++ b/test_files/config/channel_abbreviations.txt @@ -0,0 +1,3 @@ +Channel,Abbreviation +Security,Sec +xxx,yyy