Pivot Keyword List機能の追加 (#412)
* add get_pivot_keyword() func * change function name and call it's function * [WIP] support config file * compilete output * cargo fmt * [WIP] add test * add test * support -o option in pivot * add pivot mod * fix miss * pass test in pivot.rs * add comment * pass all test * add fast return * fix output * add test config file * review * rebase * cargo fmt * test pass * fix clippy in my commit * cargo fmt * little refactor * change file input logic and config format * [WIP] change output * [wip] change deta structure * change output & change data structure * pass test * add config * cargo fmt & clippy & rebase * fix cllipy * delete /rules/ in .gitignore * clean comment * clean * clean * fix rebase miss * fix rebase miss * fix clippy * file name output on -o to stdout * add pivot_keywords.txt to ./config * updated english * Documentation update * cargo fmt and clean * updated translate japanese * readme update * readme update Co-authored-by: DustInDark <nextsasasa@gmail.com> Co-authored-by: Tanaka Zakku <71482215+YamatoSecurity@users.noreply.github.com>
This commit is contained in:
270
src/detections/pivot.rs
Normal file
270
src/detections/pivot.rs
Normal file
@@ -0,0 +1,270 @@
|
||||
use hashbrown::HashMap;
|
||||
use hashbrown::HashSet;
|
||||
use lazy_static::lazy_static;
|
||||
use serde_json::Value;
|
||||
use std::sync::RwLock;
|
||||
|
||||
use crate::detections::configs;
|
||||
use crate::detections::utils::get_serde_number_to_string;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PivotKeyword {
|
||||
pub keywords: HashSet<String>,
|
||||
pub fields: HashSet<String>,
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
pub static ref PIVOT_KEYWORD: RwLock<HashMap<String, PivotKeyword>> =
|
||||
RwLock::new(HashMap::new());
|
||||
}
|
||||
|
||||
impl Default for PivotKeyword {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl PivotKeyword {
|
||||
pub fn new() -> PivotKeyword {
|
||||
PivotKeyword {
|
||||
keywords: HashSet::new(),
|
||||
fields: HashSet::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///levelがlowより大きいレコードの場合、keywordがrecord内にみつかれば、
|
||||
///それをPIVOT_KEYWORD.keywordsに入れる。
|
||||
pub fn insert_pivot_keyword(event_record: &Value) {
|
||||
//levelがlow異常なら続ける
|
||||
let mut is_exist_event_key = false;
|
||||
let mut tmp_event_record: &Value = event_record;
|
||||
for s in ["Event", "System", "Level"] {
|
||||
if let Some(record) = tmp_event_record.get(s) {
|
||||
is_exist_event_key = true;
|
||||
tmp_event_record = record;
|
||||
}
|
||||
}
|
||||
if is_exist_event_key {
|
||||
let hash_value = get_serde_number_to_string(tmp_event_record);
|
||||
|
||||
if hash_value.is_some() && hash_value.as_ref().unwrap() == "infomational"
|
||||
|| hash_value.as_ref().unwrap() == "undefined"
|
||||
|| hash_value.as_ref().unwrap() == "-"
|
||||
{
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
for (_, pivot) in PIVOT_KEYWORD.write().unwrap().iter_mut() {
|
||||
for field in &pivot.fields {
|
||||
if let Some(array_str) = configs::EVENTKEY_ALIAS.get_event_key(&String::from(field)) {
|
||||
let split: Vec<&str> = array_str.split('.').collect();
|
||||
let mut is_exist_event_key = false;
|
||||
let mut tmp_event_record: &Value = event_record;
|
||||
for s in split {
|
||||
if let Some(record) = tmp_event_record.get(s) {
|
||||
is_exist_event_key = true;
|
||||
tmp_event_record = record;
|
||||
}
|
||||
}
|
||||
if is_exist_event_key {
|
||||
let hash_value = get_serde_number_to_string(tmp_event_record);
|
||||
|
||||
if let Some(value) = hash_value {
|
||||
if value == "-" || value == "127.0.0.1" || value == "::1" {
|
||||
continue;
|
||||
}
|
||||
pivot.keywords.insert(value);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::detections::configs::load_pivot_keywords;
|
||||
use crate::detections::pivot::insert_pivot_keyword;
|
||||
use crate::detections::pivot::PIVOT_KEYWORD;
|
||||
use serde_json;
|
||||
|
||||
//PIVOT_KEYWORDはグローバルなので、他の関数の影響も考慮する必要がある。
|
||||
#[test]
|
||||
fn insert_pivot_keyword_local_ip4() {
|
||||
load_pivot_keywords("test_files/config/pivot_keywords.txt");
|
||||
let record_json_str = r#"
|
||||
{
|
||||
"Event": {
|
||||
"System": {
|
||||
"Level": "high"
|
||||
},
|
||||
"EventData": {
|
||||
"IpAddress": "127.0.0.1"
|
||||
}
|
||||
}
|
||||
}"#;
|
||||
insert_pivot_keyword(&serde_json::from_str(record_json_str).unwrap());
|
||||
|
||||
assert!(!PIVOT_KEYWORD
|
||||
.write()
|
||||
.unwrap()
|
||||
.get_mut("Ip Addresses")
|
||||
.unwrap()
|
||||
.keywords
|
||||
.contains("127.0.0.1"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_pivot_keyword_ip4() {
|
||||
load_pivot_keywords("test_files/config/pivot_keywords.txt");
|
||||
let record_json_str = r#"
|
||||
{
|
||||
"Event": {
|
||||
"System": {
|
||||
"Level": "high"
|
||||
},
|
||||
"EventData": {
|
||||
"IpAddress": "10.0.0.1"
|
||||
}
|
||||
}
|
||||
}"#;
|
||||
insert_pivot_keyword(&serde_json::from_str(record_json_str).unwrap());
|
||||
|
||||
assert!(PIVOT_KEYWORD
|
||||
.write()
|
||||
.unwrap()
|
||||
.get_mut("Ip Addresses")
|
||||
.unwrap()
|
||||
.keywords
|
||||
.contains("10.0.0.1"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_pivot_keyword_ip_empty() {
|
||||
load_pivot_keywords("test_files/config/pivot_keywords.txt");
|
||||
let record_json_str = r#"
|
||||
{
|
||||
"Event": {
|
||||
"System": {
|
||||
"Level": "high"
|
||||
},
|
||||
"EventData": {
|
||||
"IpAddress": "-"
|
||||
}
|
||||
}
|
||||
}"#;
|
||||
insert_pivot_keyword(&serde_json::from_str(record_json_str).unwrap());
|
||||
|
||||
assert!(!PIVOT_KEYWORD
|
||||
.write()
|
||||
.unwrap()
|
||||
.get_mut("Ip Addresses")
|
||||
.unwrap()
|
||||
.keywords
|
||||
.contains("-"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_pivot_keyword_local_ip6() {
|
||||
load_pivot_keywords("test_files/config/pivot_keywords.txt");
|
||||
let record_json_str = r#"
|
||||
{
|
||||
"Event": {
|
||||
"System": {
|
||||
"Level": "high"
|
||||
},
|
||||
"EventData": {
|
||||
"IpAddress": "::1"
|
||||
}
|
||||
}
|
||||
}"#;
|
||||
insert_pivot_keyword(&serde_json::from_str(record_json_str).unwrap());
|
||||
|
||||
assert!(!PIVOT_KEYWORD
|
||||
.write()
|
||||
.unwrap()
|
||||
.get_mut("Ip Addresses")
|
||||
.unwrap()
|
||||
.keywords
|
||||
.contains("::1"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_pivot_keyword_level_infomational() {
|
||||
load_pivot_keywords("test_files/config/pivot_keywords.txt");
|
||||
let record_json_str = r#"
|
||||
{
|
||||
"Event": {
|
||||
"System": {
|
||||
"Level": "infomational"
|
||||
},
|
||||
"EventData": {
|
||||
"IpAddress": "10.0.0.2"
|
||||
}
|
||||
}
|
||||
}"#;
|
||||
insert_pivot_keyword(&serde_json::from_str(record_json_str).unwrap());
|
||||
|
||||
assert!(!PIVOT_KEYWORD
|
||||
.write()
|
||||
.unwrap()
|
||||
.get_mut("Ip Addresses")
|
||||
.unwrap()
|
||||
.keywords
|
||||
.contains("10.0.0.2"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_pivot_keyword_level_low() {
|
||||
load_pivot_keywords("test_files/config/pivot_keywords.txt");
|
||||
let record_json_str = r#"
|
||||
{
|
||||
"Event": {
|
||||
"System": {
|
||||
"Level": "low"
|
||||
},
|
||||
"EventData": {
|
||||
"IpAddress": "10.0.0.1"
|
||||
}
|
||||
}
|
||||
}"#;
|
||||
insert_pivot_keyword(&serde_json::from_str(record_json_str).unwrap());
|
||||
|
||||
assert!(PIVOT_KEYWORD
|
||||
.write()
|
||||
.unwrap()
|
||||
.get_mut("Ip Addresses")
|
||||
.unwrap()
|
||||
.keywords
|
||||
.contains("10.0.0.1"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_pivot_keyword_level_none() {
|
||||
load_pivot_keywords("test_files/config/pivot_keywords.txt");
|
||||
let record_json_str = r#"
|
||||
{
|
||||
"Event": {
|
||||
"System": {
|
||||
"Level": "-"
|
||||
},
|
||||
"EventData": {
|
||||
"IpAddress": "10.0.0.3"
|
||||
}
|
||||
}
|
||||
}"#;
|
||||
insert_pivot_keyword(&serde_json::from_str(record_json_str).unwrap());
|
||||
|
||||
assert!(!PIVOT_KEYWORD
|
||||
.write()
|
||||
.unwrap()
|
||||
.get_mut("Ip Addresses")
|
||||
.unwrap()
|
||||
.keywords
|
||||
.contains("10.0.0.3"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user