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>
This commit is contained in:
DustInDark
2022-05-23 00:19:04 +09:00
committed by GitHub
parent 69564103de
commit 684c8a9688
6 changed files with 90 additions and 21 deletions

View File

@@ -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_TUNING_FILE> 'ルール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 (リソース開発)

View File

@@ -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 <LEVEL_TUNING_FILE> '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

View File

@@ -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.'

View File

@@ -206,13 +206,26 @@ impl Detection {
/// 条件に合致したレコードを表示するための関数
fn insert_message(rule: &RuleNode, record_info: &EvtxRecordInfo) {
let tag_info: Vec<String> = 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<String> = 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

View File

@@ -60,10 +60,16 @@ lazy_static! {
.unwrap()
.args
.is_present("logon-summary");
pub static ref TAGS_CONFIG: HashMap<String, String> =
Message::create_output_filter_config("config/output_tag.txt");
pub static ref CH_CONFIG: HashMap<String, String> =
Message::create_output_filter_config("config/channel_abbreviations.txt");
pub static ref TAGS_CONFIG: HashMap<String, String> = 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<String, String> = 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<String, String> {
pub fn create_output_filter_config(
path: &str,
read_tags: bool,
pass_flag: bool,
) -> HashMap<String, String> {
let mut ret: HashMap<String, String> = 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<String, String> = 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<String, String> = 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<String, String> = 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<String, String> = 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<String, String>, actual: HashMap<String, String>) {
assert_eq!(expected.len(), actual.len());
for (k, v) in expected.iter() {
assert!(actual.get(k).unwrap_or(&String::default()) == v);
}

View File

@@ -0,0 +1,3 @@
Channel,Abbreviation
Security,Sec
xxx,yyy