Skip to content

Commit

Permalink
Feature/colorlog#239 (#365)
Browse files Browse the repository at this point in the history
* added color carete #239

* added hex library

* added color config file parser #239

* added color output feature #239

* changed fast hashmap library

* added color output description(Japanese) #239

* added color output description(English) #239

* fixed medium level typo

* removed white color font level #239

* added trim and loose colorcode condition #239

* fixed hex convert error panic #239

- output warn and go next iterator when happen hex convert panic

- added user input in hex convert warn output to use easily
  • Loading branch information
hitenkoku committed Jan 25, 2022
1 parent 15ee980 commit b12029d
Show file tree
Hide file tree
Showing 7 changed files with 147 additions and 18 deletions.
21 changes: 20 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ dotenv = "0.15.0"
hhmmss = "*"
pbr = "*"
hashbrown = "0.11.2"
colored = "2.0.0"
hex = "0.4.3"

[target.x86_64-pc-windows-gnu]
linker = "x86_64-w64-mingw32-gcc"
Expand Down
4 changes: 4 additions & 0 deletions README-English.md
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,10 @@ When saving to a CSV file an additional two fields will be added:
The progress bar will only work with multiple evtx files.
It will display in real time the number and percent of evtx files that it has analyzed.

## Color Output
Hayabusa output to the screen can change font color by `Level`.
Config file is `.\config\level_color.txt`. format is `level,(RGB 6digit ColorHex)`.

# Hayabusa rules
Hayabusa detection rules are written in a sigma-like YML format and are located in the `rules` folder. In the future, we plan to host the rules at [https://github.com/Yamato-Security/hayabusa-rules](https://github.com/Yamato-Security/hayabusa-rules) so please send any issues and pull requests for rules there instead of the main hayabusa repository.

Expand Down
5 changes: 5 additions & 0 deletions README-Japanese.md
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,11 @@ CSVファイルとして保存する場合、以下の2つのフィールドが
プログレス・バーは、複数のevtxファイルに対してのみ機能します。
解析したevtxファイルの数と割合をリアルタイムで表示します。

## 標準出力へのカラー設定
Hayabusaの結果はLevel毎に文字色を変えることができます。
`.\config\level_color.txt`の値を変更することで文字色を変えることができます。
形式は`level名,(6桁のRGBのカラーhex)`です。

# Hayabusa ルール
Hayabusa検知ルールはSigmaのようなYML形式で記述されています。`rules`ディレクトリに入っていますが、将来的には[https://github.com/Yamato-Security/hayabusa-rules](https://github.com/Yamato-Security/hayabusa-rules)のレポジトリで管理する予定なので、ルールのissueとpull requestはhayabusaのレポジトリではなく、ルールレポジトリへお願いします。

Expand Down
5 changes: 5 additions & 0 deletions config/level_color.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
level,colorcode
critical,ff0000
high,ffff00
medium,00ff00
low,00ffff
126 changes: 110 additions & 16 deletions src/afterfact.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
use crate::detections::configs;
use crate::detections::print;
use crate::detections::print::AlertMessage;
use crate::detections::utils;
use chrono::{DateTime, Local, TimeZone, Utc};
use colored::*;
use hashbrown::HashMap;
use serde::Serialize;
use std::error::Error;
use std::fs::File;
Expand All @@ -26,11 +29,48 @@ pub struct CsvFormat<'a> {
#[serde(rename_all = "PascalCase")]
pub struct DisplayFormat<'a> {
timestamp: &'a str,
computer: &'a str,
event_i_d: &'a str,
level: &'a str,
rule_title: &'a str,
details: &'a str,
pub computer: &'a str,
pub event_i_d: &'a str,
pub level: &'a str,
pub rule_title: &'a str,
pub details: &'a str,
}

/// level_color.txtファイルを読み込み対応する文字色のマッピングを返却する関数
pub fn set_output_color() -> Option<HashMap<String, Vec<u8>>> {
let read_result = utils::read_csv("config/level_color.txt");
if read_result.is_err() {
// color情報がない場合は通常の白色の出力が出てくるのみで動作への影響を与えない為warnとして処理する
AlertMessage::warn(
&mut BufWriter::new(std::io::stderr().lock()),
&read_result.as_ref().unwrap_err(),
)
.ok();
return None;
}
let mut color_map: HashMap<String, Vec<u8>> = HashMap::new();
read_result.unwrap().into_iter().for_each(|line| {
if line.len() != 2 {
return;
}
let empty = &"".to_string();
let level = line.get(0).unwrap_or(empty);
let convert_color_result = hex::decode(line.get(1).unwrap_or(empty).trim());
if convert_color_result.is_err() {
AlertMessage::warn(
&mut BufWriter::new(std::io::stderr().lock()),
&format!("Failed hex convert in level_color.txt. Color output is disabled. Input Line: {}",line.join(","))
)
.ok();
return;
}
let color_code = convert_color_result.unwrap();
if level.len() == 0 || color_code.len() < 3 {
return;
}
color_map.insert(level.to_string(), color_code);
});
return Some(color_map);
}

pub fn after_fact() {
Expand Down Expand Up @@ -63,13 +103,17 @@ pub fn after_fact() {
// 標準出力に出力する場合
Box::new(BufWriter::new(io::stdout()))
};

if let Err(err) = emit_csv(&mut target, displayflag) {
let color_map = set_output_color();
if let Err(err) = emit_csv(&mut target, displayflag, color_map) {
fn_emit_csv_err(Box::new(err));
}
}

fn emit_csv<W: std::io::Write>(writer: &mut W, displayflag: bool) -> io::Result<()> {
fn emit_csv<W: std::io::Write>(
writer: &mut W,
displayflag: bool,
color_map: Option<HashMap<String, Vec<u8>>>,
) -> io::Result<()> {
let mut wtr;
if displayflag {
wtr = csv::WriterBuilder::new()
Expand All @@ -88,13 +132,63 @@ fn emit_csv<W: std::io::Write>(writer: &mut W, displayflag: bool) -> io::Result<
for (time, detect_infos) in messages.iter() {
for detect_info in detect_infos {
if displayflag {
// カラーをつけない場合は255,255,255で出力する
let mut output_color: Vec<u8> = vec![255, 255, 255];
if color_map.is_some() {
let target_color = color_map.as_ref().unwrap().get(&detect_info.level);
if target_color.is_some() {
output_color = target_color.unwrap().to_vec();
}
}
wtr.serialize(DisplayFormat {
timestamp: &format!("{} ", &format_time(time)),
level: &format!(" {} ", &detect_info.level),
computer: &format!(" {} ", &detect_info.computername),
event_i_d: &format!(" {} ", &detect_info.eventid),
rule_title: &format!(" {} ", &detect_info.alert),
details: &format!(" {}", &detect_info.detail),
timestamp: &format!(
"{} ",
&format_time(time).truecolor(
output_color[0],
output_color[1],
output_color[2]
)
),
level: &format!(
" {} ",
&detect_info.level.truecolor(
output_color[0],
output_color[1],
output_color[2]
)
),
computer: &format!(
" {} ",
&detect_info.computername.truecolor(
output_color[0],
output_color[1],
output_color[2]
)
),
event_i_d: &format!(
" {} ",
&detect_info.eventid.truecolor(
output_color[0],
output_color[1],
output_color[2]
)
),
rule_title: &format!(
" {} ",
&detect_info.alert.truecolor(
output_color[0],
output_color[1],
output_color[2]
)
),
details: &format!(
" {}",
&detect_info.detail.truecolor(
output_color[0],
output_color[1],
output_color[2]
)
),
})?;
} else {
// csv出力時フォーマット
Expand Down Expand Up @@ -266,7 +360,7 @@ mod tests {
+ "\n";
let mut file: Box<dyn io::Write> =
Box::new(File::create("./test_emit_csv.csv".to_string()).unwrap());
assert!(emit_csv(&mut file, false).is_ok());
assert!(emit_csv(&mut file, false, None).is_ok());
match read_to_string("./test_emit_csv.csv") {
Err(_) => panic!("Failed to open file."),
Ok(s) => {
Expand Down Expand Up @@ -337,7 +431,7 @@ mod tests {
+ "\n";
let mut file: Box<dyn io::Write> =
Box::new(File::create("./test_emit_csv_display.txt".to_string()).unwrap());
assert!(emit_csv(&mut file, true).is_ok());
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) => {
Expand Down
2 changes: 1 addition & 1 deletion src/detections/print.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ use crate::detections::configs;
use crate::detections::utils;
use crate::detections::utils::get_serde_number_to_string;
use chrono::{DateTime, Local, TimeZone, Utc};
use hashbrown::HashMap;
use lazy_static::lazy_static;
use regex::Regex;
use serde_json::Value;
use std::collections::BTreeMap;
use std::collections::HashMap;
use std::env;
use std::fs::create_dir;
use std::fs::File;
Expand Down

0 comments on commit b12029d

Please sign in to comment.