mirror of
https://github.com/Yamato-Security/WELA.git
synced 2025-12-06 17:22:50 +01:00
update
This commit is contained in:
23
WELA.ps1
23
WELA.ps1
@@ -60,13 +60,6 @@ $usableCounts = $usableRules | Group-Object -Property level | ForEach-Object {
|
||||
}
|
||||
}
|
||||
|
||||
$unusableCounts = $unusableRules | Group-Object -Property level | ForEach-Object {
|
||||
[PSCustomObject]@{
|
||||
Level = $_.Name
|
||||
Count = $_.Count
|
||||
}
|
||||
}
|
||||
|
||||
# Step 5: Calculate the percentages
|
||||
$usablePercentages = $usableCounts | ForEach-Object {
|
||||
$total = ($totalCounts | Where-Object Level -match $PSItem.Level | Select-Object -ExpandProperty Count)[0]
|
||||
@@ -78,16 +71,6 @@ $usablePercentages = $usableCounts | ForEach-Object {
|
||||
}
|
||||
}
|
||||
|
||||
$unusablePercentages = $unusableCounts | ForEach-Object {
|
||||
$total = ($totalCounts | Where-Object Level -match $PSItem.Level | Select-Object -ExpandProperty Count)[0]
|
||||
[PSCustomObject]@{
|
||||
Level = $PSItem.Level
|
||||
UnusableCount = $PSItem.Count
|
||||
TotalCount = $total
|
||||
Percentage = "{0:N2}" -f ($PSItem.Count / $total * 100)
|
||||
}
|
||||
}
|
||||
|
||||
# Step 6: Generate the required outputtotal
|
||||
$customOrder = @("critical", "high", "medium", "low", "informational")
|
||||
Write-Output "Detection rules that can be used on this system versus total possible rules:"
|
||||
@@ -96,12 +79,6 @@ $usablePercentages | ForEach-Object {
|
||||
Write-Output "$($_.Level) rules: $($_.UsableCount) / $($_.TotalCount) ($($_.Percentage)%)"
|
||||
}
|
||||
Write-Output ""
|
||||
Write-Output "Detection rules that cannot be used on this system:"
|
||||
$unusablePercentages = $unusablePercentages | Sort-Object { $customOrder.IndexOf($_.Level) }
|
||||
$unusablePercentages | ForEach-Object {
|
||||
Write-Output "$($_.Level) rules: $($_.UnusableCount) / $($_.TotalCount) ($($_.Percentage)%)"
|
||||
}
|
||||
Write-Output ""
|
||||
Write-Output "Usable detection rules list saved to: UsableRules.csv"
|
||||
Write-Output "Unusable detection rules list saved to: UnusableRules.csv"
|
||||
Write-Output ""
|
||||
|
||||
@@ -2,11 +2,26 @@ use csv::ReaderBuilder;
|
||||
use serde_json::{Value, json};
|
||||
use std::collections::HashSet;
|
||||
use std::error::Error;
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::fs::write;
|
||||
use std::{env, fs};
|
||||
use walkdir::WalkDir;
|
||||
use yaml_rust2::{Yaml, YamlLoader};
|
||||
|
||||
enum Channel {
|
||||
Security,
|
||||
PowerShell,
|
||||
}
|
||||
|
||||
impl Display for Channel {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Channel::Security => write!(f, "sec"),
|
||||
Channel::PowerShell => write!(f, "pwsh"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn list_yml_files(dir: &str) -> Vec<String> {
|
||||
let mut yml_files = Vec::new();
|
||||
for entry in WalkDir::new(dir).into_iter().filter_map(|e| e.ok()) {
|
||||
@@ -58,58 +73,62 @@ fn extract_event_ids(yaml: &Yaml, event_ids: &mut HashSet<String>) {
|
||||
}
|
||||
}
|
||||
|
||||
fn contains_channel_security(yaml: &Yaml) -> bool {
|
||||
fn contains_channel_security(yaml: &Yaml) -> Option<Channel> {
|
||||
match yaml {
|
||||
Yaml::Hash(hash) => {
|
||||
for (key, value) in hash {
|
||||
if key.as_str() == Some("Channel") && value.as_str() == Some("Security") {
|
||||
return true;
|
||||
}
|
||||
if contains_channel_security(value) {
|
||||
return true;
|
||||
if key.as_str() == Some("Channel") {
|
||||
match value.as_str() {
|
||||
Some("Security") => return Some(Channel::Security),
|
||||
Some("Microsoft-Windows-PowerShell/Operational")
|
||||
| Some("PowerShellCore/Operational")
|
||||
| Some("Windows PowerShell") => return Some(Channel::PowerShell),
|
||||
_ => None::<Channel>,
|
||||
};
|
||||
} else if let Some(channel) = contains_channel_security(value) {
|
||||
return Some(channel);
|
||||
}
|
||||
}
|
||||
}
|
||||
Yaml::Array(array) => {
|
||||
for item in array {
|
||||
if contains_channel_security(item) {
|
||||
return true;
|
||||
if let Some(channel) = contains_channel_security(item) {
|
||||
return Some(channel);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
false
|
||||
None
|
||||
}
|
||||
|
||||
fn parse_yaml(doc: Yaml, eid_subcategory_pair: &Vec<(String, String)>) -> Option<Value> {
|
||||
if !contains_channel_security(&doc["detection"]) {
|
||||
return None;
|
||||
}
|
||||
let uuid = doc["id"].as_str().unwrap_or("");
|
||||
let title = doc["title"].as_str().unwrap_or("");
|
||||
let desc = doc["description"].as_str().unwrap_or("");
|
||||
let level = doc["level"].as_str().unwrap_or("");
|
||||
let mut event_ids = HashSet::new();
|
||||
let mut subcategories = HashSet::new();
|
||||
extract_event_ids(&doc, &mut event_ids);
|
||||
for event_id in &event_ids {
|
||||
for (eid, subcategory) in eid_subcategory_pair {
|
||||
if eid == event_id {
|
||||
subcategories.insert(subcategory.clone());
|
||||
if let Some(ch) = contains_channel_security(&doc["detection"]) {
|
||||
let uuid = doc["id"].as_str().unwrap_or("");
|
||||
let title = doc["title"].as_str().unwrap_or("");
|
||||
let level = doc["level"].as_str().unwrap_or("");
|
||||
let mut event_ids = HashSet::new();
|
||||
let mut subcategories = HashSet::new();
|
||||
extract_event_ids(&doc, &mut event_ids);
|
||||
for event_id in &event_ids {
|
||||
for (eid, subcategory) in eid_subcategory_pair {
|
||||
if eid == event_id {
|
||||
subcategories.insert(subcategory.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
let event_ids: Vec<String> = event_ids.into_iter().collect();
|
||||
let subcategories: Vec<String> = subcategories.into_iter().collect();
|
||||
return Some(json!({
|
||||
"id": uuid,
|
||||
"title": title,
|
||||
"channel": ch.to_string(),
|
||||
"level": level,
|
||||
"event_ids": event_ids,
|
||||
"subcategory_guids": subcategories
|
||||
}));
|
||||
}
|
||||
let event_ids: Vec<String> = event_ids.into_iter().collect();
|
||||
let subcategories: Vec<String> = subcategories.into_iter().collect();
|
||||
Some(json!({
|
||||
"id": uuid,
|
||||
"title": title,
|
||||
"description": desc,
|
||||
"level": level,
|
||||
"event_ids": event_ids,
|
||||
"subcategory_guids": subcategories
|
||||
}))
|
||||
None
|
||||
}
|
||||
|
||||
fn load_event_id_guid_pairs(file_path: &str) -> Result<Vec<(String, String)>, Box<dyn Error>> {
|
||||
|
||||
Reference in New Issue
Block a user