rule file implemented.
This commit is contained in:
@@ -73,9 +73,9 @@ impl EventKeyAliasConfig {
|
|||||||
fn load_eventkey_alias() -> EventKeyAliasConfig {
|
fn load_eventkey_alias() -> EventKeyAliasConfig {
|
||||||
let mut config = EventKeyAliasConfig::new();
|
let mut config = EventKeyAliasConfig::new();
|
||||||
|
|
||||||
utils::read_csv("config/eventkey_alias.txt")
|
let read_result = utils::read_csv("config/eventkey_alias.txt");
|
||||||
.into_iter()
|
// eventkey_alisasが読み込めなかったらエラーで終了とする。
|
||||||
.for_each(|line| {
|
read_result.unwrap().into_iter().for_each(|line| {
|
||||||
if line.len() != 2 {
|
if line.len() != 2 {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -246,7 +246,12 @@ impl LeafSelectionNode {
|
|||||||
|
|
||||||
// LeafMatcherの一覧を取得する。
|
// LeafMatcherの一覧を取得する。
|
||||||
fn get_matchers(&self) -> Vec<Box<dyn LeafMatcher>> {
|
fn get_matchers(&self) -> Vec<Box<dyn LeafMatcher>> {
|
||||||
return vec![Box::new(RegexMatcher::new())];
|
return vec![
|
||||||
|
Box::new(RegexMatcher::new()),
|
||||||
|
Box::new(MinlengthMatcher::new()),
|
||||||
|
Box::new(RegexesFileMatcher::new()),
|
||||||
|
Box::new(WhitelistFileMatcher::new()),
|
||||||
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -275,6 +280,13 @@ impl SelectionNode for LeafSelectionNode {
|
|||||||
)]);
|
)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.select_value.is_badvalue() {
|
||||||
|
return Result::Err(vec![format!(
|
||||||
|
"Cannot parse yaml file. key:{}",
|
||||||
|
concat_selection_key(&match_key_list)
|
||||||
|
)]);
|
||||||
|
}
|
||||||
|
|
||||||
return self
|
return self
|
||||||
.matcher
|
.matcher
|
||||||
.as_mut()
|
.as_mut()
|
||||||
@@ -316,7 +328,15 @@ impl RegexMatcher {
|
|||||||
|
|
||||||
impl LeafMatcher for RegexMatcher {
|
impl LeafMatcher for RegexMatcher {
|
||||||
fn is_target_key(&self, key_list: &Vec<String>) -> bool {
|
fn is_target_key(&self, key_list: &Vec<String>) -> bool {
|
||||||
return key_list.is_empty();
|
if key_list.is_empty() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if key_list.len() == 1 {
|
||||||
|
return key_list.get(0).unwrap_or(&"".to_string()) == &"regex".to_string();
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init(&mut self, key_list: &Vec<String>, select_value: &Yaml) -> Result<(), Vec<String>> {
|
fn init(&mut self, key_list: &Vec<String>, select_value: &Yaml) -> Result<(), Vec<String>> {
|
||||||
@@ -378,3 +398,170 @@ impl LeafMatcher for RegexMatcher {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 指定された文字数以上であることをチェックするクラス。
|
||||||
|
struct MinlengthMatcher {
|
||||||
|
min_len: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MinlengthMatcher {
|
||||||
|
fn new() -> MinlengthMatcher {
|
||||||
|
return MinlengthMatcher { min_len: 0 };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LeafMatcher for MinlengthMatcher {
|
||||||
|
fn is_target_key(&self, key_list: &Vec<String>) -> bool {
|
||||||
|
if key_list.len() != 1 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return key_list.get(0).unwrap() == "min_length";
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init(&mut self, key_list: &Vec<String>, select_value: &Yaml) -> Result<(), Vec<String>> {
|
||||||
|
let min_length = select_value.as_i64();
|
||||||
|
if min_length.is_none() {
|
||||||
|
let errmsg = format!(
|
||||||
|
"min_length value should be Integer. [key:{}]",
|
||||||
|
concat_selection_key(key_list)
|
||||||
|
);
|
||||||
|
return Result::Err(vec![errmsg]);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.min_len = min_length.unwrap();
|
||||||
|
return Result::Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_match(&self, event_value: Option<&Value>) -> bool {
|
||||||
|
return match event_value.unwrap_or(&Value::Null) {
|
||||||
|
Value::String(s) => s.len() as i64 >= self.min_len,
|
||||||
|
Value::Number(n) => n.to_string().len() as i64 >= self.min_len,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 正規表現のリストが記載されたファイルを読み取って、比較するロジックを表すクラス
|
||||||
|
// DeepBlueCLIのcheck_cmdメソッドの一部に同様の処理が実装されていた。
|
||||||
|
struct RegexesFileMatcher {
|
||||||
|
regexes_csv_content: Vec<Vec<String>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RegexesFileMatcher {
|
||||||
|
fn new() -> RegexesFileMatcher {
|
||||||
|
return RegexesFileMatcher {
|
||||||
|
regexes_csv_content: vec![],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LeafMatcher for RegexesFileMatcher {
|
||||||
|
fn is_target_key(&self, key_list: &Vec<String>) -> bool {
|
||||||
|
if key_list.len() != 1 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return key_list.get(0).unwrap() == "regexes";
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init(&mut self, key_list: &Vec<String>, select_value: &Yaml) -> Result<(), Vec<String>> {
|
||||||
|
let value = match select_value {
|
||||||
|
Yaml::String(s) => Option::Some(s.to_owned()),
|
||||||
|
Yaml::Integer(i) => Option::Some(i.to_string()),
|
||||||
|
Yaml::Real(r) => Option::Some(r.to_owned()),
|
||||||
|
_ => Option::None,
|
||||||
|
};
|
||||||
|
if value.is_none() {
|
||||||
|
let errmsg = format!(
|
||||||
|
"regexes value should be String. [key:{}]",
|
||||||
|
concat_selection_key(key_list)
|
||||||
|
);
|
||||||
|
return Result::Err(vec![errmsg]);
|
||||||
|
}
|
||||||
|
|
||||||
|
let csv_content = utils::read_csv(&value.unwrap());
|
||||||
|
if csv_content.is_err() {
|
||||||
|
let errmsg = format!(
|
||||||
|
"cannot read regexes file. [key:{}]",
|
||||||
|
concat_selection_key(key_list)
|
||||||
|
);
|
||||||
|
return Result::Err(vec![errmsg]);
|
||||||
|
}
|
||||||
|
self.regexes_csv_content = csv_content.unwrap();
|
||||||
|
|
||||||
|
return Result::Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_match(&self, event_value: Option<&Value>) -> bool {
|
||||||
|
return match event_value.unwrap_or(&Value::Null) {
|
||||||
|
Value::String(s) => !utils::check_regex(s, 0, &self.regexes_csv_content).is_empty(),
|
||||||
|
Value::Number(n) => {
|
||||||
|
!utils::check_regex(&n.to_string(), 0, &self.regexes_csv_content).is_empty()
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ファイルに列挙された文字列に一致しない場合に検知するロジックを表す
|
||||||
|
// DeepBlueCLIのcheck_cmdメソッドの一部に同様の処理が実装されていた。
|
||||||
|
struct WhitelistFileMatcher {
|
||||||
|
whitelist_csv_content: Vec<Vec<String>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WhitelistFileMatcher {
|
||||||
|
fn new() -> WhitelistFileMatcher {
|
||||||
|
return WhitelistFileMatcher {
|
||||||
|
whitelist_csv_content: vec![],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LeafMatcher for WhitelistFileMatcher {
|
||||||
|
fn is_target_key(&self, key_list: &Vec<String>) -> bool {
|
||||||
|
if key_list.len() != 1 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return key_list.get(0).unwrap() == "whitelist";
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init(&mut self, key_list: &Vec<String>, select_value: &Yaml) -> Result<(), Vec<String>> {
|
||||||
|
let value = match select_value {
|
||||||
|
Yaml::String(s) => Option::Some(s.to_owned()),
|
||||||
|
Yaml::Integer(i) => Option::Some(i.to_string()),
|
||||||
|
Yaml::Real(r) => Option::Some(r.to_owned()),
|
||||||
|
_ => Option::None,
|
||||||
|
};
|
||||||
|
if value.is_none() {
|
||||||
|
let errmsg = format!(
|
||||||
|
"whitelist value should be String. [key:{}]",
|
||||||
|
concat_selection_key(key_list)
|
||||||
|
);
|
||||||
|
return Result::Err(vec![errmsg]);
|
||||||
|
}
|
||||||
|
|
||||||
|
let csv_content = utils::read_csv(&value.unwrap());
|
||||||
|
if csv_content.is_err() {
|
||||||
|
let errmsg = format!(
|
||||||
|
"cannot read whitelist file. [key:{}]",
|
||||||
|
concat_selection_key(key_list)
|
||||||
|
);
|
||||||
|
return Result::Err(vec![errmsg]);
|
||||||
|
}
|
||||||
|
self.whitelist_csv_content = csv_content.unwrap();
|
||||||
|
|
||||||
|
return Result::Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_match(&self, event_value: Option<&Value>) -> bool {
|
||||||
|
return match event_value.unwrap_or(&Value::Null) {
|
||||||
|
Value::String(s) => !utils::check_regex(s, 0, &self.whitelist_csv_content).is_empty(),
|
||||||
|
Value::Number(n) => {
|
||||||
|
!utils::check_regex(&n.to_string(), 0, &self.whitelist_csv_content).is_empty()
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -63,12 +63,13 @@ pub fn check_whitelist(target: &str, whitelist: &Vec<Vec<String>>) -> bool {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_csv(filename: &str) -> Vec<Vec<String>> {
|
pub fn read_csv(filename: &str) -> Result<Vec<Vec<String>>, String> {
|
||||||
let mut f = File::open(filename).expect("file not found!!!");
|
let mut f = File::open(filename).expect("file not found!!!");
|
||||||
let mut contents: String = String::new();
|
let mut contents: String = String::new();
|
||||||
let mut ret = vec![];
|
let mut ret = vec![];
|
||||||
|
let read_res = f.read_to_string(&mut contents);
|
||||||
if f.read_to_string(&mut contents).is_err() {
|
if f.read_to_string(&mut contents).is_err() {
|
||||||
return ret;
|
return Result::Err(read_res.unwrap_err().to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut rdr = csv::Reader::from_reader(contents.as_bytes());
|
let mut rdr = csv::Reader::from_reader(contents.as_bytes());
|
||||||
@@ -83,7 +84,7 @@ pub fn read_csv(filename: &str) -> Vec<Vec<String>> {
|
|||||||
ret.push(v);
|
ret.push(v);
|
||||||
});
|
});
|
||||||
|
|
||||||
return ret;
|
return Result::Ok(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_event_value<'a>(key: &String, event_value: &'a Value) -> Option<&'a Value> {
|
pub fn get_event_value<'a>(key: &String, event_value: &'a Value) -> Option<&'a Value> {
|
||||||
@@ -113,7 +114,7 @@ mod tests {
|
|||||||
use crate::detections::utils;
|
use crate::detections::utils;
|
||||||
#[test]
|
#[test]
|
||||||
fn test_check_regex() {
|
fn test_check_regex() {
|
||||||
let regexes = utils::read_csv("regexes.txt");
|
let regexes = utils::read_csv("regexes.txt").unwrap();
|
||||||
let regextext = utils::check_regex("\\cvtres.exe", 0, ®exes);
|
let regextext = utils::check_regex("\\cvtres.exe", 0, ®exes);
|
||||||
assert!(regextext == "Resource File To COFF Object Conversion Utility cvtres.exe\n");
|
assert!(regextext == "Resource File To COFF Object Conversion Utility cvtres.exe\n");
|
||||||
|
|
||||||
@@ -124,7 +125,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_check_whitelist() {
|
fn test_check_whitelist() {
|
||||||
let commandline = "\"C:\\Program Files\\Google\\Update\\GoogleUpdate.exe\"";
|
let commandline = "\"C:\\Program Files\\Google\\Update\\GoogleUpdate.exe\"";
|
||||||
let whitelist = utils::read_csv("whitelist.txt");
|
let whitelist = utils::read_csv("whitelist.txt").unwrap();
|
||||||
assert!(true == utils::check_whitelist(commandline, &whitelist));
|
assert!(true == utils::check_whitelist(commandline, &whitelist));
|
||||||
|
|
||||||
let commandline = "\"C:\\Program Files\\Google\\Update\\GoogleUpdate2.exe\"";
|
let commandline = "\"C:\\Program Files\\Google\\Update\\GoogleUpdate2.exe\"";
|
||||||
|
|||||||
Reference in New Issue
Block a user