Skip to content

Commit

Permalink
Merge pull request #1526 from Yamato-Security/1513-expand-list
Browse files Browse the repository at this point in the history
feat: `expand-list` command
  • Loading branch information
YamatoSecurity authored Dec 7, 2024
2 parents 14e479a + 4479010 commit 0c1511c
Show file tree
Hide file tree
Showing 7 changed files with 155 additions and 2 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ on:
inputs:
release_ver:
required: true
default: "2.x.x"
default: "3.x.x"
description: "Version of the release"
branch_or_tag:
required: true
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG-Japanese.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
**新機能:**

Base64文字列を抽出して、デコードする`extract-base64`コマンドを追加した。(#1512) (@fukusuket)
`expand`修飾子が入っているルールで使用されるプレースホルダー名を出力する`expand-list`コマンドを追加した。(#1513) (@fukuseket)

**バグ修正:**

Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
**New Features:**

New `extract-base64` command to extract and decode base64 strings from events. (#1512) (@fukusuket)
New `expand-list` command to output placeholder names used for rules with the `expand` modifier. (#1513) (@fukuseket)

**Bug Fixes:**

Expand Down
33 changes: 33 additions & 0 deletions src/detections/configs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ impl StoredStatic {
}
Some(Action::LogonSummary(opt)) => opt.detect_common_options.quiet_errors,
Some(Action::EidMetrics(opt)) => opt.detect_common_options.quiet_errors,
Some(Action::ExpandList(opt)) => opt.common_options.quiet,
Some(Action::ExtractBase64(opt)) => opt.detect_common_options.quiet_errors,
Some(Action::PivotKeywordsList(opt)) => opt.detect_common_options.quiet_errors,
Some(Action::Search(opt)) => opt.quiet_errors,
Expand All @@ -171,6 +172,7 @@ impl StoredStatic {
Some(Action::Search(opt)) => opt.common_options,
Some(Action::ComputerMetrics(opt)) => opt.common_options,
Some(Action::LogMetrics(opt)) => opt.common_options,
Some(Action::ExpandList(opt)) => opt.common_options,
None => CommonOptions {
no_color: false,
quiet: false,
Expand Down Expand Up @@ -949,6 +951,16 @@ pub enum Action {
/// Output event ID metrics (total number and percent of events, channel, ID, event name)
EidMetrics(EidMetricsOption),

#[clap(
author = "Yamato Security (https://github.com/Yamato-Security/hayabusa - @SecurityYamato)",
help_template = "\nHayabusa v3.0.0 - Dev Build\n{author-with-newline}\n{usage-heading}\n hayabusa.exe expand-list <INPUT> [OPTIONS]\n\n{all-args}",
term_width = 400,
display_order = 311,
disable_help_flag = true
)]
/// Extract expand placeholders from rule folder
ExpandList(ExpandListOption),

#[clap(
author = "Yamato Security (https://github.com/Yamato-Security/hayabusa - @SecurityYamato)",
help_template = "\nHayabusa v3.0.0 - Dev Build\n{author-with-newline}\n{usage-heading}\n hayabusa.exe extract-base64 <INPUT> [OPTIONS]\n\n{all-args}",
Expand Down Expand Up @@ -1046,6 +1058,7 @@ impl Action {
Action::ComputerMetrics(_) => 11,
Action::LogMetrics(_) => 12,
Action::ExtractBase64(_) => 13,
Action::ExpandList(_) => 14,
}
} else {
100
Expand All @@ -1068,6 +1081,7 @@ impl Action {
Action::ComputerMetrics(_) => "computer-metrics",
Action::LogMetrics(_) => "log-metrics",
Action::ExtractBase64(_) => "extract-base64",
Action::ExpandList(_) => "expand-list",
}
} else {
""
Expand Down Expand Up @@ -1863,6 +1877,25 @@ pub struct ExtractBase64Option {
pub clobber: bool,
}

#[derive(Args, Clone, Debug)]
pub struct ExpandListOption {
/// Specify rule directory (default: ./rules)
#[arg(
help_heading = Some("General Options"),
short = 'r',
long,
default_value = "./rules",
hide_default_value = true,
value_name = "DIR/FILE",
requires = "no_wizard",
display_order = 441
)]
pub rules: PathBuf,

#[clap(flatten)]
pub common_options: CommonOptions,
}

#[derive(Parser, Clone, Debug)]
#[clap(
author = "Yamato Security (https://github.com/Yamato-Security/hayabusa - @SecurityYamato)",
Expand Down
56 changes: 55 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ use hayabusa::options::htmlreport::{self, HTML_REPORTER};
use hayabusa::options::pivot::create_output;
use hayabusa::options::pivot::PIVOT_KEYWORD;
use hayabusa::options::profile::set_default_profile;
use hayabusa::options::{level_tuning::LevelTuning, update::Update};
use hayabusa::options::{expand_list::expand_list, level_tuning::LevelTuning, update::Update};
use hayabusa::timeline::computer_metrics::countup_event_by_computer;
use hayabusa::{detections::configs, timeline::timelines::Timeline};
use hayabusa::{detections::utils::write_color_buffer, filter};
Expand Down Expand Up @@ -850,6 +850,60 @@ impl App {
let _ = self.output_open_close_message("closing_messages.txt", stored_static);
return;
}
Action::ExpandList(opt) => {
let encoded_rule_dir = Path::new("./encoded_rules.yml");
let rule_dir = if encoded_rule_dir.exists() {
&encoded_rule_dir.to_path_buf()
} else {
&opt.rules
};
// rule configのフォルダ、ファイルを確認してエラーがあった場合は終了とする
if !rule_dir.exists() {
AlertMessage::alert(
"The rules directory does not exist. Please check the path.",
)
.ok();
return;
}
println!();
let result = expand_list(rule_dir);
let result: Vec<&String> = result.iter().collect();
if result.is_empty() {
write_color_buffer(
&BufferWriter::stdout(ColorChoice::Always),
get_writable_color(
Some(Color::Rgb(255, 175, 0)),
stored_static.common_options.no_color,
),
"No expanded rules found.",
true,
)
.ok();
} else {
write_color_buffer(
&BufferWriter::stdout(ColorChoice::Always),
get_writable_color(
Some(Color::Rgb(0, 255, 0)),
stored_static.common_options.no_color,
),
&format!("{:?} unique expand placeholders found:", result.len()),
true,
)
.ok();
for expand in result {
write_color_buffer(
&BufferWriter::stdout(ColorChoice::Always),
None,
&expand.replace("%", ""),
true,
)
.ok();
}
}
println!();
let _ = self.output_open_close_message("closing_messages.txt", stored_static);
return;
}
_ => {}
}

Expand Down
63 changes: 63 additions & 0 deletions src/options/expand_list.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
use hashbrown::HashSet;
use std::collections::HashMap;
use std::fs;
use std::path::{Path, PathBuf};
use yaml_rust2::yaml::Hash;
use yaml_rust2::YamlLoader;

fn list_yml_files<P: AsRef<Path>>(dir: P) -> Vec<String> {
let mut yml_files = Vec::new();
if let Ok(entries) = fs::read_dir(dir) {
for entry in entries.flatten() {
let path = entry.path();
if path.is_dir() {
yml_files.extend(list_yml_files(path));
} else if let Some(ext) = path.extension() {
if ext == "yml" {
yml_files.push(path.to_string_lossy().to_string());
}
}
}
}
yml_files
}

fn extract_expand_keys_recursive(hash: &Hash, expand_keys: &mut HashMap<String, String>) {
for (key, value) in hash {
if let Some(key_str) = key.as_str() {
if key_str.contains("|expand") {
if let Some(value_str) = value.as_str() {
expand_keys.insert(key_str.to_string(), value_str.to_string());
}
}
if let Some(sub_hash) = value.as_hash() {
extract_expand_keys_recursive(sub_hash, expand_keys);
}
}
}
}
fn extract_expand_keys(detection: &Hash) -> HashMap<String, String> {
let mut expand_keys = HashMap::new();
extract_expand_keys_recursive(detection, &mut expand_keys);
expand_keys
}

pub fn expand_list(dir: &PathBuf) -> HashSet<String> {
let yml_files = list_yml_files(dir);
let mut result = HashSet::new();
for file in yml_files {
if let Ok(content) = fs::read_to_string(&file) {
if let Ok(docs) = YamlLoader::load_from_str(&content) {
if let Some(yaml) = docs.first() {
if let Some(detection) = yaml["detection"].as_hash() {
let expand_keys = extract_expand_keys(detection);
if !expand_keys.is_empty() {
result.extend(expand_keys.values().cloned())
}
}
}
}
}
}
result
}
1 change: 1 addition & 0 deletions src/options/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod expand_list;
pub mod geoip_search;
pub mod htmlreport;
pub mod level_tuning;
Expand Down

0 comments on commit 0c1511c

Please sign in to comment.