Merge pull request #515 from Yamato-Security/develop

v1.2.1 release
This commit is contained in:
DustInDark
2022-04-21 21:55:30 +09:00
committed by GitHub
17 changed files with 274 additions and 86 deletions

View File

@@ -1,7 +1,18 @@
# 変更点
## v1.2.0 [2022/04/15] Black Hat Asia Arsenal 2022 Preview Release
## v1.2.1 [2022/04/20] Black Hat Asia Arsenal 2022 Preview Release
**新機能:**
- Added a `Channel` column to the output based on the `./config/channel_abbreviations` config file. (@hitenkoku)
- Rule and rule config files are now forcefully updated. (@hitenkoku)
**バグ修正:**
- Rules marked as noisy or excluded would not have their `level` changed with `--level-tuning` but now all rules will be checked. (@hitenkoku)
## v1.2.0 [2022/04/15] Black Hat Asia Arsenal 2022 Preview Release
**新機能:**
- `-C / --config` オプションの追加。検知ルールのコンフィグを指定することが可能。(Windowsでのライブ調査に便利) (@hitenkoku)
- `|equalsfield` と記載することでルール内で二つのフィールドの値が一致するかを記載に対応。 (@hach1yon)
- `-p / --pivot-keywords-list` オプションの追加。攻撃されたマシン名や疑わしいユーザ名などの情報をピボットキーワードリストとして出力する。 (@kazuminn)
@@ -9,6 +20,7 @@
- `--level-tuning` オプションの追加。ルールの検知ファイルを設定したコンフィグファイルに従って検知レベルをチューニングすることが可能(@itib@hitenkoku)
**改善:**
- 検知ルールとドキュメントの更新。 (@YamatoSecurity)
- MacとLinuxのバイナリに必要なOpenSSLライブラリを静的コンパイルした。 (@YamatoSecurity)
- タブ等の文字が含まれたフィールドに対しての検知性能の改善。 (@hach1yon@hitenkoku)
@@ -18,19 +30,24 @@
- イベントIDとタイトルが記載されたコンフィグファイルの名前を `timeline_event_info.txt` から `statistics_event_info.txt`に変更。 (@YamatoSecurity@garigariganzy)
- 64bit Windowsで32bit版のバイナリを実行しないように修正(@hitenkoku)
- MITRE ATT&CKのデータの出力を`output_tag.txt`で修正できるように修正(@hitenkoku)
- 出力にChannel名のカラムを追加(@hitenkoku)
**バグ修正:**
- `.git` フォルダ内にある `.yml` ファイルがパースエラーを引き起こしていた問題の修正。 (@hitenkoku)
- テスト用のルールファイルの読み込みエラーで不必要な改行が発生していた問題の修正。 (@hitenkoku)
- Windows Terminalのバグで標準出力が途中で止まる場合がありましたが、Hayabusa側で解決しました。 (@hitenkoku)
## v1.1.0 [2022/03/03]
**新機能:**
- `-r / --rules`オプションで一つのルール指定が可能。(ルールをテストする際に便利!) (@kazuminn)
- ルール更新オプション (`-u / --update-rules`): [hayabusa-rules](https://github.com/Yamato-Security/hayabusa-rules)レポジトリにある最新のルールに更新できる。 (@hitenkoku)
- ライブ調査オプション (`-l / --live-analysis`): Windowsイベントログディレクトリを指定しないで、楽にWindows端末でライブ調査ができる。(@hitenkoku)
**改善:**
- ドキュメンテーションの更新。 (@kazuminn@itiB@hitenkoku@YamatoSecurity)
- ルールの更新。(Hayabusaルール: 20個以上、Sigmaルール: 200個以上) (@YamatoSecurity)
- Windowsバイナリは静的でコンパイルしているので、Visual C++ 再頒布可能パッケージをインストールする必要はない。(@hitenkoku)
@@ -42,12 +59,15 @@
- Cargo crateの更新。 (@YamatoSecurity)
**バグ修正:**
- `cargo update`がより安定するために、clapのバージョンを固定した。(@hitenkoku)
- フィールドのタブや改行がある場合に、ルールが検知しなかったので、修正した。(@hitenkoku)
## v1.0.0-Release 2 [2022/01/27]
- アンチウィルスに誤検知されたExcelの結果ファイルの削除。(@YamatoSecurity)
- Rustのevtxライブラリを0.7.2に更新。 (@YamatoSecurity)
## v1.0.0 [2021/12/25]
- 最初のリリース

View File

@@ -1,5 +1,14 @@
# Changes
## v1.2.1 [2022/04/20] Black Hat Asia Arsenal 2022 Preview Release
**New Features:**
- Added a `Channel` column to the output based on the `./config/channel_abbreviations.txt` config file. (@hitenkoku)
- Rule and rule config files are now forcefully updated. (@hitenkoku)
**Bug Fixes:**
- Rules marked as noisy or excluded would not have their `level` changed with `--level-tuning` but now all rules will be checked. (@hitenkoku)
## v1.2.0 [2022/04/15] Black Hat Asia Arsenal 2022 Preview Release
**New Features:**
@@ -10,6 +19,7 @@
- `--level-tuning` option: You can tune the risk `level` in hayabusa and sigma rules to your environment. (@itib and @hitenkoku)
**Enhancements:**
- Updated detection rules and documentation. (@YamatoSecurity)
- Mac and Linux binaries now statically compile the OpenSSL libraries. (@YamatoSecurity)
- Performance and accuracy improvement for fields with tabs, etc... in them. (@hach1yon and @hitenkoku)
@@ -19,19 +29,24 @@
- Updated the event ID and title config file (`timeline_event_info.txt`) and changed the name to `statistics_event_info.txt`. (@YamatoSecurity and @garigariganzy)
- 32-bit Hayabusa Windows binaries are now prevented from running on 64-bit Windows as it would cause unexpected results. (@hitenkoku)
- MITRE ATT&CK tag output can be customized in `output_tag.txt`. (@hitenkoku)
- Added Channel column output. (@hitenkoku)
**Bug Fixes:**
- `.yml` files in the `.git` folder would cause parse errors so they are now ignored. (@hitenkoku)
- Removed unnecessary newline due to loading test file rules. (@hitenkoku)
- Fixed output stopping in Windows Terminal due a bug in Terminal itself. (@hitenkoku)
## v1.1.0 [2022/03/03]
**New Features:**
- Can specify a single rule with the `-r / --rules` option. (Great for testing rules!) (@kazuminn)
- Rule update option (`-u / --update-rules`): Update to the latest rules in the [hayabusa-rules](https://github.com/Yamato-Security/hayabusa-rules) repository. (@hitenkoku)
- Live analysis option (`-l / --live-analysis`): Can easily perform live analysis on Windows machines without specifying the Windows event log directory. (@hitenkoku)
**Enhancements:**
- Updated documentation. (@kazuminn , @hitenkoku , @YamatoSecurity)
- Updated rules. (20+ Hayabusa rules, 200+ Sigma rules) (@YamatoSecurity)
- Windows binaries are now statically compiled so installing Visual C++ Redistributable is not required. (@hitenkoku)
@@ -43,12 +58,15 @@
- Updated cargo crates. (@YamatoSecurity)
**Bug Fixes:**
- Made the clap library version static to make `cargo update` more stable. (@hitenkoku)
- Some rules were not alerting if there were tabs or carriage returns in the fields. (@hitenkoku)
## v1.0.0-Release 2 [2022/01/27]
- Removed Excel result sample files as they were being flagged by anti-virus. (@YamatoSecurity)
- Updated the Rust evtx library to 0.7.2 (@YamatoSecurity)
## v1.0.0 [2021/12/25]
- Initial release.

40
Cargo.lock generated
View File

@@ -80,9 +80,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "backtrace"
version = "0.3.64"
version = "0.3.65"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e121dee8023ce33ab248d9ce1493df03c3b38a659b240096fcbd7048ff9c31f"
checksum = "11a17d453482a265fd5f8479f2a3f405566e6ca627837aaddb85af8b1ab8ef61"
dependencies = [
"addr2line",
"cc",
@@ -684,9 +684,9 @@ dependencies = [
[[package]]
name = "flate2"
version = "1.0.22"
version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e6988e897c1c9c485f43b47a529cef42fde0547f9d8d41a7062518f1d8fc53f"
checksum = "b39522e96686d38f4bc984b9198e3a0613264abaebaff2c5c918bfa6b6da09af"
dependencies = [
"cfg-if 1.0.0",
"crc32fast",
@@ -842,7 +842,7 @@ dependencies = [
[[package]]
name = "hayabusa"
version = "1.2.0"
version = "1.2.1"
dependencies = [
"base64 0.13.0",
"chrono",
@@ -930,9 +930,9 @@ dependencies = [
[[package]]
name = "httparse"
version = "1.6.0"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9100414882e15fb7feccb4897e5f0ff0ff1ca7d1a86a23208ada4d7a18e6c6c4"
checksum = "6330e8a36bd8c859f3fa6d9382911fbb7147ec39807f63b923933a247240b9ba"
[[package]]
name = "humantime"
@@ -1114,9 +1114,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.122"
version = "0.2.124"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec647867e2bf0772e28c8bcde4f0d19a9216916e890543b5a03ed8ef27b8f259"
checksum = "21a41fed9d98f27ab1c6d161da622a4fa35e8a54a8adc24bbf3ddd0ef70b0e50"
[[package]]
name = "libgit2-sys"
@@ -1246,12 +1246,11 @@ dependencies = [
[[package]]
name = "miniz_oxide"
version = "0.4.4"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b"
checksum = "d2b29bd4bc3f33391105ebee3589c19197c4271e3e5a9ec9bfe8127eeff8f082"
dependencies = [
"adler",
"autocfg 1.1.0",
]
[[package]]
@@ -1388,9 +1387,9 @@ dependencies = [
[[package]]
name = "object"
version = "0.27.1"
version = "0.28.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67ac1d3f9a1d3616fd9a60c8d74296f22406a238b6a72f5cc1e6f314df4ffbf9"
checksum = "40bec70ba014595f99f7aa110b84331ffe1ee9aece7fe6f387cc7e3ecda4d456"
dependencies = [
"memchr",
]
@@ -1698,9 +1697,9 @@ dependencies = [
[[package]]
name = "rayon"
version = "1.5.1"
version = "1.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90"
checksum = "fd249e82c21598a9a426a4e00dd7adc1d640b22445ec8545feef801d1a74c221"
dependencies = [
"autocfg 1.1.0",
"crossbeam-deque 0.8.1",
@@ -1710,14 +1709,13 @@ dependencies = [
[[package]]
name = "rayon-core"
version = "1.9.1"
version = "1.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e"
checksum = "9f51245e1e62e1f1629cbfec37b5793bbabcaeb90f30e94d2ba03564687353e4"
dependencies = [
"crossbeam-channel",
"crossbeam-deque 0.8.1",
"crossbeam-utils 0.8.8",
"lazy_static",
"num_cpus",
]
@@ -1822,9 +1820,9 @@ dependencies = [
[[package]]
name = "rpmalloc-sys"
version = "0.2.2+1.4.1"
version = "0.2.3+b097fd0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "370e623bf2ca97dd497b7dd0e2889ec953a46c8c268489a818a5e305633e8609"
checksum = "8d4b7d5e225a53887ee57fcec492eaf114b8e290f7072d035adc6ddd6810b67b"
dependencies = [
"cc",
"libc",

View File

@@ -1,6 +1,6 @@
[package]
name = "hayabusa"
version = "1.2.0"
version = "1.2.1"
authors = ["Yamato Security @SecurityYamato"]
edition = "2021"

View File

@@ -56,6 +56,7 @@ Hayabusaは、日本の[Yamato Security](https://yamatosecurity.connpass.com/)
- [サンプルevtxファイルでHayabusaをテストする](#サンプルevtxファイルでhayabusaをテストする)
- [Hayabusaの出力](#hayabusaの出力)
- [MITRE ATT&CK戦術の省略](#mitre-attck戦術の省略)
- [Channel情報の省略](#channel情報の省略)
- [プログレスバー](#プログレスバー)
- [標準出力へのカラー設定](#標準出力へのカラー設定)
- [Hayabusaルール](#hayabusaルール)
@@ -170,6 +171,11 @@ hayabusa.exe -u
アップデートが失敗した場合は、`rules`フォルダの名前を変更してから、もう一回アップデートしてみて下さい。
>> 注意: アップデートを実行する際に `rules` フォルダは [hayabusa-rules](https://github.com/Yamato-Security/hayabusa-rules) レポジトリの最新のルールとコンフィグファイルに置き換えられます
>> 既存ファイルへの修正はすべて上書きされますので、アップデート実行前に編集したファイルのバックアップをおすすめします。
>> もし、`--level-tuning` を行っているのであれば、アップデート後にルールファイルの再調整をしてください
>> `rules`フォルダ内に新しく追加したルールは、アップデート時に上書きもしくは削除は行われません。
# ソースコードからのコンパイル(任意)
Rustがインストールされている場合、以下のコマンドでソースコードからコンパイルすることができます:
@@ -320,7 +326,7 @@ USAGE:
-s --statistics 'イベント ID の統計情報を表示する。'
-q --quiet 'Quietモード。起動バナーを表示しない。'
-Q --quiet-errors 'Quiet errorsモード。エラーログを保存しない。'
--level-tuning <LEVEL_TUNING_FILE> 'ルールlevelのチューニング [default: ./config/level_tuning.txt]'
--level-tuning <LEVEL_TUNING_FILE> 'ルールlevelのチューニング [default: ./rules/config/level_tuning.txt]'
-p --pivot-keywords-list 'ピボットキーワードの一覧作成。'
--contributors 'コントリビュータの一覧表示。'
```
@@ -460,6 +466,7 @@ Hayabusaの結果を標準出力に表示しているときデフォルト
* `Timestamp`: デフォルトでは`YYYY-MM-DD HH:mm:ss.sss +hh:mm`形式になっています。イベントログの`<Event><System><TimeCreated SystemTime>`フィールドから来ています。デフォルトのタイムゾーンはローカルのタイムゾーンになりますが、`--utc` オプションで UTC に変更することができます。
* `Computer`: イベントログの`<Event><System><Computer>`フィールドから来ています。
* `Channel`: ログ名です。イベントログの`<Event><System><EventID>`フィールドから来ています。
* `Event ID`: イベントログの`<Event><System><EventID>`フィールドから来ています。
* `Level`: YML検知ルールの`level`フィールドから来ています。(例:`informational`, `low`, `medium`, `high`, `critical`) デフォルトでは、すべてのレベルのアラートとイベントが出力されますが、`-m`オプションで最低のレベルを指定することができます。例えば`-m high`オプションを付けると、`high``critical`アラートしか出力されません。
* `Title`: YML検知ルールの`title`フィールドから来ています。
@@ -493,6 +500,38 @@ CSVファイルとして保存する場合、以下の列が追加されます:
* `Exfil` : Exfiltration (持ち出し)
* `Impact` : Impact (影響)
## Channel情報の省略
簡潔に出力するためにChannelの表示を以下のように省略しています。
`config/channel_abbreviations.txt`の設定ファイルで自由に編集できます。
* `Application` : App
* `DNS Server` : DNS-Svr
* `Microsoft-ServiceBus-Client` : SvcBusCli
* `Microsoft-Windows-CodeIntegrity/Operational` : CodeInteg
* `Microsoft-Windows-LDAP-Client/Debug` : LDAP-Cli
* `Microsoft-Windows-AppLocker/MSI and Script` : AppLocker
* `Microsoft-Windows-AppLocker/EXE and DLL` : AppLocker
* `Microsoft-Windows-AppLocker/Packaged app-Deployment` : AppLocker
* `Microsoft-Windows-AppLocker/Packaged app-Execution` : AppLocker
* `Microsoft-Windows-Bits-Client/Operational` : BitsCli
* `Microsoft-Windows-DHCP-Server/Operational` : DHCP-Svr
* `Microsoft-Windows-DriverFrameworks-UserMode/Operational` : DvrFmwk
* `Microsoft-Windows-NTLM/Operational` : NTLM
* `Microsoft-Windows-SmbClient/Security` : SmbCliSec
* `Microsoft-Windows-Sysmon/Operational` : Sysmon
* `Microsoft-Windows-TaskScheduler/Operational` : TaskSch
* `Microsoft-Windows-PrintService/Admin` : PrintAdm
* `Microsoft-Windows-PrintService/Operational` : PrintOp
* `Microsoft-Windows-PowerShell/Operational` : PwSh
* `Microsoft-Windows-Windows Defender/Operational` : Defender
* `Microsoft-Windows-Windows Firewall With Advanced Security/Firewall` : Firewall
* `Microsoft-Windows-WMI-Activity/Operational` : WMI
* `MSExchange Management` : Exchange
* `Security` : Sec
* `System` : Sys
* `Windows PowerShell` : WinPwSh
## プログレスバー
プログレス・バーは、複数のevtxファイルに対してのみ機能します。
@@ -560,10 +599,10 @@ Hayabusaルールは、Windowsのイベントログ解析専用に設計され
## 検知レベルのlevelチューニング
Hayabusaルール、Sigmaルールはそれぞれの作者が検知した際のリスクレベルを決めています。
ユーザが独自のリスクレベルに設定するには`./config/level_tuning.txt`に変換情報を書き、`hayabusa.exe --level-tuning`を実行することでルールファイルが書き換えられます。
ユーザが独自のリスクレベルに設定するには`./rules/config/level_tuning.txt`に変換情報を書き、`hayabusa.exe --level-tuning`を実行することでルールファイルが書き換えられます。
ルールファイルが直接書き換えられることに注意して使用してください。
`./config/level_tuning.txt`の例:
`./rules/config/level_tuning.txt`の例:
```
id,new_level
00000000-0000-0000-0000-000000000000,informational # sample level tuning line

View File

@@ -56,6 +56,7 @@ Hayabusa is a **Windows event log fast forensics timeline generator** and **thre
- [Testing Hayabusa on Sample Evtx Files](#testing-hayabusa-on-sample-evtx-files)
- [Hayabusa Output](#hayabusa-output)
- [MITRE ATT&CK Tactics Abbreviations](#mitre-attck-tactics-abbreviations)
- [Channel Abbreviations](#channel-abbreviations)
- [Progress Bar](#progress-bar)
- [Color Output](#color-output)
- [Hayabusa Rules](#hayabusa-rules)
@@ -168,6 +169,11 @@ hayabusa.exe -u
If the update fails, you may need to rename the `rules` folder and try again.
>> Caution: When updating, rules and config files in the `rules` folder are replaced with the latest rules and config files in the [hayabusa-rules](https://github.com/Yamato-Security/hayabusa-rules) repository.
>> Any changes you make to existing files will be overwritten, so we recommend that you make backups of any files that you edit before updating.
>> If you are performing level tuning with `--level-tuning`, please re-tune your rule files after each update.
>> If you add new rules inside of the `rules` folder, they will **not** be overwritten or deleted when updating.
# Compiling From Source (Optional)
If you have Rust installed, you can compile from source with the following command:
@@ -313,7 +319,7 @@ USAGE:
-s --statistics 'Prints statistics of event IDs.'
-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> 'Tune the rule level [default: ./config/level_tuning.txt]'
--level-tuning <LEVEL_TUNING_FILE> 'Tune the rule level [default: ./rules/config/level_tuning.txt]'
-p --pivot-keywords-list 'Create a list of pivot keywords.'
--contributors 'Prints the list of contributors.'
```
@@ -453,6 +459,7 @@ When hayabusa output is being displayed to the screen (the default), it will dis
* `Timestamp`: Default is `YYYY-MM-DD HH:mm:ss.sss +hh:mm` format. This comes from the `<Event><System><TimeCreated SystemTime>` field in the event log. The default timezone will be the local timezone but you can change the timezone to UTC with the `--utc` option.
* `Computer`: This comes from the `<Event><System><Computer>` field in the event log.
* `Channel`: The name of log. This comes from the `<Event><System><Channel>` field in the event log.
* `Event ID`: This comes from the `<Event><System><EventID>` field in the event log.
* `Level`: This comes from the `level` field in the YML detection rule. (`informational`, `low`, `medium`, `high`, `critical`) By default, all level alerts will be displayed but you can set the minimum level with `-m`. For example, you can set `-m high`) in order to only scan for and display high and critical alerts.
* `Title`: This comes from the `title` field in the YML detection rule.
@@ -486,6 +493,38 @@ You can freely edit these abbreviations in the `config/output_tag.txt` configura
* `Exfil` : Exfiltration
* `Impact` : Impact
## Channel Abbreviations
In order to save space, we use the following abbreviations when displaying Channel.
You can freely edit these abbreviations in the `config/config/channel_abbreviations.txt` configuration file.
* `Application` : App
* `DNS Server` : DNS-Svr
* `Microsoft-ServiceBus-Client` : SvcBusCli
* `Microsoft-Windows-CodeIntegrity/Operational` : CodeInteg
* `Microsoft-Windows-LDAP-Client/Debug` : LDAP-Cli
* `Microsoft-Windows-AppLocker/MSI and Script` : AppLocker
* `Microsoft-Windows-AppLocker/EXE and DLL` : AppLocker
* `Microsoft-Windows-AppLocker/Packaged app-Deployment` : AppLocker
* `Microsoft-Windows-AppLocker/Packaged app-Execution` : AppLocker
* `Microsoft-Windows-Bits-Client/Operational` : BitsCli
* `Microsoft-Windows-DHCP-Server/Operational` : DHCP-Svr
* `Microsoft-Windows-DriverFrameworks-UserMode/Operational` : DvrFmwk
* `Microsoft-Windows-NTLM/Operational` : NTLM
* `Microsoft-Windows-SmbClient/Security` : SmbCliSec
* `Microsoft-Windows-Sysmon/Operational` : Sysmon
* `Microsoft-Windows-TaskScheduler/Operational` : TaskSch
* `Microsoft-Windows-PrintService/Admin` : PrintAdm
* `Microsoft-Windows-PrintService/Operational` : PrintOp
* `Microsoft-Windows-PowerShell/Operational` : PwSh
* `Microsoft-Windows-Windows Defender/Operational` : Defender
* `Microsoft-Windows-Windows Firewall With Advanced Security/Firewall` : Firewall
* `Microsoft-Windows-WMI-Activity/Operational` : WMI
* `MSExchange Management` : Exchange
* `Security` : Sec
* `System` : Sys
* `Windows PowerShell` : WinPwSh
## Progress Bar
The progress bar will only work with multiple evtx files.
@@ -552,10 +591,10 @@ You can also add a rule ID to `rules/config/noisy_rules.txt` in order to ignore
Hayabusa and Sigma rule authors will determine the risk level of the alert when writing their rules.
However, the actual risk level will differ between environments.
You can tune the risk level of the rules by adding them to `./config/level_tuning.txt` and executing `hayabusa.exe --level-tuning` which will update the `level` line in the rule file.
You can tune the risk level of the rules by adding them to `./rules/config/level_tuning.txt` and executing `hayabusa.exe --level-tuning` which will update the `level` line in the rule file.
Please note that the rule file will be updated directly.
`./config/level_tuning.txt` sample line:
`./rules/config/level_tuning.txt` sample line:
```
id,new_level

View File

@@ -0,0 +1,27 @@
Channel,Abbreviation
Application,App
DNS Server,DNS-Svr
Microsoft-ServiceBus-Client,SvcBusCli
Microsoft-Windows-CodeIntegrity/Operational,CodeInteg
Microsoft-Windows-LDAP-Client/Debug,LDAP-Cli
Microsoft-Windows-AppLocker/MSI and Script,AppLocker
Microsoft-Windows-AppLocker/EXE and DLL,AppLocker
Microsoft-Windows-AppLocker/Packaged app-Deployment,AppLocker
Microsoft-Windows-AppLocker/Packaged app-Execution,AppLocker
Microsoft-Windows-Bits-Client/Operational,BitsCli
Microsoft-Windows-DHCP-Server/Operational,DHCP-Svr
Microsoft-Windows-DriverFrameworks-UserMode/Operational,DvrFmwk
Microsoft-Windows-NTLM/Operational,NTLM
Microsoft-Windows-SmbClient/Security,SmbCliSec
Microsoft-Windows-Sysmon/Operational,Sysmon
Microsoft-Windows-TaskScheduler/Operational,TaskSch
Microsoft-Windows-PrintService/Admin,PrintAdm
Microsoft-Windows-PrintService/Operational,PrintOp
Microsoft-Windows-PowerShell/Operational,PwSh
Microsoft-Windows-Windows Defender/Operational,Defender
Microsoft-Windows-Windows Firewall With Advanced Security/Firewall,Firewall
Microsoft-Windows-WMI-Activity/Operational,WMI
MSExchange Management,Exchange
Security,Sec
System,Sys
Windows PowerShell,WinPwSh

View File

@@ -1,2 +0,0 @@
id,new_level
00000000-0000-0000-0000-000000000000,informational # sample level tuning line

View File

@@ -19,6 +19,7 @@ use std::process;
pub struct CsvFormat<'a> {
timestamp: &'a str,
computer: &'a str,
channel: &'a str,
event_i_d: &'a str,
level: &'a str,
mitre_attack: &'a str,
@@ -35,6 +36,7 @@ pub struct CsvFormat<'a> {
pub struct DisplayFormat<'a> {
timestamp: &'a str,
pub computer: &'a str,
pub channel: &'a str,
pub event_i_d: &'a str,
pub level: &'a str,
pub rule_title: &'a str,
@@ -167,6 +169,7 @@ fn emit_csv<W: std::io::Write>(
level: &_format_cell(&level, ColPos::Other, colors),
computer: &_format_cell(&detect_info.computername, ColPos::Other, colors),
event_i_d: &_format_cell(&detect_info.eventid, ColPos::Other, colors),
channel: &_format_cell(&detect_info.channel, ColPos::Other, colors),
rule_title: &_format_cell(&detect_info.alert, ColPos::Other, colors),
details: &_format_cell(&details, ColPos::Other, colors),
record_information: recinfo.as_deref(),
@@ -179,6 +182,7 @@ fn emit_csv<W: std::io::Write>(
level: &level,
computer: &detect_info.computername,
event_i_d: &detect_info.eventid,
channel: &detect_info.channel,
mitre_attack: &detect_info.tag_info,
rule_title: &detect_info.alert,
details: &detect_info.detail,
@@ -323,6 +327,7 @@ mod tests {
use crate::afterfact::emit_csv;
use crate::detections::print;
use crate::detections::print::DetectInfo;
use crate::detections::print::CH_CONFIG;
use chrono::{Local, TimeZone, Utc};
use serde_json::Value;
use std::fs::File;
@@ -337,12 +342,13 @@ mod tests {
}
fn test_emit_csv_output() {
let testfilepath: &str = "test.evtx";
let testrulepath: &str = "test-rule.yml";
let test_filepath: &str = "test.evtx";
let test_rulepath: &str = "test-rule.yml";
let test_title = "test_title";
let test_level = "high";
let test_computername = "testcomputer";
let test_eventid = "1111";
let test_channel = "Sec";
let output = "pokepoke";
let test_attack = "execution/txxxx.yyy";
let test_recinfo = "record_infoinfo11";
@@ -368,11 +374,15 @@ mod tests {
&event,
output.to_string(),
DetectInfo {
filepath: testfilepath.to_string(),
rulepath: testrulepath.to_string(),
filepath: test_filepath.to_string(),
rulepath: test_rulepath.to_string(),
level: test_level.to_string(),
computername: test_computername.to_string(),
eventid: test_eventid.to_string(),
channel: CH_CONFIG
.get("Security")
.unwrap_or(&String::default())
.to_string(),
alert: test_title.to_string(),
detail: String::default(),
tag_info: test_attack.to_string(),
@@ -385,7 +395,7 @@ mod tests {
.unwrap();
let expect_tz = expect_time.with_timezone(&Local);
let expect =
"Timestamp,Computer,EventID,Level,MitreAttack,RuleTitle,Details,RecordInformation,RulePath,FilePath\n"
"Timestamp,Computer,Channel,EventID,Level,MitreAttack,RuleTitle,Details,RecordInformation,RulePath,FilePath\n"
.to_string()
+ &expect_tz
.clone()
@@ -394,6 +404,8 @@ mod tests {
+ ","
+ test_computername
+ ","
+ test_channel
+ ","
+ test_eventid
+ ","
+ test_level
@@ -406,9 +418,9 @@ mod tests {
+ ","
+ test_recinfo
+ ","
+ testrulepath
+ test_rulepath
+ ","
+ testfilepath
+ test_filepath
+ "\n";
let mut file: Box<dyn io::Write> = Box::new(File::create("./test_emit_csv.csv").unwrap());
assert!(emit_csv(&mut file, false, None).is_ok());
@@ -423,12 +435,13 @@ mod tests {
}
fn check_emit_csv_display() {
let testfilepath: &str = "test2.evtx";
let testrulepath: &str = "test-rule2.yml";
let test_filepath: &str = "test2.evtx";
let test_rulepath: &str = "test-rule2.yml";
let test_title = "test_title2";
let test_level = "medium";
let test_computername = "testcomputer2";
let test_eventid = "2222";
let expect_channel = "Sysmon";
let output = "displaytest";
let test_attack = "execution/txxxx.zzz";
{
@@ -453,11 +466,15 @@ mod tests {
&event,
output.to_string(),
DetectInfo {
filepath: testfilepath.to_string(),
rulepath: testrulepath.to_string(),
filepath: test_filepath.to_string(),
rulepath: test_rulepath.to_string(),
level: test_level.to_string(),
computername: test_computername.to_string(),
eventid: test_eventid.to_string(),
channel: CH_CONFIG
.get("Microsoft-Windows-Sysmon/Operational")
.unwrap_or(&String::default())
.to_string(),
alert: test_title.to_string(),
detail: String::default(),
tag_info: test_attack.to_string(),
@@ -471,7 +488,7 @@ mod tests {
.unwrap();
let expect_tz = expect_time.with_timezone(&Local);
let expect_header =
"Timestamp|Computer|EventID|Level|RuleTitle|Details|RecordInformation\n";
"Timestamp|Computer|Channel|EventID|Level|RuleTitle|Details|RecordInformation\n";
let expect_colored = expect_header.to_string()
+ &get_white_color_string(
&expect_tz
@@ -482,6 +499,8 @@ mod tests {
+ " | "
+ &get_white_color_string(test_computername)
+ " | "
+ &get_white_color_string(expect_channel)
+ " | "
+ &get_white_color_string(test_eventid)
+ " | "
+ &get_white_color_string(test_level)
@@ -500,6 +519,8 @@ mod tests {
+ " | "
+ test_computername
+ " | "
+ expect_channel
+ " | "
+ test_eventid
+ " | "
+ test_level

View File

@@ -102,7 +102,7 @@ fn build_app<'a>() -> ArgMatches<'a> {
.arg(
// TODO: When update claps to 3.x, these can write in usage texts...
Arg::from_usage("--level-tuning=[LEVEL_TUNING_FILE] 'Adjust rule level.'")
.default_value("./config/level_tuning.txt"),
.default_value("./rules/config/level_tuning.txt"),
)
.usage(usages)
.args_from_usage(usages)

View File

@@ -9,7 +9,7 @@ use crate::detections::print::MESSAGES;
use crate::detections::print::PIVOT_KEYWORD_LIST_FLAG;
use crate::detections::print::QUIET_ERRORS_FLAG;
use crate::detections::print::STATISTICS_FLAG;
use crate::detections::print::TAGS_CONFIG;
use crate::detections::print::{CH_CONFIG, TAGS_CONFIG};
use crate::detections::rule;
use crate::detections::rule::AggResult;
use crate::detections::rule::RuleNode;
@@ -219,6 +219,13 @@ impl Detection {
.replace('\"', ""),
eventid: get_serde_number_to_string(&record_info.record["Event"]["System"]["EventID"])
.unwrap_or_else(|| "-".to_owned()),
channel: CH_CONFIG
.get(
&get_serde_number_to_string(&record_info.record["Event"]["System"]["Channel"])
.unwrap_or_default(),
)
.unwrap_or(&String::default())
.to_string(),
alert: rule.yaml["title"].as_str().unwrap_or("").to_string(),
detail: String::default(),
tag_info: tag_info.join(" | "),
@@ -252,6 +259,7 @@ impl Detection {
level: rule.yaml["level"].as_str().unwrap_or("").to_owned(),
computername: "-".to_owned(),
eventid: "-".to_owned(),
channel: "-".to_owned(),
alert: rule.yaml["title"].as_str().unwrap_or("").to_owned(),
detail: output,
record_information: rec_info,

View File

@@ -28,6 +28,7 @@ pub struct DetectInfo {
pub level: String,
pub computername: String,
pub eventid: String,
pub channel: String,
pub alert: String,
pub detail: String,
pub tag_info: String,
@@ -55,7 +56,9 @@ lazy_static! {
.args
.is_present("statistics");
pub static ref TAGS_CONFIG: HashMap<String, String> =
Message::create_tags_config("config/output_tag.txt");
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 PIVOT_KEYWORD_LIST_FLAG: bool = configs::CONFIG
.read()
.unwrap()
@@ -77,7 +80,7 @@ impl Message {
/// ファイルパスで記載されたtagでのフル名、表示の際に置き換えられる文字列のHashMapを作成する関数。tagではこのHashMapのキーに対応しない出力は出力しないものとする
/// ex. attack.impact,Impact
pub fn create_tags_config(path: &str) -> HashMap<String, String> {
pub fn create_output_filter_config(path: &str) -> HashMap<String, String> {
let read_result = utils::read_csv(path);
if read_result.is_err() {
AlertMessage::alert(
@@ -283,6 +286,7 @@ mod tests {
level: "high".to_string(),
computername: "testcomputer1".to_string(),
eventid: "1".to_string(),
channel: String::default(),
alert: "test1".to_string(),
detail: String::default(),
tag_info: "txxx.001".to_string(),
@@ -314,6 +318,7 @@ mod tests {
level: "high".to_string(),
computername: "testcomputer2".to_string(),
eventid: "2".to_string(),
channel: String::default(),
alert: "test2".to_string(),
detail: String::default(),
tag_info: "txxx.002".to_string(),
@@ -345,6 +350,7 @@ mod tests {
level: "high".to_string(),
computername: "testcomputer3".to_string(),
eventid: "3".to_string(),
channel: String::default(),
alert: "test3".to_string(),
detail: String::default(),
tag_info: "txxx.003".to_string(),
@@ -371,6 +377,7 @@ mod tests {
level: "medium".to_string(),
computername: "testcomputer4".to_string(),
eventid: "4".to_string(),
channel: String::default(),
alert: "test4".to_string(),
detail: String::default(),
tag_info: "txxx.004".to_string(),
@@ -380,7 +387,7 @@ mod tests {
let display = format!("{}", format_args!("{:?}", message));
println!("display::::{}", display);
let expect = "Message { map: {1970-01-01T00:00:00Z: [DetectInfo { filepath: \"a\", rulepath: \"test_rule4\", level: \"medium\", computername: \"testcomputer4\", eventid: \"4\", alert: \"test4\", detail: \"CommandLine4: hoge\", tag_info: \"txxx.004\", record_information: Some(\"record_information4\") }], 1996-02-27T01:05:01Z: [DetectInfo { filepath: \"a\", rulepath: \"test_rule\", level: \"high\", computername: \"testcomputer1\", eventid: \"1\", alert: \"test1\", detail: \"CommandLine1: hoge\", tag_info: \"txxx.001\", record_information: Some(\"record_information1\") }, DetectInfo { filepath: \"a\", rulepath: \"test_rule2\", level: \"high\", computername: \"testcomputer2\", eventid: \"2\", alert: \"test2\", detail: \"CommandLine2: hoge\", tag_info: \"txxx.002\", record_information: Some(\"record_information2\") }], 2000-01-21T09:06:01Z: [DetectInfo { filepath: \"a\", rulepath: \"test_rule3\", level: \"high\", computername: \"testcomputer3\", eventid: \"3\", alert: \"test3\", detail: \"CommandLine3: hoge\", tag_info: \"txxx.003\", record_information: Some(\"record_information3\") }]} }";
let expect = "Message { map: {1970-01-01T00:00:00Z: [DetectInfo { filepath: \"a\", rulepath: \"test_rule4\", level: \"medium\", computername: \"testcomputer4\", eventid: \"4\", channel: \"\", alert: \"test4\", detail: \"CommandLine4: hoge\", tag_info: \"txxx.004\", record_information: Some(\"record_information4\") }], 1996-02-27T01:05:01Z: [DetectInfo { filepath: \"a\", rulepath: \"test_rule\", level: \"high\", computername: \"testcomputer1\", eventid: \"1\", channel: \"\", alert: \"test1\", detail: \"CommandLine1: hoge\", tag_info: \"txxx.001\", record_information: Some(\"record_information1\") }, DetectInfo { filepath: \"a\", rulepath: \"test_rule2\", level: \"high\", computername: \"testcomputer2\", eventid: \"2\", channel: \"\", alert: \"test2\", detail: \"CommandLine2: hoge\", tag_info: \"txxx.002\", record_information: Some(\"record_information2\") }], 2000-01-21T09:06:01Z: [DetectInfo { filepath: \"a\", rulepath: \"test_rule3\", level: \"high\", computername: \"testcomputer3\", eventid: \"3\", channel: \"\", alert: \"test3\", detail: \"CommandLine3: hoge\", tag_info: \"txxx.003\", record_information: Some(\"record_information3\") }]} }";
assert_eq!(display, expect);
}
@@ -474,7 +481,7 @@ mod tests {
);
}
#[test]
/// outputで指定されているキー(eventkey_alias.txt内で設定済み)が対象のレコード内に該当する情報がない場合の出力テスト
/// output test when no exist info in target record output and described key-value data in eventkey_alias.txt
fn test_parse_message_not_exist_value_in_record() {
let mut message = Message::new();
let json_str = r##"
@@ -502,9 +509,9 @@ mod tests {
);
}
#[test]
/// output_tag.txtの読み込みテスト
/// test of loading output filter config by output_tag.txt
fn test_load_output_tag() {
let actual = Message::create_tags_config("test_files/config/output_tag.txt");
let actual = Message::create_output_filter_config("test_files/config/output_tag.txt");
let expected: HashMap<String, String> = HashMap::from([
("attack.impact".to_string(), "Impact".to_string()),
("xxx".to_string(), "yyy".to_string()),

View File

@@ -184,11 +184,11 @@ pub fn get_event_value<'a>(key: &str, event_value: &'a Value) -> Option<&'a Valu
pub fn get_thread_num() -> usize {
let def_thread_num_str = num_cpus::get().to_string();
let conf = configs::CONFIG.read().unwrap();
let threadnum = &conf
.args
conf.args
.value_of("thread-number")
.unwrap_or(def_thread_num_str.as_str());
threadnum.parse::<usize>().unwrap()
.unwrap_or(def_thread_num_str.as_str())
.parse::<usize>()
.unwrap()
}
pub fn create_tokio_runtime() -> Runtime {

View File

@@ -19,10 +19,16 @@ pub struct RuleExclude {
pub no_use_rule: HashSet<String>,
}
impl RuleExclude {
pub fn default() -> RuleExclude {
RuleExclude {
no_use_rule: HashSet::new(),
}
}
}
pub fn exclude_ids() -> RuleExclude {
let mut exclude_ids = RuleExclude {
no_use_rule: HashSet::new(),
};
let mut exclude_ids = RuleExclude::default();
if !configs::CONFIG
.read()

View File

@@ -235,7 +235,7 @@ impl App {
.unwrap()
.args
.value_of("level-tuning")
.unwrap_or("./config/level_tuning.txt")
.unwrap_or("./rules/config/level_tuning.txt")
.to_string();
if Path::new(&level_tuning_config_path).exists() {
@@ -253,7 +253,7 @@ impl App {
} else {
AlertMessage::alert(
&mut BufWriter::new(std::io::stderr().lock()),
"Need rule_levels.txt file to use --level-tuning option [default: ./config/level_tuning.txt]",
"Need rule_levels.txt file to use --level-tuning option [default: ./rules/config/level_tuning.txt]",
)
.ok();
}
@@ -654,17 +654,21 @@ impl App {
println!(
"Attempting to git clone the hayabusa-rules repository into the rules folder."
);
// レポジトリが開けなかった段階でhayabusa rulesのgit cloneを実施する
// execution git clone of hayabusa-rules repository when failed open hayabusa repository.
result = self.clone_rules();
} else if hayabusa_rule_repo.is_ok() {
// rulesrepositoryが確認できる場合
// origin/mainのfetchができなくなるケースはネットワークなどのケースが考えられるため、git cloneは実施しない
// case of exist hayabusa-rules repository
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.
prev_modified_rules = self.get_updated_rules("rules", &prev_modified_time);
prev_modified_time = fs::metadata("rules").unwrap().modified().unwrap();
result = self.pull_repository(hayabusa_rule_repo.unwrap());
result = self.pull_repository(&hayabusa_rule_repo.unwrap());
} else {
// hayabusa-rulesrepositoryrulesに存在しない場合
// hayabusa repositoryがあればsubmodule情報もあると思われるのでupdate
// case of no exist hayabusa-rules repository in rules.
// execute update because submodule information exists if hayabusa repository exists submodule information.
self._repo_main_reset_hard(hayabusa_rule_repo.as_ref().unwrap())?;
prev_modified_time = fs::metadata("rules").unwrap().modified().unwrap();
let rules_path = Path::new("rules");
if !rules_path.exists() {
@@ -673,12 +677,12 @@ impl App {
let hayabusa_repo = hayabusa_repo.unwrap();
let submodules = hayabusa_repo.submodules()?;
let mut is_success_submodule_update = true;
// submoduleのname参照だと参照先を変えることで意図しないフォルダを削除する可能性があるためハードコーディングする
// submodule rules erase path is hard coding to avoid unintentional remove folder.
fs::remove_dir_all(".git/.submodule/rules").ok();
for mut submodule in submodules {
submodule.update(true, None)?;
let submodule_repo = submodule.open()?;
if let Err(e) = self.pull_repository(submodule_repo) {
if let Err(e) = self.pull_repository(&submodule_repo) {
AlertMessage::alert(
&mut BufWriter::new(std::io::stderr().lock()),
&format!("Failed submodule update. {}", e),
@@ -701,8 +705,21 @@ impl App {
result
}
/// hard reset in main branch
fn _repo_main_reset_hard(&self, input_repo: &Repository) -> Result<(), git2::Error> {
let branch = input_repo
.find_branch("main", git2::BranchType::Local)
.unwrap();
let local_head = branch.get().target().unwrap();
let object = input_repo.find_object(local_head, None).unwrap();
match input_repo.reset(&object, git2::ResetType::Hard, None) {
Ok(()) => Ok(()),
_ => Err(git2::Error::from_str("Failed reset main branch in rules")),
}
}
/// Pull(fetch and fast-forward merge) repositoryto input_repo.
fn pull_repository(&self, input_repo: Repository) -> Result<String, git2::Error> {
fn pull_repository(&self, input_repo: &Repository) -> Result<String, git2::Error> {
match input_repo
.find_remote("origin")?
.fetch(&["main"], None, None)
@@ -775,9 +792,7 @@ impl App {
.read_dir(
rule_folder_path,
"INFORMATIONAL",
&filter::RuleExclude {
no_use_rule: HashSet::new(),
},
&filter::RuleExclude::default(),
)
.ok();

View File

@@ -1,5 +1,5 @@
use crate::detections::{configs, utils};
use crate::filter;
use crate::filter::RuleExclude;
use crate::yaml::ParseYaml;
use std::collections::HashMap;
use std::fs::{self, File};
@@ -45,8 +45,9 @@ impl LevelTuning {
// Read Rule files
let mut rulefile_loader = ParseYaml::new();
//noisy rules and exclude rules treats as update target
let result_readdir =
rulefile_loader.read_dir(rules_path, "informational", &filter::exclude_ids());
rulefile_loader.read_dir(rules_path, "informational", &RuleExclude::default());
if result_readdir.is_err() {
return Result::Err(format!("{}", result_readdir.unwrap_err()));
}
@@ -98,9 +99,6 @@ impl LevelTuning {
#[cfg(test)]
mod tests {
// use crate::{filter::RuleExclude, yaml};
// use hashbrown::HashSet;
use super::*;
#[test]

View File

@@ -290,9 +290,7 @@ mod tests {
AlertMessage::create_error_log(ERROR_LOG_PATH.to_string());
let mut yaml = yaml::ParseYaml::new();
let exclude_ids = RuleExclude {
no_use_rule: HashSet::new(),
};
let exclude_ids = RuleExclude::default();
let _ = &yaml.read_dir(
"test_files/rules/yaml/1.yml",
&String::default(),
@@ -401,9 +399,7 @@ mod tests {
let mut yaml = yaml::ParseYaml::new();
let path = Path::new("test_files/rules/yaml");
let exclude_ids = RuleExclude {
no_use_rule: HashSet::new(),
};
let exclude_ids = RuleExclude::default();
yaml.read_dir(path, "", &exclude_ids).unwrap();
assert_eq!(yaml.ignorerule_count, 0);
}
@@ -411,9 +407,7 @@ mod tests {
fn test_exclude_deprecated_rules_file() {
let mut yaml = yaml::ParseYaml::new();
let path = Path::new("test_files/rules/deprecated");
let exclude_ids = RuleExclude {
no_use_rule: HashSet::new(),
};
let exclude_ids = RuleExclude::default();
yaml.read_dir(path, "", &exclude_ids).unwrap();
assert_eq!(yaml.ignorerule_count, 1);
}