Skip to content

Commit

Permalink
Merge pull request #339 from HotCakeX/Harden-Windows-Security-v.0.6.1
Browse files Browse the repository at this point in the history
Harden Windows Security v.0.6.1
  • Loading branch information
HotCakeX authored Sep 7, 2024
2 parents e16b184 + d264df1 commit 0758eb6
Show file tree
Hide file tree
Showing 63 changed files with 647 additions and 337 deletions.
42 changes: 42 additions & 0 deletions Harden-Windows-Security Module/.editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,45 @@ dotnet_diagnostic.CA1040.severity = error

# CA1816: Dispose methods should call SuppressFinalize
dotnet_diagnostic.CA1816.severity = error

# CA2153: Do Not Catch Corrupted State Exceptions
dotnet_diagnostic.CA2153.severity = error

# CA2300: Do not use insecure deserializer BinaryFormatter
dotnet_diagnostic.CA2300.severity = error

# CA2302: Ensure BinaryFormatter.Binder is set before calling BinaryFormatter.Deserialize
dotnet_diagnostic.CA2302.severity = error

# CA2327: Do not use insecure JsonSerializerSettings
dotnet_diagnostic.CA2327.severity = error

# CA3012: Review code for regex injection vulnerabilities
dotnet_diagnostic.CA3012.severity = error

# CA3011: Review code for DLL injection vulnerabilities
dotnet_diagnostic.CA3011.severity = error

# CA2217: Do not mark enums with FlagsAttribute
dotnet_diagnostic.CA2217.severity = error

# CA1069: Enums values should not be duplicated
dotnet_diagnostic.CA1069.severity = error

# CA1823: Avoid unused private fields
dotnet_diagnostic.CA1823.severity = error

# CA1836: Prefer IsEmpty over Count
dotnet_diagnostic.CA1836.severity = error

# CA2000: Dispose objects before losing scope
dotnet_diagnostic.CA2000.severity = error

# CA1830: Prefer strongly-typed Append and Insert method overloads on StringBuilder
dotnet_diagnostic.CA1830.severity = error

# CA1822: Mark members as static
dotnet_diagnostic.CA1822.severity = error

# CA1050: Declare types in namespaces
dotnet_diagnostic.CA1050.severity = error
4 changes: 2 additions & 2 deletions Harden-Windows-Security Module/Harden Windows Security.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,10 @@

<ItemGroup>
<Content Include="Main files\Resources\**">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Main files\Shared\**">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,5 @@ System.Text.RegularExpressions
System.ComponentModel.Primitives
System.Security.Principal.Windows
System.ComponentModel.TypeConverter
Microsoft.Management.Infrastructure
System.DirectoryServices.AccountManagement
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
using Microsoft.Management.Infrastructure;
using Microsoft.Management.Infrastructure.Options;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Management;
using System.Net.Http;

#nullable enable

Expand Down Expand Up @@ -82,7 +86,6 @@ public enum NetSecurityEnabled : ushort
False = 2
}

[Flags]
public enum NetSecurityProfile : ushort
{
Any = 0,
Expand Down Expand Up @@ -177,37 +180,127 @@ public enum FirewallRuleAction
Disable
}


/// <summary>
/// Enable or disable a firewall rule by DisplayName
/// Can be expanded in the future to provide the full functionality of the built-in cmdlets but for now these are the features that are needed
/// This method can Add or Remove Firewall rules added to the Group Policy store that are responsible for blocking pre-defined country IP Addresses.
/// If the same rules already exist, the method will delete the old ones and recreate new ones in order to let the system have up to date IP ranges.
/// Group Policy is idempotent so it will actively maintain the policies set in it.
/// Another benefit of using LocalStore is that it supports large arrays of IP addresses.
/// The default store which goes to Windows firewall store does not support large arrays and throws: "The array bounds are invalid" error.
/// </summary>
/// <param name="action">Enable/Disable</param>
/// <param name="displayName">The DisplayName of the Firewall rule to Enable/Disable</param>
public static void ManageFirewallRule(FirewallRuleAction action, string displayName)
/// <param name="DisplayName">The DisplayName of the Firewall rule</param>
/// <param name="ListDownloadURL">Link to the GitHub file that contains the IP Addresses</param>
/// <param name="ToAdd">If true, the firewall rules will be added. If false, the firewall rules will only be deleted.</param>
public static void BlockIPAddressListsInGroupPolicy(string DisplayName, string? ListDownloadURL, bool ToAdd)
{
// Convert the enum to the corresponding method name
string methodName = action.ToString();
// An array to hold the IP Address ranges
string[] ipList = Array.Empty<string>();

if (ToAdd)
{
if (ListDownloadURL == null)
{
throw new Exception("ListDownloadURL cannot be null when creating Firewall rules.");
}

Logger.LogMessage("Downloading the IP Address list", LogTypeIntel.Information);
// Download the IP Addresses list
ipList = DownloadIPList(ListDownloadURL);
}

// Establish a CIM session to localhost
using (CimSession cimSession = CimSession.Create(null))
{

// Define options to specify the policy store
using (CimOperationOptions options = new CimOperationOptions())
{
options.SetCustomOption("PolicyStore", "localhost", mustComply: true);

// Delete existing rules with the same name
// it is thorough, any number of firewall rules that match the same name in both inbound and outbound sections of the Group policy firewall rules will be included
DeleteFirewallRules(cimSession, DisplayName, "localhost");

if (ToAdd)
{
// Create inbound and outbound rules
CreateFirewallRule(cimSession, DisplayName, ipList, isInbound: true);
CreateFirewallRule(cimSession, DisplayName, ipList, isInbound: false);
}
}
}

// Define the WMI query to get the firewall rule by DisplayName
// The 'LIKE' operator in WMI queries can be used for case-insensitive matching
string query = $"SELECT * FROM MSFT_NetFirewallRule WHERE UPPER(DisplayName) = '{displayName.ToUpperInvariant()}'";
#region Helper Methods

// Initialize the ManagementScope
ManagementScope scope = new ManagementScope(@"\\.\ROOT\StandardCimv2");
scope.Connect();
// Downloads the IP Address list from the GitHub URLs and converts them into string arrays
string[] DownloadIPList(string URL)
{
// Download the fresh list of IPs
using HttpClient client = new HttpClient();
HttpResponseMessage response = client.GetAsync(URL).Result;
string content = response.Content.ReadAsStringAsync().Result;

// Converts the list from string to string array
return content.Split(new[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries);
}

// Deletes the Firewall rules
void DeleteFirewallRules(CimSession cimSession, string ruleName, string policyStore)
{
// Define custom options for the operation
using (CimOperationOptions options = new CimOperationOptions())
{
options.SetCustomOption("PolicyStore", policyStore, mustComply: true);

// Check for existing rules with the same name and delete them
var existingRules = cimSession.EnumerateInstances("root/StandardCimv2", "MSFT_NetFirewallRule", options)
.Where(instance => instance.CimInstanceProperties["ElementName"].Value.ToString() == ruleName);

foreach (var rule in existingRules)
{
cimSession.DeleteInstance("root/StandardCimv2", rule, options);
Logger.LogMessage($"Deleted existing firewall rule: {ruleName}", LogTypeIntel.Information);
}
}
}

// Execute the WMI query
using (ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, new ObjectQuery(query)))
// Creates the Firewall rules
void CreateFirewallRule(CimSession cimSession, string name, string[] ipList, bool isInbound)
{
using (ManagementObjectCollection results = searcher.Get())
// Define custom options for the operation
using (CimOperationOptions options = new CimOperationOptions())
{
// Iterate through the results and invoke the specified method
foreach (ManagementObject rule in results)
options.SetCustomOption("PolicyStore", "localhost", mustComply: true);

// The LocalAddress and RemoteAddress accept String[] type
// SetCustomOption doesn't support string arrays using 3 overloads variations
// so we have to use the 4 overload variation that allows us to explicitly define the type
string[] emptyArray = Array.Empty<string>();
// Empty array will set it to "Any"
options.SetCustomOption("LocalAddress", emptyArray, Microsoft.Management.Infrastructure.CimType.StringArray, mustComply: true);
options.SetCustomOption("RemoteAddress", ipList, Microsoft.Management.Infrastructure.CimType.StringArray, mustComply: true);

// Define properties for the new firewall rule
using (CimInstance newFirewallRule = new CimInstance("MSFT_NetFirewallRule", "root/StandardCimv2"))
{
rule.InvokeMethod(methodName, null);
newFirewallRule.CimInstanceProperties.Add(CimProperty.Create("ElementName", name, CimFlags.None)); // ElementName is the same as DisplayName
newFirewallRule.CimInstanceProperties.Add(CimProperty.Create("Description", name, CimFlags.None)); // Setting the Description the same value as the DisplayName
newFirewallRule.CimInstanceProperties.Add(CimProperty.Create("Direction", (ushort)(isInbound ? 1 : 2), CimFlags.None)); // 1 for Inbound, 2 for Outbound
newFirewallRule.CimInstanceProperties.Add(CimProperty.Create("Action", (ushort)4, CimFlags.None)); // Block
newFirewallRule.CimInstanceProperties.Add(CimProperty.Create("Enabled", (ushort)1, CimFlags.None)); // Enable
newFirewallRule.CimInstanceProperties.Add(CimProperty.Create("Profiles", (ushort)0, CimFlags.None)); // Any
newFirewallRule.CimInstanceProperties.Add(CimProperty.Create("EdgeTraversalPolicy", (ushort)0, CimFlags.None)); // Block

// Create the instance
cimSession.CreateInstance("root/StandardCimv2", newFirewallRule, options);

Logger.LogMessage($"Successfully created a Firewall rule with the name {name} and the direction {(isInbound ? "Inbound" : "Outbound")}.", LogTypeIntel.Information);
}
}
}

#endregion

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -422,16 +422,18 @@ public static BitLockerVolume GetEncryptedVolumeInfo(string targetVolume)
// Helper method to invoke a method on a WMI class
private static ManagementBaseObject InvokeCimMethod(ManagementBaseObject instance, string methodName, Dictionary<string, object>? parameters)
{
ManagementClass managementClass = new ManagementClass(instance.ClassPath);
var inParams = managementClass.GetMethodParameters(methodName);
if (parameters != null)
using (ManagementClass managementClass = new ManagementClass(instance.ClassPath))
{
foreach (var param in parameters)
var inParams = managementClass.GetMethodParameters(methodName);
if (parameters != null)
{
inParams[param.Key] = param.Value;
foreach (var param in parameters)
{
inParams[param.Key] = param.Value;
}
}
return ((ManagementObject)instance).InvokeMethod(methodName, inParams, null);
}
return ((ManagementObject)instance).InvokeMethod(methodName, inParams, null);
}

// Method to get the drive letters of all volumes on the system, encrypted or not
Expand Down Expand Up @@ -462,10 +464,20 @@ private static ManagementObjectCollection GetCimInstances(string namespacePath,
ManagementScope scope = new ManagementScope(namespacePath);
string queryString = string.IsNullOrEmpty(filter) ? $"SELECT * FROM {className}" : $"SELECT * FROM {className} WHERE {filter}";
ObjectQuery query = new ObjectQuery(queryString);
ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query);
return searcher.Get();

// Declare the collection to return
ManagementObjectCollection result;

using (ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query))
{
// Get the collection from the searcher
result = searcher.Get();
}

return result;
}


// Get the BitLocker info of all of the volumes on the system
public static List<BitLockerVolume> GetAllEncryptedVolumeInfo()
{
Expand Down
Loading

0 comments on commit 0758eb6

Please sign in to comment.