add equalsfield pipe (#467)
This commit is contained in:
92
Cargo.lock
generated
92
Cargo.lock
generated
@@ -48,9 +48,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.55"
|
||||
version = "1.0.56"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "159bb86af3a200e19a068f4224eae4c8bb2d0fa054c7e5d1cacd5cef95e684cd"
|
||||
checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27"
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
@@ -359,12 +359,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.5.2"
|
||||
version = "0.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e54ea8bc3fb1ee042f5aace6e3c6e025d3874866da222930f70ce62aceba0bfa"
|
||||
checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"crossbeam-utils 0.8.7",
|
||||
"crossbeam-utils 0.8.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -385,8 +385,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"crossbeam-epoch 0.9.7",
|
||||
"crossbeam-utils 0.8.7",
|
||||
"crossbeam-epoch 0.9.8",
|
||||
"crossbeam-utils 0.8.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -406,12 +406,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.9.7"
|
||||
version = "0.9.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c00d6d2ea26e8b151d99093005cb442fb9a37aeaca582a03ec70946f49ab5ed9"
|
||||
checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c"
|
||||
dependencies = [
|
||||
"autocfg 1.1.0",
|
||||
"cfg-if 1.0.0",
|
||||
"crossbeam-utils 0.8.7",
|
||||
"crossbeam-utils 0.8.8",
|
||||
"lazy_static",
|
||||
"memoffset 0.6.5",
|
||||
"scopeguard",
|
||||
@@ -441,9 +442,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.7"
|
||||
version = "0.8.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5e5bed1f1c269533fa816a0a5492b3545209a205ca1a54842be180eb63a16a6"
|
||||
checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"lazy_static",
|
||||
@@ -776,7 +777,7 @@ checksum = "d39cd93900197114fa1fcb7ae84ca742095eed9442088988ae74fa744e930e77"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
"wasi",
|
||||
"wasi 0.10.0+wasi-snapshot-preview1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1113,9 +1114,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.119"
|
||||
version = "0.2.121"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4"
|
||||
checksum = "efaa7b300f3b5fe8eb6bf21ce3895e1751d9665086af2d64b42f19701015ff4f"
|
||||
|
||||
[[package]]
|
||||
name = "libgit2-sys"
|
||||
@@ -1147,9 +1148,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libz-sys"
|
||||
version = "1.1.3"
|
||||
version = "1.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "de5435b8549c16d423ed0c03dbaafe57cf6c3344744f1242520d59c9d8ecec66"
|
||||
checksum = "6f35facd4a5673cb5a48822be2be1d4236c1c99cb4113cab7061ac720d5bf859"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
@@ -1183,9 +1184,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.14"
|
||||
version = "0.4.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
|
||||
checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
]
|
||||
@@ -1273,14 +1274,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.8.0"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba272f85fa0b41fc91872be579b3bbe0f56b792aa361a380eb669469f68dafb2"
|
||||
checksum = "52da4364ffb0e4fe33a9841a98a3f3014fb964045ce4f7a45a398243c8d6b0c9"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
"miow 0.3.7",
|
||||
"ntapi",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
@@ -1394,9 +1396,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.9.0"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5"
|
||||
checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
|
||||
|
||||
[[package]]
|
||||
name = "openssl"
|
||||
@@ -1420,9 +1422,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
|
||||
|
||||
[[package]]
|
||||
name = "openssl-src"
|
||||
version = "111.17.0+1.1.1m"
|
||||
version = "111.18.0+1.1.1n"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05d6a336abd10814198f66e2a91ccd7336611f30334119ca8ce300536666fcf4"
|
||||
checksum = "7897a926e1e8d00219127dc020130eca4292e5ca666dd592480d72c3eca2ff6c"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
@@ -1485,7 +1487,7 @@ checksum = "28141e0cc4143da2443301914478dc976a61ffdb3f043058310c70df2fed8954"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
"redox_syscall 0.2.11",
|
||||
"redox_syscall 0.2.12",
|
||||
"smallvec 1.8.0",
|
||||
"windows-sys",
|
||||
]
|
||||
@@ -1580,9 +1582,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.15"
|
||||
version = "1.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145"
|
||||
checksum = "632d02bff7f874a36f33ea8bb416cd484b90cc66c1194b1a1110d067a7013f58"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
@@ -1713,7 +1715,7 @@ checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e"
|
||||
dependencies = [
|
||||
"crossbeam-channel",
|
||||
"crossbeam-deque 0.8.1",
|
||||
"crossbeam-utils 0.8.7",
|
||||
"crossbeam-utils 0.8.8",
|
||||
"lazy_static",
|
||||
"num_cpus",
|
||||
]
|
||||
@@ -1735,18 +1737,18 @@ checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.11"
|
||||
version = "0.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8380fe0152551244f0747b1bf41737e0f8a74f97a14ccefd1148187271634f3c"
|
||||
checksum = "8ae183fc1b06c149f0c1793e1eb447c8b04bfe46d48e9e48bfb8d2d7ed64ecf0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.5.4"
|
||||
version = "1.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
|
||||
checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
@@ -2142,9 +2144,9 @@ checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.86"
|
||||
version = "1.0.89"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b"
|
||||
checksum = "ea297be220d52398dcc07ce15a209fce436d361735ac1db700cab3b6cdfb9f54"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -2172,16 +2174,16 @@ dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"fastrand",
|
||||
"libc",
|
||||
"redox_syscall 0.2.11",
|
||||
"redox_syscall 0.2.12",
|
||||
"remove_dir_all",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
|
||||
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
@@ -2232,7 +2234,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"wasi",
|
||||
"wasi 0.10.0+wasi-snapshot-preview1",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
@@ -2317,7 +2319,7 @@ dependencies = [
|
||||
"bytes 1.1.0",
|
||||
"libc",
|
||||
"memchr",
|
||||
"mio 0.8.0",
|
||||
"mio 0.8.2",
|
||||
"num_cpus",
|
||||
"once_cell",
|
||||
"parking_lot 0.12.0",
|
||||
@@ -2598,6 +2600,12 @@ version = "0.10.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.79"
|
||||
@@ -2786,6 +2794,6 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zeroize"
|
||||
version = "1.5.3"
|
||||
version = "1.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50344758e2f40e3a1fcfc8f6f91aa57b5f8ebd8d27919fe6451f15aaaf9ee608"
|
||||
checksum = "7eb5728b8afd3f280a869ce1d4c554ffaed35f45c231fc41bfbd0381bef50317"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use regex::Regex;
|
||||
use std::collections::VecDeque;
|
||||
use std::{cmp::Ordering, collections::VecDeque};
|
||||
use yaml_rust::Yaml;
|
||||
|
||||
use crate::detections::{detection::EvtxRecordInfo, utils};
|
||||
@@ -192,6 +192,7 @@ pub struct DefaultMatcher {
|
||||
re: Option<Regex>,
|
||||
pipes: Vec<PipeElement>,
|
||||
key_list: Vec<String>,
|
||||
eqfield_key: Option<String>,
|
||||
}
|
||||
|
||||
impl DefaultMatcher {
|
||||
@@ -200,9 +201,14 @@ impl DefaultMatcher {
|
||||
re: Option::None,
|
||||
pipes: Vec::new(),
|
||||
key_list: Vec::new(),
|
||||
eqfield_key: Option::None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_eqfield_key(&self) -> Option<&String> {
|
||||
self.eqfield_key.as_ref()
|
||||
}
|
||||
|
||||
/// このmatcherの正規表現とマッチするかどうか判定します。
|
||||
/// 判定対象の文字列とこのmatcherが保持する正規表現が完全にマッチした場合のTRUEを返します。
|
||||
/// 例えば、判定対象文字列が"abc"で、正規表現が"ab"の場合、正規表現は判定対象文字列の一部分にしか一致していないので、この関数はfalseを返します。
|
||||
@@ -265,6 +271,7 @@ impl LeafMatcher for DefaultMatcher {
|
||||
"endswith" => Option::Some(PipeElement::Endswith),
|
||||
"contains" => Option::Some(PipeElement::Contains),
|
||||
"re" => Option::Some(PipeElement::Re),
|
||||
"equalsfield" => Option::Some(PipeElement::EqualsField),
|
||||
_ => Option::None,
|
||||
};
|
||||
if pipe_element.is_none() {
|
||||
@@ -285,34 +292,54 @@ impl LeafMatcher for DefaultMatcher {
|
||||
);
|
||||
return Result::Err(vec![errmsg]);
|
||||
}
|
||||
let is_re = &self
|
||||
|
||||
let is_eqfield = self
|
||||
.pipes
|
||||
.iter()
|
||||
.any(|pipe_element| matches!(pipe_element, PipeElement::Re));
|
||||
// 正規表現ではない場合、ワイルドカードであることを表す。
|
||||
// ワイルドカードは正規表現でマッチングするので、ワイルドカードを正規表現に変換するPipeを内部的に追加することにする。
|
||||
if !is_re {
|
||||
self.pipes.push(PipeElement::Wildcard);
|
||||
}
|
||||
.any(|pipe_element| matches!(pipe_element, PipeElement::EqualsField));
|
||||
if is_eqfield {
|
||||
// PipeElement::EqualsFieldは特別
|
||||
self.eqfield_key = Option::Some(pattern);
|
||||
} else {
|
||||
// 正規表現ではない場合、ワイルドカードであることを表す。
|
||||
// ワイルドカードは正規表現でマッチングするので、ワイルドカードを正規表現に変換するPipeを内部的に追加することにする。
|
||||
let is_re = self
|
||||
.pipes
|
||||
.iter()
|
||||
.any(|pipe_element| matches!(pipe_element, PipeElement::Re));
|
||||
if !is_re {
|
||||
self.pipes.push(PipeElement::Wildcard);
|
||||
}
|
||||
|
||||
// パターンをPipeで処理する。
|
||||
let pattern = DefaultMatcher::from_pattern_to_regex_str(pattern, &self.pipes);
|
||||
// Pipeで処理されたパターンを正規表現に変換
|
||||
let re_result = Regex::new(&pattern);
|
||||
if re_result.is_err() {
|
||||
let errmsg = format!(
|
||||
"Cannot parse regex. [regex:{}, key:{}]",
|
||||
pattern,
|
||||
utils::concat_selection_key(key_list)
|
||||
);
|
||||
return Result::Err(vec![errmsg]);
|
||||
let pattern = DefaultMatcher::from_pattern_to_regex_str(pattern, &self.pipes);
|
||||
// Pipeで処理されたパターンを正規表現に変換
|
||||
let re_result = Regex::new(&pattern);
|
||||
if re_result.is_err() {
|
||||
let errmsg = format!(
|
||||
"Cannot parse regex. [regex:{}, key:{}]",
|
||||
pattern,
|
||||
utils::concat_selection_key(key_list)
|
||||
);
|
||||
return Result::Err(vec![errmsg]);
|
||||
}
|
||||
self.re = re_result.ok();
|
||||
}
|
||||
self.re = re_result.ok();
|
||||
|
||||
Result::Ok(())
|
||||
}
|
||||
|
||||
fn is_match(&self, event_value: Option<&String>, _recinfo: &EvtxRecordInfo) -> bool {
|
||||
fn is_match(&self, event_value: Option<&String>, recinfo: &EvtxRecordInfo) -> bool {
|
||||
// PipeElement::EqualsFieldが設定されていた場合
|
||||
if let Some(eqfield_key) = &self.eqfield_key {
|
||||
let another_value = recinfo.get_value(eqfield_key);
|
||||
// Evtxのレコードに存在しないeventkeyを指定された場合はfalseにする
|
||||
if event_value.is_none() || another_value.is_none() {
|
||||
return false;
|
||||
}
|
||||
|
||||
return another_value.unwrap().cmp(event_value.unwrap()) == Ordering::Equal;
|
||||
}
|
||||
|
||||
// yamlにnullが設定されていた場合
|
||||
// keylistが空(==JSONのgrep検索)の場合、無視する。
|
||||
if self.key_list.is_empty() && self.re.is_none() {
|
||||
@@ -341,6 +368,7 @@ enum PipeElement {
|
||||
Contains,
|
||||
Re,
|
||||
Wildcard,
|
||||
EqualsField,
|
||||
}
|
||||
|
||||
impl PipeElement {
|
||||
@@ -377,10 +405,9 @@ impl PipeElement {
|
||||
PipeElement::Endswith => fn_add_asterisk_begin(pattern),
|
||||
// containsの場合はpatternの前後にwildcardを足すことで対応する
|
||||
PipeElement::Contains => fn_add_asterisk_end(fn_add_asterisk_begin(pattern)),
|
||||
// 正規表現の場合は特に処理する必要無い
|
||||
PipeElement::Re => pattern,
|
||||
// WildCardは正規表現に変換する。
|
||||
PipeElement::Wildcard => PipeElement::pipe_pattern_wildcard(pattern),
|
||||
_ => pattern,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1707,4 +1734,128 @@ mod tests {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_eq_field() {
|
||||
// equalsfieldsで正しく検知できることを確認
|
||||
let rule_str = r#"
|
||||
detection:
|
||||
selection:
|
||||
Channel|equalsfield: Computer
|
||||
details: 'command=%CommandLine%'
|
||||
"#;
|
||||
|
||||
let record_json_str = r#"
|
||||
{
|
||||
"Event": {"System": {"EventID": 4103, "Channel": "Security", "Computer": "Security" }},
|
||||
"Event_attributes": {"xmlns": "http://schemas.microsoft.com/win/2004/08/events/event"}
|
||||
}"#;
|
||||
|
||||
let mut rule_node = parse_rule_from_str(rule_str);
|
||||
match serde_json::from_str(record_json_str) {
|
||||
Ok(record) => {
|
||||
let keys = detections::rule::get_detection_keys(&rule_node);
|
||||
let recinfo = utils::create_rec_info(record, "testpath".to_owned(), &keys);
|
||||
assert!(rule_node.select(&recinfo));
|
||||
}
|
||||
Err(_) => {
|
||||
panic!("Failed to parse json record.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_eq_field_notdetect() {
|
||||
// equalsfieldsの検知できないパターン
|
||||
// equalsfieldsで正しく検知できることを確認
|
||||
let rule_str = r#"
|
||||
detection:
|
||||
selection:
|
||||
Channel|equalsfield: Computer
|
||||
details: 'command=%CommandLine%'
|
||||
"#;
|
||||
|
||||
let record_json_str = r#"
|
||||
{
|
||||
"Event": {"System": {"EventID": 4103, "Channel": "Security", "Computer": "Powershell" }},
|
||||
"Event_attributes": {"xmlns": "http://schemas.microsoft.com/win/2004/08/events/event"}
|
||||
}"#;
|
||||
|
||||
let mut rule_node = parse_rule_from_str(rule_str);
|
||||
match serde_json::from_str(record_json_str) {
|
||||
Ok(record) => {
|
||||
let keys = detections::rule::get_detection_keys(&rule_node);
|
||||
let recinfo = utils::create_rec_info(record, "testpath".to_owned(), &keys);
|
||||
assert!(!rule_node.select(&recinfo));
|
||||
}
|
||||
Err(_) => {
|
||||
panic!("Failed to parse json record.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_eq_field_emptyfield() {
|
||||
// 存在しないフィールドを指定した場合は検知しない
|
||||
let rule_str = r#"
|
||||
detection:
|
||||
selection:
|
||||
Channel|equalsfield: NoField
|
||||
details: 'command=%CommandLine%'
|
||||
"#;
|
||||
|
||||
let record_json_str = r#"
|
||||
{
|
||||
"Event": {"System": {"EventID": 4103, "Channel": "Security", "Computer": "Securiti" }},
|
||||
"Event_attributes": {"xmlns": "http://schemas.microsoft.com/win/2004/08/events/event"}
|
||||
}"#;
|
||||
|
||||
let mut rule_node = parse_rule_from_str(rule_str);
|
||||
match serde_json::from_str(record_json_str) {
|
||||
Ok(record) => {
|
||||
let keys = detections::rule::get_detection_keys(&rule_node);
|
||||
let recinfo = utils::create_rec_info(record, "testpath".to_owned(), &keys);
|
||||
assert!(!rule_node.select(&recinfo));
|
||||
}
|
||||
Err(_) => {
|
||||
panic!("Failed to parse json record.");
|
||||
}
|
||||
}
|
||||
|
||||
let rule_str = r#"
|
||||
detection:
|
||||
selection:
|
||||
NoField|equalsfield: Channel
|
||||
details: 'command=%CommandLine%'
|
||||
"#;
|
||||
let mut rule_node = parse_rule_from_str(rule_str);
|
||||
match serde_json::from_str(record_json_str) {
|
||||
Ok(record) => {
|
||||
let keys = detections::rule::get_detection_keys(&rule_node);
|
||||
let recinfo = utils::create_rec_info(record, "testpath".to_owned(), &keys);
|
||||
assert!(!rule_node.select(&recinfo));
|
||||
}
|
||||
Err(_) => {
|
||||
panic!("Failed to parse json record.");
|
||||
}
|
||||
}
|
||||
|
||||
let rule_str = r#"
|
||||
detection:
|
||||
selection:
|
||||
NoField|equalsfield: NoField1
|
||||
details: 'command=%CommandLine%'
|
||||
"#;
|
||||
let mut rule_node = parse_rule_from_str(rule_str);
|
||||
match serde_json::from_str(record_json_str) {
|
||||
Ok(record) => {
|
||||
let keys = detections::rule::get_detection_keys(&rule_node);
|
||||
let recinfo = utils::create_rec_info(record, "testpath".to_owned(), &keys);
|
||||
assert!(!rule_node.select(&recinfo));
|
||||
}
|
||||
Err(_) => {
|
||||
panic!("Failed to parse json record.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,19 +106,21 @@ pub fn get_detection_keys(node: &RuleNode) -> Vec<String> {
|
||||
for key in detection.name_to_selection.keys() {
|
||||
let selection = &detection.name_to_selection[key];
|
||||
let desc = selection.get_descendants();
|
||||
let keys = desc.iter().filter_map(|node| {
|
||||
desc.iter().for_each(|node| {
|
||||
if !node.is::<LeafSelectionNode>() {
|
||||
return Option::None;
|
||||
return;
|
||||
}
|
||||
|
||||
let node = node.downcast_ref::<LeafSelectionNode>().unwrap();
|
||||
let key = node.get_key();
|
||||
if key.is_empty() {
|
||||
return Option::None;
|
||||
}
|
||||
Option::Some(key.to_string())
|
||||
let keys = node.get_keys();
|
||||
let keys = keys.iter().filter_map(|key| {
|
||||
if key.is_empty() {
|
||||
return None;
|
||||
}
|
||||
Some(key.to_string())
|
||||
});
|
||||
ret.extend(keys);
|
||||
});
|
||||
ret.extend(keys);
|
||||
}
|
||||
|
||||
ret
|
||||
|
||||
@@ -3,7 +3,7 @@ use downcast_rs::Downcast;
|
||||
use std::{sync::Arc, vec};
|
||||
use yaml_rust::Yaml;
|
||||
|
||||
use super::matchers;
|
||||
use super::matchers::{self, DefaultMatcher};
|
||||
|
||||
// Ruleファイルの detection- selection配下のノードはこのtraitを実装する。
|
||||
pub trait SelectionNode: Downcast {
|
||||
@@ -250,6 +250,24 @@ impl LeafSelectionNode {
|
||||
&self.key
|
||||
}
|
||||
|
||||
pub fn get_keys(&self) -> Vec<&String> {
|
||||
let mut keys = vec![];
|
||||
if !self.key.is_empty() {
|
||||
keys.push(&self.key);
|
||||
}
|
||||
|
||||
if let Some(matcher) = &self.matcher {
|
||||
let matcher = matcher.downcast_ref::<DefaultMatcher>();
|
||||
if let Some(matcher) = matcher {
|
||||
if let Some(eq_key) = matcher.get_eqfield_key() {
|
||||
keys.push(eq_key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
keys
|
||||
}
|
||||
|
||||
fn _create_key(&self) -> String {
|
||||
if self.key_list.is_empty() {
|
||||
return String::default();
|
||||
|
||||
Reference in New Issue
Block a user