From b47561a79c063955ff468c9acd826014d2e08eb4 Mon Sep 17 00:00:00 2001 From: DustInDark Date: Tue, 17 May 2022 11:32:57 +0900 Subject: [PATCH] remove color option (#518) * removed used crate in color option and add term color #481 * removed level_color.txt due to fix output color #481 * removed color definition by file * update cargo * removed color definiton by true type vec * added hex crate * added level_color.txt and color output to command prompt and powershell #481 * adjust termcolor crate * restored level_color.txt * remove c option #481 * fixed document #481 * fixed stdoutput test * add no-color option #481 - disable color output when no-color option set * added no-color option document * Fixed clipy err * doc, changelog, cargo pkg update * changelog and rules update * version up to 1.2.2 * readme and changelog update * reformat to markdown lint * adjusted logon summary generator section in japanese readme to english readme * fixed typo in readme Co-authored-by: garigariganzy Co-authored-by: Tanaka Zakku <71482215+YamatoSecurity@users.noreply.github.com> --- CHANGELOG-Japanese.md | 25 ++- CHANGELOG.md | 22 ++- Cargo.lock | 232 ++++++++++++--------------- Cargo.toml | 4 +- README-Japanese.md | 11 +- README.md | 15 +- config/level_color.txt | 3 +- contributors.txt | 1 - src/afterfact.rs | 330 ++++++++++++++++++-------------------- src/detections/configs.rs | 4 +- 10 files changed, 308 insertions(+), 339 deletions(-) diff --git a/CHANGELOG-Japanese.md b/CHANGELOG-Japanese.md index 5c1e0b95..d001ff67 100644 --- a/CHANGELOG-Japanese.md +++ b/CHANGELOG-Japanese.md @@ -1,15 +1,30 @@ # 変更点 -## v1.2.1 [2022/04/20] Black Hat Asia Arsenal 2022 Preview Release +## v1.2.2 [2022/05/17] **新機能:** -- 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) + +- ログオン情報の要約の機能の追加。 (`-L` / `--logon-summary`) (@garigariganzy) + +**改善:** + +- カラー出力はデフォルトで有効になって、コマンドプロンプトとPowerShellプロンプトに対応している。 (@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 +- `rules`フォルダが存在するが、レポジトリがダウンロードされていない場合は、ルール更新が失敗していたが、修正した。(#516) (@hitenkoku) +- 1.2.1バイナリで表示する誤ったバージョン番号の修正。 + +## v1.2.1 [2022/04/20] Black Hat Asia Arsenal 2022 RC2 + +**新機能:** +- `./config/channel_abbreviations`の設定ファイルにより、`Channel`列も出力されるようになった。 (@hitenkoku) +- ルールとルールの設定ファイルは強制的に上書きされる。 (@hitenkoku) + +**バグ修正:** +- ルールがnoisyもしくはexcludedと設定された場合は、`--level-tuning`オプションで`level`が更新されなかったが、修正した。 (@hitenkoku) + +## v1.2.0 [2022/04/15] Black Hat Asia Arsenal 2022 RC1 **新機能:** diff --git a/CHANGELOG.md b/CHANGELOG.md index 6baa48c0..604e057e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,17 +1,35 @@ # Changes -## v1.2.1 [2022/04/20] Black Hat Asia Arsenal 2022 Preview Release +## v1.2.2 [2022/05/17] **New Features:** + +- Added a logon summary feature. (`-L` / `--logon-summary`) (@garigariganzy) + +**Enhancements:** + +- Colored output is now on by default and supports Command and Powershell prompts. (@hitenkoku) + +**Bug Fixes:** + +- Fixed a bug in the update feature when the rules repository does not exist but the rules folder exists. (#516) (@hitenkoku) +- Fixed wrong version number in the 1.2.1 binary. + +## v1.2.1 [2022/04/20] Black Hat Asia Arsenal 2022 RC2 + +**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 +## v1.2.0 [2022/04/15] Black Hat Asia Arsenal 2022 RC1 **New Features:** + - Specify config directory (`-C / --config`): When specifying a different rules directory, the rules config directory will still be the default `rules/config`, so this option is useful when you want to test rules and their config files in a different directory. (@hitenkoku) - `|equalsfield` aggregator: In order to write rules that compare if two fields are equal or not. (@hach1yon) - Pivot keyword list generator feature (`-p / --pivot-keywords-list`): Will generate a list of keywords to grep for to quickly identify compromised machines, suspicious usernames, files, etc... (@kazuminn) diff --git a/Cargo.lock b/Cargo.lock index e04349ee..f32487b1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -48,9 +48,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.56" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27" +checksum = "08f9b8508dccb7687a1d6c4ce66b2b0ecef467c94667de27d8d7fe1f8d2a9cdc" [[package]] name = "arrayref" @@ -107,9 +107,9 @@ dependencies = [ [[package]] name = "base-x" -version = "0.2.8" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4521f3e3d031370679b3b140beb36dfe4801b09ac77e30c61941f97df3ef28b" +checksum = "dc19a4937b4fbd3fe3379793130e42060d10627a360f2127802b10b87e7baf74" [[package]] name = "base64" @@ -120,12 +120,6 @@ dependencies = [ "byteorder", ] -[[package]] -name = "base64" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" - [[package]] name = "bitflags" version = "1.3.2" @@ -198,9 +192,9 @@ checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" [[package]] name = "camino" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f3132262930b0522068049f5870a856ab8affc80c70d08b6ecb785771a6fc23" +checksum = "07fd178c5af4d59e83498ef15cf3f154e1a6f9d091270cb86283c65ef44e9ef0" dependencies = [ "serde", ] @@ -222,7 +216,7 @@ checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa" dependencies = [ "camino", "cargo-platform", - "semver 1.0.7", + "semver 1.0.9", "serde", "serde_json", ] @@ -286,17 +280,6 @@ dependencies = [ "bitflags", ] -[[package]] -name = "colored" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" -dependencies = [ - "atty", - "lazy_static", - "winapi 0.3.9", -] - [[package]] name = "console" version = "0.14.1" @@ -884,28 +867,27 @@ checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" [[package]] name = "hashbrown" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c21d40587b92fa6a6c6e3c1bdbf87d75511db5672f9c93175574b3a00df1758" +checksum = "db0d4cf898abf0081f964436dc980e96670a0f36863e4b83aaacdb65c9d7ccc3" dependencies = [ "ahash", ] [[package]] name = "hayabusa" -version = "1.2.1" +version = "1.2.2" dependencies = [ - "base64 0.13.0", + "base64", "chrono", "clap", - "colored", "csv", "dotenv", "downcast-rs", "evtx", "flate2", "git2", - "hashbrown 0.12.0", + "hashbrown 0.12.1", "hex 0.4.3", "hhmmss", "is_elevated", @@ -922,7 +904,8 @@ dependencies = [ "serde_json", "slack-hook", "static_vcruntime", - "tokio 1.17.0", + "termcolor", + "tokio 1.18.2", "yaml-rust", ] @@ -982,9 +965,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.7.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6330e8a36bd8c859f3fa6d9382911fbb7147ec39807f63b923933a247240b9ba" +checksum = "496ce29bb5a52785b44e0f7ca2847ae0bb839c9bd28f69acac9b99d461c0c04c" [[package]] name = "humantime" @@ -1072,12 +1055,9 @@ dependencies = [ [[package]] name = "indoc" -version = "1.0.4" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7906a9fababaeacb774f72410e497a1d18de916322e33797bb2cd29baa23c9e" -dependencies = [ - "unindent", -] +checksum = "05a0bd019339e5d968b37855180087b7b9d512c5046fbd244cf8c95687927d6e" [[package]] name = "instant" @@ -1166,9 +1146,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.124" +version = "0.2.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21a41fed9d98f27ab1c6d161da622a4fa35e8a54a8adc24bbf3ddd0ef70b0e50" +checksum = "5916d2ae698f6de9bfb891ad7a8d65c09d232dc58cc4ac433c7da3b2fd84bc2b" [[package]] name = "libgit2-sys" @@ -1200,9 +1180,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.5" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f35facd4a5673cb5a48822be2be1d4236c1c99cb4113cab7061ac720d5bf859" +checksum = "92e7e15d7610cce1d9752e137625f14e61a28cd45929b6e12e47b50fe154ee2e" dependencies = [ "cc", "libc", @@ -1237,9 +1217,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.16" +version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ "cfg-if 1.0.0", ] @@ -1258,9 +1238,9 @@ checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" [[package]] name = "memchr" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "memoffset" @@ -1318,7 +1298,7 @@ dependencies = [ "kernel32-sys", "libc", "log", - "miow 0.2.2", + "miow", "net2", "slab", "winapi 0.2.8", @@ -1326,16 +1306,14 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52da4364ffb0e4fe33a9841a98a3f3014fb964045ce4f7a45a398243c8d6b0c9" +checksum = "713d550d9b44d89174e066b7a6217ae06234c10cb47819a88290d2b353c31799" dependencies = [ "libc", "log", - "miow 0.3.7", - "ntapi", "wasi 0.11.0+wasi-snapshot-preview1", - "winapi 0.3.9", + "windows-sys", ] [[package]] @@ -1350,15 +1328,6 @@ dependencies = [ "ws2_32-sys", ] -[[package]] -name = "miow" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" -dependencies = [ - "winapi 0.3.9", -] - [[package]] name = "native-tls" version = "0.2.10" @@ -1388,15 +1357,6 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "ntapi" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f" -dependencies = [ - "winapi 0.3.9", -] - [[package]] name = "num-derive" version = "0.3.3" @@ -1410,9 +1370,9 @@ dependencies = [ [[package]] name = "num-integer" -version = "0.1.44" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" dependencies = [ "autocfg 1.1.0", "num-traits", @@ -1420,9 +1380,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" dependencies = [ "autocfg 1.1.0", ] @@ -1439,9 +1399,9 @@ dependencies = [ [[package]] name = "object" -version = "0.28.3" +version = "0.28.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40bec70ba014595f99f7aa110b84331ffe1ee9aece7fe6f387cc7e3ecda4d456" +checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424" dependencies = [ "memchr", ] @@ -1454,18 +1414,30 @@ checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" [[package]] name = "openssl" -version = "0.10.38" +version = "0.10.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c7ae222234c30df141154f159066c5093ff73b63204dcda7121eb082fc56a95" +checksum = "fb81a6430ac911acb25fe5ac8f1d2af1b4ea8a4fdfda0f1ee4292af2e2d8eb0e" dependencies = [ "bitflags", "cfg-if 1.0.0", "foreign-types", "libc", "once_cell", + "openssl-macros", "openssl-sys", ] +[[package]] +name = "openssl-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "openssl-probe" version = "0.1.5" @@ -1483,9 +1455,9 @@ dependencies = [ [[package]] name = "openssl-sys" -version = "0.9.72" +version = "0.9.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e46109c383602735fa0a2e48dd2b7c892b048e1bf69e5c3b1d804b7d9c203cb" +checksum = "9d5fd19fb3e0a8191c1e34935718976a3e70c112ab9a24af6d7cadccd9d90bc0" dependencies = [ "autocfg 1.1.0", "cc", @@ -1513,7 +1485,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58" dependencies = [ "lock_api 0.4.7", - "parking_lot_core 0.9.2", + "parking_lot_core 0.9.3", ] [[package]] @@ -1533,9 +1505,9 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.2" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "995f667a6c822200b0433ac218e05582f0e2efa1b922a3fd2fbaadc5f87bab37" +checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" dependencies = [ "cfg-if 1.0.0", "libc", @@ -1570,9 +1542,9 @@ checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" [[package]] name = "pin-project-lite" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" [[package]] name = "pkg-config" @@ -1602,9 +1574,9 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" [[package]] name = "proc-macro2" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1" +checksum = "9027b48e9d4c9175fa2218adf3557f91c1137021739951d4932f5f8268ac48aa" dependencies = [ "unicode-xid", ] @@ -1775,9 +1747,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.9.2" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f51245e1e62e1f1629cbfec37b5793bbabcaeb90f30e94d2ba03564687353e4" +checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f" dependencies = [ "crossbeam-channel", "crossbeam-deque 0.8.1", @@ -1858,7 +1830,7 @@ version = "0.9.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f88643aea3c1343c804950d7bf983bd2067f5ab59db6d613a08e05572f2714ab" dependencies = [ - "base64 0.10.1", + "base64", "bytes 0.4.12", "cookie", "cookie_store", @@ -1998,9 +1970,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d65bd28f48be7196d222d95b9243287f48d27aca604e08497513019ff0502cc4" +checksum = "8cb243bdfdb5936c8dc3c45762a19d12ab4550cdc753bc247637d4ec35a040fd" dependencies = [ "serde", ] @@ -2013,18 +1985,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.136" +version = "1.0.137" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" +checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.136" +version = "1.0.137" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" +checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" dependencies = [ "proc-macro2", "quote", @@ -2033,9 +2005,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.79" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95" +checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" dependencies = [ "itoa 1.0.1", "ryu", @@ -2232,9 +2204,9 @@ checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" [[package]] name = "syn" -version = "1.0.91" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d" +checksum = "a07e33e919ebcd69113d5be0e4d70c5707004ff45188910106854f38b960df4a" dependencies = [ "proc-macro2", "quote", @@ -2308,18 +2280,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.30" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" +checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.30" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" +checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" dependencies = [ "proc-macro2", "quote", @@ -2377,9 +2349,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.5.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" dependencies = [ "tinyvec_macros", ] @@ -2411,14 +2383,14 @@ dependencies = [ [[package]] name = "tokio" -version = "1.17.0" +version = "1.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2af73ac49756f3f7c01172e34a23e5d0216f6c32333757c2c61feb2bbff5a5ee" +checksum = "4903bf0427cf68dddd5aa6a93220756f8be0c34fcfa9f5e6191e103e15a31395" dependencies = [ "bytes 1.1.0", "libc", "memchr", - "mio 0.8.2", + "mio 0.8.3", "num_cpus", "once_cell", "parking_lot 0.12.0", @@ -2580,9 +2552,9 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" +checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" [[package]] name = "unicode-normalization" @@ -2601,15 +2573,9 @@ checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" [[package]] name = "unicode-xid" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" - -[[package]] -name = "unindent" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "514672a55d7380da379785a4d70ca8386c8883ff7eaae877be4d2081cebe73d8" +checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" [[package]] name = "url" @@ -2810,9 +2776,9 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-sys" -version = "0.34.0" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5acdd78cb4ba54c0045ac14f62d8f94a03d10047904ae2a40afa1e99d8f70825" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" dependencies = [ "windows_aarch64_msvc", "windows_i686_gnu", @@ -2823,33 +2789,33 @@ dependencies = [ [[package]] name = "windows_aarch64_msvc" -version = "0.34.0" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17cffbe740121affb56fad0fc0e421804adf0ae00891205213b5cecd30db881d" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" [[package]] name = "windows_i686_gnu" -version = "0.34.0" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2564fde759adb79129d9b4f54be42b32c89970c18ebf93124ca8870a498688ed" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" [[package]] name = "windows_i686_msvc" -version = "0.34.0" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cd9d32ba70453522332c14d38814bceeb747d80b3958676007acadd7e166956" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" [[package]] name = "windows_x86_64_gnu" -version = "0.34.0" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfce6deae227ee8d356d19effc141a509cc503dfd1f850622ec4b0f84428e1f4" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" [[package]] name = "windows_x86_64_msvc" -version = "0.34.0" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d19538ccc21819d01deaf88d6a17eae6596a12e9aafdbb97916fb49896d89de9" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" [[package]] name = "winreg" @@ -2899,6 +2865,6 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.5.4" +version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb5728b8afd3f280a869ce1d4c554ffaed35f45c231fc41bfbd0381bef50317" +checksum = "94693807d016b2f2d2e14420eb3bfcca689311ff775dcf113d74ea624b7cdf07" diff --git a/Cargo.toml b/Cargo.toml index 1eff3321..34c0d79b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "hayabusa" -version = "1.2.1" +version = "1.2.2" authors = ["Yamato Security @SecurityYamato"] edition = "2021" @@ -29,9 +29,9 @@ dotenv = "0.15.*" hhmmss = "*" pbr = "*" hashbrown = "0.12.*" -colored = "2.*" hex = "0.4.*" git2="0.13" +termcolor="*" prettytable-rs = "0.8" [target.'cfg(windows)'.dependencies] diff --git a/README-Japanese.md b/README-Japanese.md index 3293a281..a8b463ac 100644 --- a/README-Japanese.md +++ b/README-Japanese.md @@ -148,12 +148,12 @@ CSVのタイムラインをElastic Stackにインポートする方法は[こち * ルールレベルのチューニング。 * イベントログから不審なユーザやファイルを素早く特定するのに有用な、ピボットキーワードの一覧作成。 * 詳細な調査のために全フィールド情報の出力。 +* 成功と失敗したユーザログオンの要約。 # 予定されている機能 * すべてのエンドポイントでの企業全体のスレットハンティング。 * MITRE ATT&CKのヒートマップ生成機能。 -* ユーザーログオンと失敗したログオンのサマリー。 # ダウンロード @@ -312,7 +312,6 @@ USAGE: -f --filepath=[FILEPATH] '1つの.evtxファイルのパス。' -F --full-data '全てのフィールド情報を出力する。' -r --rules=[RULEFILE/RULEDIRECTORY] 'ルールファイルまたはルールファイルを持つディレクトリ。(デフォルト: ./rules)' - -c --color 'カラーで出力する。 (ターミナルはTrue Colorに対応する必要がある。)' -C --config=[RULECONFIGDIRECTORY] 'ルールフォルダのコンフィグディレクトリ(デフォルト: ./rules/config)' -o --output=[CSV_TIMELINE] 'タイムラインをCSV形式で保存する。(例: results.csv)' -v --verbose '詳細な情報を出力する。' @@ -326,6 +325,7 @@ USAGE: --rfc-2822 'RFC 2822形式で日付と時刻を出力する。(例: Mon, 07 Aug 2006 12:34:56 -0600)' --rfc-3339 'RFC 3339形式で日付と時刻を出力する。 (例: 2006-08-07T12:34:56.485214 -06:00)' -U --utc 'UTC形式で日付と時刻を出力する。(デフォルト: 現地時間)' + --no-color 'カラー出力を無効にする。' -t --thread-number=[NUMBER] 'スレッド数。(デフォルト: パフォーマンスに最適な数値)' -s --statistics 'イベント ID の統計情報を表示する。' -L --logon-summary 'ユーザのログオン情報の要約を出力' @@ -455,7 +455,7 @@ Processes.Image ## ログオン情報の要約 -`-L` または `--logon-summary` オプションを使うことでログオン情報の要約(ユーザ名、ログイン成功数、ログイン失敗数)の画面出力ができます。`-d` オプションを合わせて使うことでevtxファイルごとのログイン情報の要約を出力できます。 +`-L` または `--logon-summary` オプションを使うことでログオン情報の要約(ユーザ名、ログイン成功数、ログイン失敗数)の画面出力ができます。単体のevtxファイルを解析したい場合は`-f`オプションを利用してください。複数のevtxファイルを対象としたい場合は `-d` オプションを合わせて使うことでevtxファイルごとのログイン情報の要約を出力できます。 # サンプルevtxファイルでHayabusaをテストする @@ -548,11 +548,10 @@ CSVファイルとして保存する場合、以下の列が追加されます: ## 標準出力へのカラー設定 -`-c`または`--color`を指定することで、Hayabusaの結果は`level`毎に文字色を変えることができます。 +Hayabusaの結果は`level`毎に文字色が変わります。 `./config/level_color.txt`の値を変更することで文字色を変えることができます。 形式は`level名,(6桁のRGBのカラーhex)`です。 -注意: True Colorに対応しているターミナルが必要です。 -例: [Windows Terminal](https://docs.microsoft.com/en-us/windows/terminal/install) またはmacOSの[iTerm2](https://iterm2.com/)。 +カラー出力をしないようにしたい場合は`--no-color`オプションをご利用ください。 # Hayabusaルール diff --git a/README.md b/README.md index 088259d5..2a655244 100644 --- a/README.md +++ b/README.md @@ -145,12 +145,12 @@ You can learn how to import CSV files into Elastic Stack [here](doc/ElasticStack * Rule level tuning. * Create a list of unique pivot keywords to quickly identify abnormal users, hostnames, processes, etc... as well as correlate events. * Output all fields for more thorough investigations. +* Successful and failed user logon summary. # Planned Features * Enterprise-wide hunting on all endpoints. * MITRE ATT&CK heatmap generation. -* User logon and failed logon summary. # Downloads @@ -303,8 +303,7 @@ USAGE: -d --directory=[DIRECTORY] 'Directory of multiple .evtx files.' -f --filepath=[FILEPATH] 'File path to one .evtx file.' -F --full-data 'Print all field information.' - -r --rules=[RULEFILE/RULEDIRECTORY] 'Rule file or directory. (Default: ./rules)' - -c --color 'Output with color. (Terminal needs to support True Color.)' + -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)' -v --verbose 'Output verbose information.' @@ -318,12 +317,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' -t --thread-number=[NUMBER] 'Thread number. (Default: Optimal number for performance.)' -s --statistics 'Prints statistics of event IDs.' -L --logon-summary 'User logon and failed logon summary' -q --quiet 'Quiet mode. Do not display the launch banner.' -Q --quiet-errors 'Quiet errors mode. Do not save error logs.' - --level-tuning 'Tune the rule level [default: ./rules/config/level_tuning.txt]' + --level-tuning '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.' ``` @@ -448,7 +448,7 @@ The format is `KeywordName.FieldName`. For example, when creating the list of `U ## Logon Summary Generator You can use the `-L` or `--logon-summary` option to output logon information summary(logon username, logon success and logon failed count). -You can get logon information each evtx file with `-d` option. +You can display the logon information for one evtx file with `-f` or multiple evtx files with the `-d` option. # Testing Hayabusa on Sample Evtx Files @@ -541,10 +541,9 @@ It will display in real time the number and percent of evtx files that it has fi ## Color Output -You can output the alerts in color based on the alert `level` by specifying `-c` or `--color`. +The alerts will be outputted in color based on the alert `level`. You can change the default colors in the config file at `./config/level_color.txt` in the format of `level,(RGB 6-digit ColorHex)`. -Note: Color can only be displayed in terminals that support [True Color](https://en.wikipedia.org/wiki/Color_depth#True_color_(24-bit)). -Example: [Windows Terminal](https://docs.microsoft.com/en-us/windows/terminal/install) or [iTerm2](https://iterm2.com/) for macOS. +If you want to disable color output, you can use `--no-color` option. # Hayabusa Rules diff --git a/config/level_color.txt b/config/level_color.txt index b01047b6..2a27bd60 100644 --- a/config/level_color.txt +++ b/config/level_color.txt @@ -2,5 +2,4 @@ level,colorcode critical,ff0000 high,ffff00 medium,00ffff -low,00ff00 - +low,00ff00 \ No newline at end of file diff --git a/contributors.txt b/contributors.txt index 1aae846b..53b594ea 100644 --- a/contributors.txt +++ b/contributors.txt @@ -1,7 +1,6 @@ Hayabusa was possible thanks to the following people (in alphabetical order): Akira Nishikawa (@nishikawaakira): Previous lead developer, core hayabusa rule support, etc... -DustInDark (@hitenkoku): Core developer (too many contributions to list up) Garigariganzy (@garigariganzy31): Developer, event ID statistics implementation, etc... ItiB (@itiB_S144) : Core developer, sigmac hayabusa backend, rule creation, etc... James Takai / hachiyone(@hach1yon): Current lead developer, tokio multi-threading, sigma aggregation logic, sigmac backend, rule creation, sigma count implementation etc… diff --git a/src/afterfact.rs b/src/afterfact.rs index 036a0cd4..c59712bc 100644 --- a/src/afterfact.rs +++ b/src/afterfact.rs @@ -3,9 +3,9 @@ use crate::detections::print; use crate::detections::print::AlertMessage; use crate::detections::utils; use chrono::{DateTime, Local, TimeZone, Utc}; -use colored::*; use csv::QuoteStyle; use hashbrown::HashMap; +use lazy_static::lazy_static; use serde::Serialize; use std::error::Error; use std::fs::File; @@ -13,6 +13,7 @@ use std::io; use std::io::BufWriter; use std::io::Write; use std::process; +use termcolor::{BufferWriter, Color, ColorChoice, ColorSpec, WriteColor}; #[derive(Debug, Serialize)] #[serde(rename_all = "PascalCase")] @@ -45,12 +46,17 @@ pub struct DisplayFormat<'a> { pub record_information: Option<&'a str>, } +lazy_static! { + pub static ref OUTPUT_COLOR: HashMap = set_output_color(); +} + /// level_color.txtファイルを読み込み対応する文字色のマッピングを返却する関数 -pub fn set_output_color() -> Option>> { - if !configs::CONFIG.read().unwrap().args.is_present("color") { - return None; - } +pub fn set_output_color() -> HashMap { let read_result = utils::read_csv("config/level_color.txt"); + let mut color_map: HashMap = HashMap::new(); + if configs::CONFIG.read().unwrap().args.is_present("no-color") { + return color_map; + } if read_result.is_err() { // color情報がない場合は通常の白色の出力が出てくるのみで動作への影響を与えない為warnとして処理する AlertMessage::warn( @@ -58,9 +64,8 @@ pub fn set_output_color() -> Option>> { read_result.as_ref().unwrap_err(), ) .ok(); - return None; + return color_map; } - let mut color_map: HashMap> = HashMap::new(); read_result.unwrap().into_iter().for_each(|line| { if line.len() != 2 { return; @@ -80,9 +85,17 @@ pub fn set_output_color() -> Option>> { if level.is_empty() || color_code.len() < 3 { return; } - color_map.insert(level.to_string(), color_code); + color_map.insert(level.to_lowercase(), Color::Rgb(color_code[0], color_code[1], color_code[2])); }); - Some(color_map) + color_map +} + +fn _get_output_color(color_map: &HashMap, level: &str) -> Option { + let mut color = None; + if let Some(c) = color_map.get(&level.to_lowercase()) { + color = Some(c.to_owned()); + } + color } pub fn after_fact() { @@ -98,7 +111,7 @@ pub fn after_fact() { let mut displayflag = false; let mut target: Box = if let Some(csv_path) = configs::CONFIG.read().unwrap().args.value_of("output") { - // ファイル出力する場合 + // output to file match File::create(csv_path) { Ok(file) => Box::new(BufWriter::new(file)), Err(err) => { @@ -112,7 +125,7 @@ pub fn after_fact() { } } else { displayflag = true; - // 標準出力に出力する場合 + // stdoutput (termcolor crate color output is not csv writer) Box::new(BufWriter::new(io::stdout())) }; let color_map = set_output_color(); @@ -124,24 +137,21 @@ pub fn after_fact() { fn emit_csv( writer: &mut W, displayflag: bool, - color_map: Option>>, + color_map: HashMap, ) -> io::Result<()> { - let mut wtr = if displayflag { - csv::WriterBuilder::new() - .double_quote(false) - .quote_style(QuoteStyle::Never) - .delimiter(b'|') - .from_writer(writer) - } else { - csv::WriterBuilder::new().from_writer(writer) - }; + let disp_wtr = BufferWriter::stdout(ColorChoice::Always); + let mut disp_wtr_buf = disp_wtr.buffer(); + + let mut wtr = csv::WriterBuilder::new().from_writer(writer); let messages = print::MESSAGES.lock().unwrap(); - // levelの区分が"Critical","High","Medium","Low","Informational","Undefined"の6つであるため + // level is devided by "Critical","High","Medium","Low","Informational","Undefined". let mut total_detect_counts_by_level: Vec = vec![0; 6]; let mut unique_detect_counts_by_level: Vec = vec![0; 6]; let mut detected_rule_files: Vec = Vec::new(); + println!(); + let mut plus_header = true; for (time, detect_infos) in messages.iter() { for detect_info in detect_infos { let mut level = detect_info.level.to_string(); @@ -149,15 +159,10 @@ fn emit_csv( level = "info".to_string(); } if displayflag { - let colors = color_map - .as_ref() - .map(|cl_mp| _get_output_color(cl_mp, &detect_info.level)); - let colors = colors.as_ref(); - let recinfo = detect_info .record_information .as_ref() - .map(|recinfo| _format_cell(recinfo, ColPos::Last, colors)); + .map(|recinfo| _format_cellpos(recinfo, ColPos::Last)); let details = detect_info .detail .chars() @@ -165,18 +170,30 @@ fn emit_csv( .collect::(); let dispformat = DisplayFormat { - timestamp: &_format_cell(&format_time(time), ColPos::First, colors), - 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), + timestamp: &_format_cellpos(&format_time(time), ColPos::First), + level: &_format_cellpos(&level, ColPos::Other), + computer: &_format_cellpos(&detect_info.computername, ColPos::Other), + event_i_d: &_format_cellpos(&detect_info.eventid, ColPos::Other), + channel: &_format_cellpos(&detect_info.channel, ColPos::Other), + rule_title: &_format_cellpos(&detect_info.alert, ColPos::Other), + details: &_format_cellpos(&details, ColPos::Other), record_information: recinfo.as_deref(), }; - wtr.serialize(dispformat)?; + + disp_wtr_buf + .set_color( + ColorSpec::new().set_fg(_get_output_color(&color_map, &detect_info.level)), + ) + .ok(); + write!( + disp_wtr_buf, + "{}", + _get_serialized_disp_output(dispformat, plus_header) + ) + .ok(); + plus_header = false; } else { - // csv出力時フォーマット + // csv output format wtr.serialize(CsvFormat { timestamp: &format_time(time), level: &level, @@ -201,9 +218,11 @@ fn emit_csv( total_detect_counts_by_level[level_suffix] += 1; } } - println!(); - - wtr.flush()?; + if displayflag { + disp_wtr.print(&disp_wtr_buf)?; + } else { + wtr.flush()?; + } println!(); _print_unique_results( total_detect_counts_by_level, @@ -220,13 +239,31 @@ fn emit_csv( Ok(()) } +/// columnt position. in cell +/// First: | | +/// Last: | | +/// Othre: | | enum ColPos { - First, // 先頭 - Last, // 最後 - Other, // それ以外 + First, + Last, + Other, } -fn _format_cellpos(column: ColPos, colval: &str) -> String { +fn _get_serialized_disp_output(dispformat: DisplayFormat, plus_header: bool) -> String { + let mut disp_serializer = csv::WriterBuilder::new() + .double_quote(false) + .quote_style(QuoteStyle::Never) + .delimiter(b'|') + .has_headers(plus_header) + .from_writer(vec![]); + + disp_serializer.serialize(dispformat).ok(); + + String::from_utf8(disp_serializer.into_inner().unwrap_or_default()).unwrap_or_default() +} + +/// return str position in output file +fn _format_cellpos(colval: &str, column: ColPos) -> String { return match column { ColPos::First => format!("{} ", colval), ColPos::Last => format!(" {}", colval), @@ -234,23 +271,17 @@ fn _format_cellpos(column: ColPos, colval: &str) -> String { }; } -fn _format_cell(word: &str, column: ColPos, output_color: Option<&Vec>) -> String { - if let Some(color) = output_color { - let colval = format!("{}", word.truecolor(color[0], color[1], color[2])); - _format_cellpos(column, &colval) - } else { - _format_cellpos(column, word) - } -} - -/// 与えられたユニークな検知数と全体の検知数の情報(レベル別と総計)を元に結果文を標準出力に表示する関数 +/// output info which unique detection count and all detection count information(devided by level and total) to stdout. fn _print_unique_results( mut counts_by_level: Vec, head_word: String, tail_word: String, - color_map: &Option>>, + color_map: &HashMap, ) { - let mut wtr = BufWriter::new(io::stdout()); + let buf_wtr = BufferWriter::stdout(ColorChoice::Always); + let mut wtr = buf_wtr.buffer(); + wtr.set_color(ColorSpec::new().set_fg(None)).ok(); + let levels = Vec::from([ "critical", "high", @@ -260,10 +291,10 @@ fn _print_unique_results( "undefined", ]); - // configsの登録順番と表示をさせたいlevelの順番が逆であるため + // the order in which are registered and the order of levels to be displayed are reversed counts_by_level.reverse(); - // 全体の集計(levelの記載がないためformatの第二引数は空の文字列) + // output total results writeln!( wtr, "{} {}: {}", @@ -272,33 +303,18 @@ fn _print_unique_results( counts_by_level.iter().sum::() ) .ok(); + for (i, level_name) in levels.iter().enumerate() { let output_raw_str = format!( "{} {} {}: {}", head_word, level_name, tail_word, counts_by_level[i] ); - let output_str = if color_map.is_none() { - output_raw_str - } else { - let output_color = _get_output_color(color_map.as_ref().unwrap(), level_name); - output_raw_str - .truecolor(output_color[0], output_color[1], output_color[2]) - .to_string() - }; - writeln!(wtr, "{}", output_str).ok(); - } - wtr.flush().ok(); -} -/// levelに対応したtruecolorの値の配列を返す関数 -fn _get_output_color(color_map: &HashMap>, level: &str) -> Vec { - // カラーをつけない場合は255,255,255で出力する - let mut output_color: Vec = vec![255, 255, 255]; - let target_color = color_map.get(level); - if let Some(color) = target_color { - output_color = color.to_vec(); + wtr.set_color(ColorSpec::new().set_fg(_get_output_color(color_map, level_name))) + .ok(); + writeln!(wtr, "{}", output_raw_str).ok(); } - output_color + buf_wtr.print(&wtr).ok(); } fn format_time(time: &DateTime) -> String { @@ -309,6 +325,7 @@ fn format_time(time: &DateTime) -> String { } } +/// return rfc time format string by option fn format_rfc(time: &DateTime) -> String where Tz::Offset: std::fmt::Display, @@ -324,11 +341,15 @@ where #[cfg(test)] mod tests { + use crate::afterfact::DisplayFormat; + use crate::afterfact::_get_serialized_disp_output; use crate::afterfact::emit_csv; + use crate::afterfact::format_time; use crate::detections::print; use crate::detections::print::DetectInfo; use crate::detections::print::CH_CONFIG; use chrono::{Local, TimeZone, Utc}; + use hashbrown::HashMap; use serde_json::Value; use std::fs::File; use std::fs::{read_to_string, remove_file}; @@ -423,7 +444,7 @@ mod tests { + test_filepath + "\n"; let mut file: Box = Box::new(File::create("./test_emit_csv.csv").unwrap()); - assert!(emit_csv(&mut file, false, None).is_ok()); + assert!(emit_csv(&mut file, false, HashMap::default()).is_ok()); match read_to_string("./test_emit_csv.csv") { Err(_) => panic!("Failed to open file."), Ok(s) => { @@ -435,119 +456,72 @@ mod tests { } fn check_emit_csv_display() { - 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 test_channel = "Sysmon"; let output = "displaytest"; - let test_attack = "execution/txxxx.zzz"; - { - let mut messages = print::MESSAGES.lock().unwrap(); - messages.clear(); - let val = r##" - { - "Event": { - "EventData": { - "CommandRLine": "hoge" - }, - "System": { - "TimeCreated_attributes": { - "SystemTime": "1996-02-27T01:05:01Z" - } - } - } - } - "##; - let event: Value = serde_json::from_str(val).unwrap(); - messages.insert( - &event, - output.to_string(), - DetectInfo { - 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(), - record_information: Option::Some(String::default()), - }, - ); - messages.debug(); - } - let expect_time = Utc + let test_recinfo = "testinfo"; + + let test_timestamp = Utc .datetime_from_str("1996-02-27T01:05:01Z", "%Y-%m-%dT%H:%M:%SZ") .unwrap(); - let expect_tz = expect_time.with_timezone(&Local); let expect_header = "Timestamp|Computer|Channel|EventID|Level|RuleTitle|Details|RecordInformation\n"; - let expect_colored = expect_header.to_string() - + &get_white_color_string( - &expect_tz - .clone() - .format("%Y-%m-%d %H:%M:%S%.3f %:z") - .to_string(), - ) - + " | " - + &get_white_color_string(test_computername) - + " | " - + &get_white_color_string(expect_channel) - + " | " - + &get_white_color_string(test_eventid) - + " | " - + &get_white_color_string(test_level) - + " | " - + &get_white_color_string(test_title) - + " | " - + &get_white_color_string(output) - + " | " - + &get_white_color_string("") - + "\n"; - let expect_nocoloed = expect_header.to_string() - + &expect_tz - .clone() - .format("%Y-%m-%d %H:%M:%S%.3f %:z") - .to_string() - + " | " + let expect_tz = test_timestamp.with_timezone(&Local); + + let expect_no_header = expect_tz + .clone() + .format("%Y-%m-%d %H:%M:%S%.3f %:z") + .to_string() + + "|" + test_computername - + " | " - + expect_channel - + " | " + + "|" + + test_channel + + "|" + test_eventid - + " | " + + "|" + test_level - + " | " + + "|" + test_title - + " | " + + "|" + output - + " | " - + "" + + "|" + + test_recinfo + "\n"; - - let mut file: Box = - Box::new(File::create("./test_emit_csv_display.txt").unwrap()); - assert!(emit_csv(&mut file, true, None).is_ok()); - match read_to_string("./test_emit_csv_display.txt") { - Err(_) => panic!("Failed to open file."), - Ok(s) => { - assert!(s == expect_colored || s == expect_nocoloed); - } - }; - assert!(remove_file("./test_emit_csv_display.txt").is_ok()); - } - - fn get_white_color_string(target: &str) -> String { - let white_color_header = "\u{1b}[38;2;255;255;255m"; - let white_color_footer = "\u{1b}[0m"; - - white_color_header.to_owned() + target + white_color_footer + let expect_with_header = expect_header.to_string() + &expect_no_header; + assert_eq!( + _get_serialized_disp_output( + DisplayFormat { + timestamp: &format_time(&test_timestamp), + level: test_level, + computer: test_computername, + event_i_d: test_eventid, + channel: test_channel, + rule_title: test_title, + details: output, + record_information: Some(test_recinfo), + }, + true + ), + expect_with_header + ); + assert_eq!( + _get_serialized_disp_output( + DisplayFormat { + timestamp: &format_time(&test_timestamp), + level: test_level, + computer: test_computername, + event_i_d: test_eventid, + channel: test_channel, + rule_title: test_title, + details: output, + record_information: Some(test_recinfo), + }, + false + ), + expect_no_header + ); } } diff --git a/src/detections/configs.rs b/src/detections/configs.rs index a6389005..34b07397 100644 --- a/src/detections/configs.rs +++ b/src/detections/configs.rs @@ -74,7 +74,6 @@ fn build_app<'a>() -> ArgMatches<'a> { -f --filepath=[FILEPATH] 'File path to one .evtx file.' -F --full-data 'Print all field information.' -r --rules=[RULEDIRECTORY/RULEFILE] 'Rule file or directory (default: ./rules)' - -c --color 'Output with color. (Terminal needs to support True Color.)' -C --config=[RULECONFIGDIRECTORY] 'Rule config folder. (Default: ./rules/config)' -o --output=[CSV_TIMELINE] 'Save the timeline in CSV format. (Example: results.csv)' -v --verbose 'Output verbose information.' @@ -88,6 +87,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' -t --thread-number=[NUMBER] 'Thread number. (Default: Optimal number for performance.)' -s --statistics 'Prints statistics of event IDs.' -L --logon-summary 'User logon and failed logon summary' @@ -97,7 +97,7 @@ fn build_app<'a>() -> ArgMatches<'a> { --contributors 'Prints the list of contributors.'"; App::new(&program) .about("Hayabusa: Aiming to be the world's greatest Windows event log analysis tool!") - .version("1.2.1") + .version("1.2.2") .author("Yamato Security (https://github.com/Yamato-Security/hayabusa) @SecurityYamato") .setting(AppSettings::VersionlessSubcommands) .arg(