display computers with most alerts (#558)

* added top3 alert by level and computer #557

* cargo fmt

* updated changelog #557

* updated readme #557

* added output when one computer name in level. #557

* updated screenshot

* updated rules

* add SOF-ELK link

* readme update

* readme update

* cargo fmt

* change display num from 3 to 5 #557

* excluded count when computer name is "-" in event and fixed output #557

- removed warn output.

- changed output when count is 0.

* cargo fmt

* changed computer name summary to filter unique computer name and rule path pair #557

* cargo fmt

* readme update change order of output

* changelog update

* fixed crash bug when level is not valid #560 #557

Co-authored-by: Tanaka Zakku <71482215+YamatoSecurity@users.noreply.github.com>
This commit is contained in:
DustInDark
2022-06-03 12:01:14 +09:00
committed by GitHub
parent af5a85fc0c
commit 9e1fabb21e
7 changed files with 103 additions and 18 deletions

View File

@@ -8,6 +8,7 @@
- `--all-tags`オプションでルールにある全てのtagsを、outputで指定したcsvのMitreAttackの列に出力するようにした。 (#525) (@hitenkoku)
- `-R` / `--display-record-id` オプションの追加。evtx file内のレコードを特定するレコードID`<Event><System><EventRecordID>`が出力できるようになった。 (#548) (@hitenkoku)
- レベルごとの検知数が最も多い日を表示するようにした。 (#550) (@hitenkoku)
- レベルごとの検知数上位3つのコンピュータ名を表示するようにした。 (#557)(@hitenkoku)
**改善:**

View File

@@ -7,7 +7,8 @@
- Added Event Frequency Timeline feature to visualize the number of events. (Note: There needs to be more than 5 events.) (#533)(@hitenkoku)
- Display all the `tags` defined in a rule to the `MitreAttack` column when saving to CSV file with the `--all-tags` option. (#525) (@hitenkoku)
- Added the `-R / --display-record-id` option: Display the event record ID (`<Event><System><EventRecordID>`). (#548) (@hitenkoku)
- Display date with most detections by level. (#550) (@hitenkoku)
- Display dates with most detections. (#550) (@hitenkoku)
- Display the top 5 computers with the most unique detections. (#557) (@hitenkoku)
**Enhancements:**

View File

@@ -66,7 +66,8 @@ Hayabusaは、日本の[Yamato Security](https://yamatosecurity.connpass.com/)
- [プログレスバー](#プログレスバー)
- [標準出力へのカラー設定](#標準出力へのカラー設定)
- [イベント頻度タイムライン](#イベント頻度タイムライン)
- [各レベルの最多検知日の出力](#各レベルの最多検知日の出力)
- [最多検知日の出力](#最多検知日の出力)
- [最多検知端末名の出力](#最多検知端末名の出力)
- [Hayabusaルール](#hayabusaルール)
- [Hayabusa v.s. 変換されたSigmaルール](#hayabusa-vs-変換されたsigmaルール)
- [検知ルールのチューニング](#検知ルールのチューニング)
@@ -87,7 +88,7 @@ Hayabusaは、日本の[Yamato Security](https://yamatosecurity.connpass.com/)
### スレット(脅威)ハンティング
Hayabusaには現在、2200以上のSigmaルールと約125のHayabusa検知ルールがあり、定期的にルールが追加されています。 最終的な目標はインシデントレスポンスや定期的なスレットハンティングのために、HayabusaエージェントをすべてのWindows端末にインストールして、中央サーバーにアラートを返す仕組みを作ることです。
Hayabusaには現在、2300以上のSigmaルールと130以上のHayabusa検知ルールがあり、定期的にルールが追加されています。 最終的な目標はインシデントレスポンスや定期的なスレットハンティングのために、HayabusaエージェントをすべてのWindows端末にインストールして、中央サーバーにアラートを返す仕組みを作ることです。
### フォレンジックタイムラインの高速生成
@@ -155,7 +156,7 @@ CSVのタイムラインをElastic Stackにインポートする方法は[こち
* 不良ルールやノイズの多いルールを除外するルールチューニング設定が可能です。
* MITRE ATT&CKとのマッピング (CSVの出力ファイルのみ)。
* ルールレベルのチューニング。
* イベントログから不審なユーザやファイルを素早く特定するのに有用な、ピボットキーワードの一覧作成。
* イベントログから不審なユーザやファイルを素早く特定するためのピボットキーワードの一覧作成。
* 詳細な調査のために全フィールド情報の出力。
* 成功と失敗したユーザログオンの要約。
@@ -453,7 +454,7 @@ Checking target evtx FilePath: "./hayabusa-sample-evtx/YamatoSecurity/T1218.004_
## ピボットキーワードの作成
`-p`もしくは`--pivot-keywords-list`オプションを使うことで不審なユーザやホスト名、プロセスなどを一覧で出力することができ、イベントログから素早く特定することができます。
ピボットキーワードのカスタマイズは`config/pivot_keywords.txt`を変更することで行うことができます。以下はデフォルトの設定になります:
ピボットキーワードのカスタマイズは`config/pivot_keywords.txt`を変更することで行うことができます。以下はデフォルトの設定になります:
```
Users.SubjectUserName
@@ -577,10 +578,14 @@ Hayabusaの結果は`level`毎に文字色が変わります。
検知したイベントの数が5以上の時、頻度のタイムライン(スパークライン)を画面に出力します。
マーカーの数は最大10個です。
## 各レベルの最多検知日の出力
## 最多検知日の出力
各レベルで最も検知された日付を画面に出力します。
## 最多検知端末名の出力
各レベルで多く検知されたユニークなイベントが多い端末名上位5つを画面に出力します。
# Hayabusaルール
Hayabusa検知ルールはSigmaのようなYML形式で記述されています。`rules`ディレクトリに入っていますが、将来的には[https://github.com/Yamato-Security/hayabusa-rules](https://github.com/Yamato-Security/hayabusa-rules)のレポジトリで管理する予定なので、ルールのissueとpull requestはhayabusaのレポジトリではなく、ルールレポジトリへお願いします。
@@ -676,6 +681,7 @@ id,new_level
* [LogonTracer](https://github.com/JPCERTCC/LogonTracer) - [JPCERTCC](https://twitter.com/jpcert) による、横方向の動きを検知するためにログオンを視覚化するグラフィカルなインターフェース。
* [RustyBlue](https://github.com/Yamato-Security/RustyBlue) - 大和セキュリティによるDeepBlueCLIのRust版。
* [Sigma](https://github.com/SigmaHQ/Sigma) - コミュニティベースの汎用SIEMルール。
* [SOF-ELK](https://github.com/philhagen/sof-elk) - [Phil Hagen](https://twitter.com/philhagen) によるDFIR解析用のElastic Stack VM。
* [so-import-evtx](https://docs.securityonion.net/en/2.3/so-import-evtx.html) - evtxファイルをSecurityOnionにインポートするツール。
* [SysmonTools](https://github.com/nshalabi/SysmonTools) - Sysmonの設定とオフライン可視化ツール。
* [Timeline Explorer](https://ericzimmerman.github.io/#!index.md) - [Eric Zimmerman](https://twitter.com/ericrzimmerman) による最高のCSVタイムラインアナライザ。

View File

@@ -65,7 +65,8 @@ Hayabusa is a **Windows event log fast forensics timeline generator** and **thre
- [Progress Bar](#progress-bar)
- [Color Output](#color-output)
- [Event Fequency Timeline](#event-fequency-timeline)
- [Dates with most detections categorized by level](#dates-with-most-detections-categorized-by-level)
- [Dates with most total detections](#dates-with-most-total-detections)
- [Top 5 computers with most unique detections](#top-5-computers-with-most-unique-detections)
- [Hayabusa Rules](#hayabusa-rules)
- [Hayabusa v.s. Converted Sigma Rules](#hayabusa-vs-converted-sigma-rules)
- [Detection Rule Tuning](#detection-rule-tuning)
@@ -575,9 +576,13 @@ If you want to disable color output, you can use `--no-color` option.
The Event Frequency Timeline feature displays a sparkline frequency timeline of detected events.
Note: There needs to be more than 5 events.
## Dates with most detections categorized by level
## Dates with most total detections
A summary of the dates with the most detections categorized by level (`critical`, `high`, etc...).
A summary of the dates with the most total detections categorized by level (`critical`, `high`, etc...).
## Top 5 computers with most unique detections
The top 5 computers with the most unique detections categorized by level (`critical`, `high`, etc...).
# Hayabusa Rules
@@ -675,6 +680,7 @@ There is no "one tool to rule them all" and we have found that each has its own
* [LogonTracer](https://github.com/JPCERTCC/LogonTracer) - A graphical interface to visualize logons to detect lateral movement by [JPCERTCC](https://twitter.com/jpcert_en).
* [RustyBlue](https://github.com/Yamato-Security/RustyBlue) - Rust port of DeepBlueCLI by Yamato Security.
* [Sigma](https://github.com/SigmaHQ/sigma) - Community based generic SIEM rules.
* [SOF-ELK](https://github.com/philhagen/sof-elk) - A pre-packaged VM with Elastic Stack to import data for DFIR analysis by [Phil Hagen](https://twitter.com/philhagen)
* [so-import-evtx](https://docs.securityonion.net/en/2.3/so-import-evtx.html) - Import evtx files into Security Onion.
* [SysmonTools](https://github.com/nshalabi/SysmonTools) - Configuration and off-line log visualization tool for Sysmon.
* [Timeline Explorer](https://ericzimmerman.github.io/#!index.md) - The best CSV timeline analyzer by [Eric Zimmerman](https://twitter.com/ericrzimmerman).

2
rules

Submodule rules updated: 3312639216...902c59e3c5

Binary file not shown.

Before

Width:  |  Height:  |  Size: 158 KiB

After

Width:  |  Height:  |  Size: 267 KiB

View File

@@ -202,9 +202,12 @@ fn emit_csv<W: std::io::Write>(
// level is devided by "Critical","High","Medium","Low","Informational","Undefined".
let mut total_detect_counts_by_level: Vec<u128> = vec![0; 6];
let mut unique_detect_counts_by_level: Vec<u128> = vec![0; 6];
let mut detected_rule_files: Vec<String> = Vec::new();
let mut detected_rule_files: HashSet<String> = HashSet::new();
let mut detected_computer_and_rule_names: HashSet<String> = HashSet::new();
let mut detect_counts_by_date_and_level: HashMap<String, HashMap<String, u128>> =
HashMap::new();
let mut detect_counts_by_computer_and_level: HashMap<String, HashMap<String, i128>> =
HashMap::new();
let levels = Vec::from([
"critical",
@@ -217,6 +220,7 @@ fn emit_csv<W: std::io::Write>(
// レベル別、日ごとの集計用変数の初期化
for level_init in levels {
detect_counts_by_date_and_level.insert(level_init.to_string(), HashMap::new());
detect_counts_by_computer_and_level.insert(level_init.to_string(), HashMap::new());
}
println!();
@@ -300,9 +304,28 @@ fn emit_csv<W: std::io::Write>(
.entry(time_str_date.to_string())
.or_insert(0) += 1;
if !detected_rule_files.contains(&detect_info.rulepath) {
detected_rule_files.push(detect_info.rulepath.clone());
detected_rule_files.insert(detect_info.rulepath.clone());
unique_detect_counts_by_level[level_suffix] += 1;
}
let computer_rule_check_key =
format!("{}|{}", &detect_info.computername, &detect_info.rulepath);
if !detected_computer_and_rule_names.contains(&computer_rule_check_key) {
detected_computer_and_rule_names.insert(computer_rule_check_key);
let mut detect_counts_by_computer = detect_counts_by_computer_and_level
.get(&detect_info.level.to_lowercase())
.unwrap_or_else(|| {
detect_counts_by_computer_and_level
.get("undefined")
.unwrap()
})
.clone();
*detect_counts_by_computer
.entry(Clone::clone(&detect_info.computername))
.or_insert(0) += 1;
detect_counts_by_computer_and_level
.insert(detect_info.level.to_lowercase(), detect_counts_by_computer);
}
total_detect_counts_by_level[level_suffix] += 1;
detect_counts_by_date_and_level
.insert(detect_info.level.to_lowercase(), detect_counts_by_date);
@@ -336,9 +359,6 @@ fn emit_csv<W: std::io::Write>(
);
println!();
_print_detection_summary_by_date(detect_counts_by_date_and_level, &color_map);
println!();
_print_unique_results(
total_detect_counts_by_level,
"Total".to_string(),
@@ -353,6 +373,13 @@ fn emit_csv<W: std::io::Write>(
"detections".to_string(),
&color_map,
);
println!();
_print_detection_summary_by_date(detect_counts_by_date_and_level, &color_map);
println!();
_print_detection_summary_by_computer(detect_counts_by_computer_and_level, &color_map);
Ok(())
}
@@ -457,18 +484,18 @@ fn _print_detection_summary_by_date(
for (date, cnt) in detections_by_day {
if cnt > &tmp_cnt {
date_str = date.clone();
max_detect_str = format!("{} (Count: {})", date, cnt);
max_detect_str = format!("{} ({})", date, cnt);
tmp_cnt = *cnt;
}
}
wtr.set_color(ColorSpec::new().set_fg(_get_output_color(color_map, level)))
.ok();
if date_str == String::default() {
max_detect_str = "-".to_string();
max_detect_str = "n/a".to_string();
}
writeln!(
wtr,
"Date with most {} detections: {}",
"Date with most total {} detections: {}",
level, &max_detect_str
)
.ok();
@@ -476,6 +503,50 @@ fn _print_detection_summary_by_date(
buf_wtr.print(&wtr).ok();
}
/// 各レベル毎で最も高い検知数を出した日付を出力する
fn _print_detection_summary_by_computer(
detect_counts_by_computer: HashMap<String, HashMap<String, i128>>,
color_map: &HashMap<String, Color>,
) {
let buf_wtr = BufferWriter::stdout(ColorChoice::Always);
let mut wtr = buf_wtr.buffer();
wtr.set_color(ColorSpec::new().set_fg(None)).ok();
let output_levels = Vec::from(["critical", "high", "medium", "low", "informational"]);
for level in output_levels {
// output_levelsはlevelsからundefinedを除外した配列であり、各要素は必ず初期化されているのでSomeであることが保証されているのでunwrapをそのまま実施
let detections_by_computer = detect_counts_by_computer.get(level).unwrap();
let mut result_vec: Vec<String> = Vec::new();
//computer nameで-となっているものは除外して集計する
let mut sorted_detections: Vec<(&String, &i128)> = detections_by_computer
.iter()
.filter(|a| a.0 != "-")
.collect();
sorted_detections.sort_by(|a, b| (-a.1).cmp(&(-b.1)));
for x in sorted_detections.iter().take(5) {
result_vec.push(format!("{} ({})", x.0, x.1));
}
let result_str = if result_vec.is_empty() {
"n/a".to_string()
} else {
result_vec.join(", ")
};
wtr.set_color(ColorSpec::new().set_fg(_get_output_color(color_map, level)))
.ok();
writeln!(
wtr,
"Top 5 computers with most unique {} detections: {}",
level, &result_str
)
.ok();
}
buf_wtr.print(&wtr).ok();
}
fn format_time(time: &DateTime<Utc>) -> String {
if configs::CONFIG.read().unwrap().args.is_present("utc") {
format_rfc(time)