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:
@@ -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 (リソース開発)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.'
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
3
test_files/config/channel_abbreviations.txt
Normal file
3
test_files/config/channel_abbreviations.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
Channel,Abbreviation
|
||||
Security,Sec
|
||||
xxx,yyy
|
||||
Reference in New Issue
Block a user