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
|
# Step 5: Calculate the percentages
|
||||||
$usablePercentages = $usableCounts | ForEach-Object {
|
$usablePercentages = $usableCounts | ForEach-Object {
|
||||||
$total = ($totalCounts | Where-Object Level -match $PSItem.Level | Select-Object -ExpandProperty Count)[0]
|
$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
|
# Step 6: Generate the required outputtotal
|
||||||
$customOrder = @("critical", "high", "medium", "low", "informational")
|
$customOrder = @("critical", "high", "medium", "low", "informational")
|
||||||
Write-Output "Detection rules that can be used on this system versus total possible rules:"
|
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 "$($_.Level) rules: $($_.UsableCount) / $($_.TotalCount) ($($_.Percentage)%)"
|
||||||
}
|
}
|
||||||
Write-Output ""
|
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 "Usable detection rules list saved to: UsableRules.csv"
|
||||||
Write-Output "Unusable detection rules list saved to: UnusableRules.csv"
|
Write-Output "Unusable detection rules list saved to: UnusableRules.csv"
|
||||||
Write-Output ""
|
Write-Output ""
|
||||||
|
|||||||
@@ -2,11 +2,26 @@ use csv::ReaderBuilder;
|
|||||||
use serde_json::{Value, json};
|
use serde_json::{Value, json};
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
use std::fmt::{Display, Formatter};
|
||||||
use std::fs::write;
|
use std::fs::write;
|
||||||
use std::{env, fs};
|
use std::{env, fs};
|
||||||
use walkdir::WalkDir;
|
use walkdir::WalkDir;
|
||||||
use yaml_rust2::{Yaml, YamlLoader};
|
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> {
|
fn list_yml_files(dir: &str) -> Vec<String> {
|
||||||
let mut yml_files = Vec::new();
|
let mut yml_files = Vec::new();
|
||||||
for entry in WalkDir::new(dir).into_iter().filter_map(|e| e.ok()) {
|
for entry in WalkDir::new(dir).into_iter().filter_map(|e| e.ok()) {
|
||||||
@@ -58,37 +73,39 @@ 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 {
|
match yaml {
|
||||||
Yaml::Hash(hash) => {
|
Yaml::Hash(hash) => {
|
||||||
for (key, value) in hash {
|
for (key, value) in hash {
|
||||||
if key.as_str() == Some("Channel") && value.as_str() == Some("Security") {
|
if key.as_str() == Some("Channel") {
|
||||||
return true;
|
match value.as_str() {
|
||||||
}
|
Some("Security") => return Some(Channel::Security),
|
||||||
if contains_channel_security(value) {
|
Some("Microsoft-Windows-PowerShell/Operational")
|
||||||
return true;
|
| 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) => {
|
Yaml::Array(array) => {
|
||||||
for item in array {
|
for item in array {
|
||||||
if contains_channel_security(item) {
|
if let Some(channel) = contains_channel_security(item) {
|
||||||
return true;
|
return Some(channel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
false
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_yaml(doc: Yaml, eid_subcategory_pair: &Vec<(String, String)>) -> Option<Value> {
|
fn parse_yaml(doc: Yaml, eid_subcategory_pair: &Vec<(String, String)>) -> Option<Value> {
|
||||||
if !contains_channel_security(&doc["detection"]) {
|
if let Some(ch) = contains_channel_security(&doc["detection"]) {
|
||||||
return None;
|
|
||||||
}
|
|
||||||
let uuid = doc["id"].as_str().unwrap_or("");
|
let uuid = doc["id"].as_str().unwrap_or("");
|
||||||
let title = doc["title"].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 level = doc["level"].as_str().unwrap_or("");
|
||||||
let mut event_ids = HashSet::new();
|
let mut event_ids = HashSet::new();
|
||||||
let mut subcategories = HashSet::new();
|
let mut subcategories = HashSet::new();
|
||||||
@@ -102,14 +119,16 @@ fn parse_yaml(doc: Yaml, eid_subcategory_pair: &Vec<(String, String)>) -> Option
|
|||||||
}
|
}
|
||||||
let event_ids: Vec<String> = event_ids.into_iter().collect();
|
let event_ids: Vec<String> = event_ids.into_iter().collect();
|
||||||
let subcategories: Vec<String> = subcategories.into_iter().collect();
|
let subcategories: Vec<String> = subcategories.into_iter().collect();
|
||||||
Some(json!({
|
return Some(json!({
|
||||||
"id": uuid,
|
"id": uuid,
|
||||||
"title": title,
|
"title": title,
|
||||||
"description": desc,
|
"channel": ch.to_string(),
|
||||||
"level": level,
|
"level": level,
|
||||||
"event_ids": event_ids,
|
"event_ids": event_ids,
|
||||||
"subcategory_guids": subcategories
|
"subcategory_guids": subcategories
|
||||||
}))
|
}));
|
||||||
|
}
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_event_id_guid_pairs(file_path: &str) -> Result<Vec<(String, String)>, Box<dyn Error>> {
|
fn load_event_id_guid_pairs(file_path: &str) -> Result<Vec<(String, String)>, Box<dyn Error>> {
|
||||||
|
|||||||
Reference in New Issue
Block a user