Merge pull request #655 from Yamato-Security/643-enhancement-implement-null-keyword
Implement null keyword
This commit is contained in:
@@ -5,6 +5,7 @@
|
|||||||
**新機能:**
|
**新機能:**
|
||||||
|
|
||||||
- `config/profiles.yaml`と`config/default_profile.yaml`の設定ファイルで、出力内容をカスタマイズできる。 (#165) (@hitenkoku)
|
- `config/profiles.yaml`と`config/default_profile.yaml`の設定ファイルで、出力内容をカスタマイズできる。 (#165) (@hitenkoku)
|
||||||
|
- 対象のフィールドがレコード内に存在しないことを確認する `null` キーワードに対応した。 (#643) (@hitenkoku)
|
||||||
|
|
||||||
**改善:**
|
**改善:**
|
||||||
|
|
||||||
|
|||||||
@@ -4,13 +4,14 @@
|
|||||||
|
|
||||||
**New Features:**
|
**New Features:**
|
||||||
|
|
||||||
- Customizable output of fields defined at `config/profiles.yaml` and `config/default_profile.yaml` (#165) (@hitenkoku)
|
- Customizable output of fields defined at `config/profiles.yaml` and `config/default_profile.yaml`. (#165) (@hitenkoku)
|
||||||
|
- Implemented the `null` keyword for rule detection. It is used to check if a target field exists or not. (#643) (@hitenkoku)
|
||||||
|
|
||||||
**Enhancements:**
|
**Enhancements:**
|
||||||
|
|
||||||
- Removed ./ from rule path when updating. (#642) (@hitenkoku)
|
- Removed ./ from rule path when updating. (#642) (@hitenkoku)
|
||||||
- Added new output alias for MITRE ATT&CK tags and other tags. (#637) (@hitenkoku)
|
- Added new output alias for MITRE ATT&CK tags and other tags. (#637) (@hitenkoku)
|
||||||
- Changed output summary numbers from without commas to with commas. (#649) (@hitenkoku)
|
- Added commas to summary numbers to make them easier to read. (#649) (@hitenkoku)
|
||||||
|
|
||||||
**Bug Fixes:**
|
**Bug Fixes:**
|
||||||
|
|
||||||
|
|||||||
@@ -218,7 +218,7 @@ impl DefaultMatcher {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// YEAのルールファイルのフィールド名とそれに続いて指定されるパイプを、正規表現形式の文字列に変換します。
|
/// Hayabusaのルールファイルのフィールド名とそれに続いて指定されるパイプを、正規表現形式の文字列に変換します。
|
||||||
/// ワイルドカードの文字列を正規表現にする処理もこのメソッドに実装されています。patternにワイルドカードの文字列を指定して、pipesにPipeElement::Wildcardを指定すればOK!!
|
/// ワイルドカードの文字列を正規表現にする処理もこのメソッドに実装されています。patternにワイルドカードの文字列を指定して、pipesにPipeElement::Wildcardを指定すればOK!!
|
||||||
fn from_pattern_to_regex_str(pattern: String, pipes: &[PipeElement]) -> String {
|
fn from_pattern_to_regex_str(pattern: String, pipes: &[PipeElement]) -> String {
|
||||||
// パターンをPipeで処理する。
|
// パターンをPipeで処理する。
|
||||||
@@ -346,6 +346,17 @@ impl LeafMatcher for DefaultMatcher {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// yamlにnullが設定されていた場合
|
||||||
|
if self.re.is_none() {
|
||||||
|
// レコード内に対象のフィールドが存在しなければ検知したものとして扱う
|
||||||
|
for v in self.key_list.iter() {
|
||||||
|
if recinfo.get_value(v).is_none() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if event_value.is_none() {
|
if event_value.is_none() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -353,7 +364,7 @@ impl LeafMatcher for DefaultMatcher {
|
|||||||
let event_value_str = event_value.unwrap();
|
let event_value_str = event_value.unwrap();
|
||||||
if self.key_list.is_empty() {
|
if self.key_list.is_empty() {
|
||||||
// この場合ただのgrep検索なので、ただ正規表現に一致するかどうか調べればよいだけ
|
// この場合ただのgrep検索なので、ただ正規表現に一致するかどうか調べればよいだけ
|
||||||
return self.re.as_ref().unwrap().is_match(event_value_str);
|
self.re.as_ref().unwrap().is_match(event_value_str)
|
||||||
} else {
|
} else {
|
||||||
// 通常の検索はこっち
|
// 通常の検索はこっち
|
||||||
self.is_regex_fullmatch(event_value_str)
|
self.is_regex_fullmatch(event_value_str)
|
||||||
@@ -1984,4 +1995,65 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_eq_field_null() {
|
||||||
|
// 値でnullであった場合に対象のフィールドが存在しないことを確認
|
||||||
|
let rule_str = r#"
|
||||||
|
enabled: true
|
||||||
|
detection:
|
||||||
|
selection:
|
||||||
|
Channel:
|
||||||
|
value: Security
|
||||||
|
Takoyaki:
|
||||||
|
value: null
|
||||||
|
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_null_not_detect() {
|
||||||
|
// 値でnullであった場合に対象のフィールドが存在しないことを確認するテスト
|
||||||
|
let rule_str = r#"
|
||||||
|
enabled: true
|
||||||
|
detection:
|
||||||
|
selection:
|
||||||
|
EventID: null
|
||||||
|
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(e) => {
|
||||||
|
panic!("Failed to parse json record.{:?}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user