Skip to content

Commit

Permalink
Merge pull request #308 from HotCakeX/Harden-Windows-Security-Module-…
Browse files Browse the repository at this point in the history
…v0.5.1

Harden Windows Security Module v0.5.1
  • Loading branch information
HotCakeX authored Jul 28, 2024
2 parents 71effef + 28924af commit 9c704c8
Show file tree
Hide file tree
Showing 66 changed files with 6,033 additions and 2,510 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# Defining the custom class for CIM instance classes
class CimClassInfo {
[System.String]$ClassName
[System.Collections.Generic.List[System.String]]$Methods
[System.Collections.Generic.List[System.String]]$Properties

CimClassInfo([System.String]$ClassName) {
$this.ClassName = $ClassName
$this.Methods = [System.Collections.Generic.List[System.String]]::new()
$this.Properties = [System.Collections.Generic.List[System.String]]::new()
}
}

# Defining the custom class for namespaces
class NamespaceInfo {
[System.String]$NamespaceName
[System.Collections.Generic.List[CimClassInfo]]$Classes

NamespaceInfo([System.String]$NamespaceName) {
$this.NamespaceName = $NamespaceName
$this.Classes = [System.Collections.Generic.List[CimClassInfo]]::new()
}
}

function Get-NamespaceInfo {
[OutputType([System.Collections.Generic.List[NamespaceInfo]])]
param (
[System.String]$RootNamespace = 'root',
[System.String]$OutputFile = $null
)

# Initialize a list to hold NamespaceInfo objects
$NamespaceInfos = [System.Collections.Generic.List[NamespaceInfo]]::new()

# Initialize a list to hold namespaces
$Namespaces = [System.Collections.Generic.List[System.String]]::new()
$Namespaces.Add($RootNamespace)

# Initialize an index to track the current namespace
$Index = 0

# Loop through namespaces
while ($Index -lt $Namespaces.Count) {
# Get the current namespace
$CurrentNamespace = $Namespaces[$Index]

# Create a new NamespaceInfo object
$NamespaceInfo = [NamespaceInfo]::new($CurrentNamespace)

# Get child namespaces of the current namespace
$ChildNamespaces = Get-CimInstance -Namespace $CurrentNamespace -ClassName __Namespace

# Add child namespaces to the list
foreach ($ChildNamespace in $ChildNamespaces.Name) {
$Namespaces.Add("$CurrentNamespace\$ChildNamespace")
}

# Get classes in the current namespace
$Classes = Get-CimClass -Namespace $CurrentNamespace

# Add classes to the NamespaceInfo object
foreach ($Class in $Classes) {
# Create a new CimClassInfo object
$CimClassInfo = [CimClassInfo]::new($Class.CimClassName)

# Get methods of the class
$Methods = ($Class.CimClassMethods).Name

# Add methods to the CimClassInfo object
foreach ($Method in $Methods) {
$CimClassInfo.Methods.Add($Method)
}

# Get properties of the class
$Properties = ($Class.CimClassProperties).Name

# Add properties to the CimClassInfo object
foreach ($Property in $Properties) {
$CimClassInfo.Properties.Add($Property)
}

# Add the CimClassInfo object to the NamespaceInfo object
$NamespaceInfo.Classes.Add($CimClassInfo)
}

# Add the NamespaceInfo object to the list
$NamespaceInfos.Add($NamespaceInfo)

# Move to the next namespace
$Index++
}

# Export to JSON too if OutputFile is specified
if ($OutputFile) {
$NamespaceInfos | ConvertTo-Json -Depth 100 | Out-File -FilePath $OutputFile
}

return $NamespaceInfos
}

$NamespaceInfo = Get-NamespaceInfo -RootNamespace 'root' -OutputFile 'NamespaceInfo.json'
$NamespaceInfo
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"BYOVD",
"Categoriex",
"catname",
"Cbac",
"CDROM",
"CETCOMPAT",
"CHACHA",
Expand Down Expand Up @@ -157,10 +158,12 @@
"psscriptroot",
"publicfirewall",
"pwsh",
"QWORD",
"Readline",
"rebootlessly",
"Regsvr",
"RELEASENOTES",
"Remoting",
"reparse",
"Requiredbuild",
"REQUIREDSCRIPTS",
Expand All @@ -171,6 +174,7 @@
"SCHTASKS",
"scriptblock",
"scriptblocks",
"Scroller",
"Secureboot",
"securestring",
"Shellv",
Expand Down Expand Up @@ -211,6 +215,7 @@
"WDAC",
"webmail",
"webserver",
"Webshell",
"WHQL",
"Winget",
"Winreg",
Expand All @@ -220,7 +225,8 @@
"WTDS",
"XDRs",
"Zune"
]
],
"dotnetAcquisitionExtension.enablePreviewFeatures": true
},
"extensions": {
"recommendations": [
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
System
System.IO
System.Xml
System.Net
System.Linq
System.Memory
System.Console
System.Windows
System.CodeDom
System.Runtime
System.Net.Http
System.Security
PresentationCore
System.Text.Json
Microsoft.CSharp
System.Threading
System.Management
System.ObjectModel
System.Collections
System.Net.Primitives
PresentationFramework
Expand All @@ -19,13 +24,17 @@ System.Security.Claims
System.Threading.Tasks
System.Linq.Expressions
System.Threading.Thread
System.Xml.ReaderWriter
System.DirectoryServices
Microsoft.Win32.Registry
System.Security.Principal
System.Diagnostics.Process
Microsoft.Win32.Primitives
System.Management.Automation
System.IO.Compression.zipfile
System.Collections.Concurrent
System.Runtime.InteropServices
System.Text.RegularExpressions
System.ComponentModel.Primitives
System.Security.Principal.Windows
System.Security.Principal.Windows
System.DirectoryServices.AccountManagement
Original file line number Diff line number Diff line change
Expand Up @@ -163,12 +163,13 @@ public static void PrepDownloadedFiles(bool GUI = false, string LGPOPath = null,
while (!DownloadsTask.IsCompleted)
{
// Wait for 500 milliseconds before checking again
System.Threading.Thread.Sleep(50);
System.Threading.Thread.Sleep(500);
}

if (DownloadsTask.IsFaulted)
{
throw new Exception(DownloadsTask.Exception.Message);
// throw the exceptions
throw DownloadsTask.Exception;
}
else if (DownloadsTask.IsCompletedSuccessfully)
{
Expand Down
8 changes: 4 additions & 4 deletions Harden-Windows-Security Module/Main files/C#/Categoriex.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@ public string[] GetValidValues()
string[] categoriex = new string[]
{
"MicrosoftDefender", // 55 - 3x(N/A) + Number of Process Mitigations which are dynamically increased
"AttackSurfaceReductionRules", // 20
"BitLockerSettings", // 22 + Number of Non-OS drives which are dynamically increased
"AttackSurfaceReductionRules", // 19 rules
"BitLockerSettings", // 21 + conditional item for Hibernation check (only available on non-VMs) + Number of Non-OS drives which are dynamically increased
"TLSSecurity", // 21
"LockScreen", // 14
"UserAccountControl", // 4
"DeviceGuard", // 8
"WindowsFirewall", // 20
"OptionalWindowsFeatures", // 13
"WindowsFirewall", // 19
"OptionalWindowsFeatures", // 14
"WindowsNetworking", // 9
"MiscellaneousConfigurations", // 17
"WindowsUpdateConfigurations", // 14
Expand Down
65 changes: 40 additions & 25 deletions Harden-Windows-Security Module/Main files/C#/CategoryProcessing.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

namespace HardeningModule
{
// Registry keys are case-insensitive
// https://learn.microsoft.com/en-us/windows/win32/sysinfo/structure-of-the-registry
public class CategoryProcessing
{
// to store the structure of the Registry resources CSV data
Expand All @@ -19,7 +21,8 @@ private class CsvRecord
public string Name { get; set; }
public string FriendlyName { get; set; }
public string Type { get; set; }
public string Value { get; set; }
public List<string> Value { get; set; }
public bool ValueIsList { get; set; }
public string CSPLink { get; set; }
}

Expand Down Expand Up @@ -50,8 +53,16 @@ private static List<CsvRecord> ReadCsv()

string[] fields = ParseCsvLine(line);

if (fields.Length == 9)
if (fields.Length == 10)
{
// Determine if the ValueIsList field is true
bool valueIsList = bool.Parse(fields[8]);

// Split the value field by commas only if ValueIsList is true
List<string> values = valueIsList
? fields[7].Trim('"').Split(',').Select(v => v.Trim()).ToList()
: new List<string> { fields[7].Trim('"') };

records.Add(new CsvRecord
{
Origin = fields[0],
Expand All @@ -61,13 +72,14 @@ private static List<CsvRecord> ReadCsv()
Name = fields[4],
FriendlyName = fields[5],
Type = fields[6],
Value = fields[7],
CSPLink = fields[8]
Value = values,
ValueIsList = valueIsList,
CSPLink = fields[9]
});
}
else
{
throw new ArgumentException("The CSV file is not formatted correctly. There should be 9 fields in each line.");
throw new ArgumentException("The CSV file is not formatted correctly. There should be 10 fields in each line.");
}
}
}
Expand Down Expand Up @@ -137,17 +149,20 @@ public static List<IndividualResult> ProcessCategory(string catName, string meth
List<CsvRecord> csvData = ReadCsv();

// Filter the items based on category and origin
var filteredItems = csvData.Where(item => item.Category == catName && item.Origin == method);
var filteredItems = csvData.Where(item =>
item.Category.Equals(catName, StringComparison.OrdinalIgnoreCase) &&
item.Origin.Equals(method, StringComparison.OrdinalIgnoreCase)
);

// Process each filtered item
foreach (var item in filteredItems)
{
// Initialize valueMatches to "false"
string valueMatches = "false";
// Initialize valueMatches to "False"
string valueMatches = "False";
string regValueStr = null;

// If the type defined in the CSV is HKLM
if (item.Hive == "HKEY_LOCAL_MACHINE")
if (item.Hive.Equals("HKEY_LOCAL_MACHINE", StringComparison.OrdinalIgnoreCase))
{
// Open the registry key in HKEY_LOCAL_MACHINE
using (var key = Registry.LocalMachine.OpenSubKey(item.Key))
Expand Down Expand Up @@ -176,20 +191,20 @@ public static List<IndividualResult> ProcessCategory(string catName, string meth
regValueStr = regValue?.ToString();
}

// Parse the expected value based on its type in the CSV file
object parsedValue = ParseRegistryValue(type: item.Type, value: item.Value);
// Parse the expected values based on their type in the CSV file
var parsedValues = item.Value.Select(v => ParseRegistryValue(type: item.Type, value: v)).ToList();

// Check if the registry value matches the expected value
if (regValue != null && CompareRegistryValues(type: item.Type, regValue: regValue, expectedValue: parsedValue))
// Check if the registry value matches any of the expected values
if (regValue != null && parsedValues.Any(parsedValue => CompareRegistryValues(type: item.Type, regValue: regValue, expectedValue: parsedValue)))
{
// Set valueMatches to "true" if it matches
valueMatches = "true";
// Set valueMatches to "True" if it matches any expected value
valueMatches = "True";
}
}
}
}
// If the type defined in the CSV is HKCU
else if (item.Hive == "HKEY_CURRENT_USER")
else if (item.Hive.Equals("HKEY_CURRENT_USER", StringComparison.OrdinalIgnoreCase))
{
// Open the registry key in HKEY_CURRENT_USER
using (var key = Registry.CurrentUser.OpenSubKey(item.Key))
Expand All @@ -214,14 +229,14 @@ public static List<IndividualResult> ProcessCategory(string catName, string meth
regValueStr = regValue?.ToString();
}

// Parse the expected value based on its type in the CSV file
object parsedValue = ParseRegistryValue(type: item.Type, value: item.Value);
// Parse the expected values based on their type in the CSV file
var parsedValues = item.Value.Select(v => ParseRegistryValue(type: item.Type, value: v)).ToList();

// Check if the registry value matches the expected value
if (regValue != null && CompareRegistryValues(type: item.Type, regValue: regValue, expectedValue: parsedValue))
// Check if the registry value matches any of the expected values
if (regValue != null && parsedValues.Any(parsedValue => CompareRegistryValues(type: item.Type, regValue: regValue, expectedValue: parsedValue)))
{
// Set valueMatches to "true" if it matches
valueMatches = "true";
// Set valueMatches to "True" if it matches any expected value
valueMatches = "True";
}
}
}
Expand Down Expand Up @@ -266,7 +281,7 @@ private static object ParseRegistryValue(string type, string value)
// Will add more types later if needed, e.g., BINARY, MULTI_STRING etc.
default:
{
throw new ArgumentException($"ParseRegistryValue: sUnknown registry value type: {type}");
throw new ArgumentException($"ParseRegistryValue: Unknown registry value type: {type}");
}
}
}
Expand Down Expand Up @@ -299,8 +314,8 @@ private static bool CompareRegistryValues(string type, object regValue, object e
}
case "String":
{
// String values are compared as strings
return regValue.ToString() == expectedValue.ToString();
// String values are compared as strings using ordinal ignore case
return regValue.ToString().Equals(expectedValue.ToString(), StringComparison.OrdinalIgnoreCase);
}
// Will add more types later if needed, e.g., BINARY, MULTI_STRING etc.
default:
Expand Down
Loading

0 comments on commit 9c704c8

Please sign in to comment.