From c02c55cb6753f3b95a48472efc4ab0561356030e Mon Sep 17 00:00:00 2001 From: Violet Hansen Date: Thu, 2 Jan 2025 19:30:32 +0200 Subject: [PATCH] Removed dependency on WDACConfig No longer depends on WDACConfig, everything is included natively. --- .../{CiToolRunner.cs => CiToolHelper.cs} | 214 ++++++++++++++++-- .../C#/Others/PolicyToCIPConverter.cs | 28 +++ .../DangerousScriptHostsBlocking.cs | 46 ++-- .../DownloadsDefenseMeasures.cs | 193 +++++++++------- .../Main files/C#/Types/CiPolicyInfo.cs | 22 -- .../UnprotectWindowsSecurity.cs | 6 +- .../Dangerous-Script-Hosts-Blocking.xml | 20 +- .../Resources/Downloads-Defense-Measures.xml | 70 ++++++ 8 files changed, 434 insertions(+), 165 deletions(-) rename Harden-Windows-Security Module/Main files/C#/Others/{CiToolRunner.cs => CiToolHelper.cs} (58%) create mode 100644 Harden-Windows-Security Module/Main files/C#/Others/PolicyToCIPConverter.cs delete mode 100644 Harden-Windows-Security Module/Main files/C#/Types/CiPolicyInfo.cs create mode 100644 Harden-Windows-Security Module/Main files/Resources/Downloads-Defense-Measures.xml diff --git a/Harden-Windows-Security Module/Main files/C#/Others/CiToolRunner.cs b/Harden-Windows-Security Module/Main files/C#/Others/CiToolHelper.cs similarity index 58% rename from Harden-Windows-Security Module/Main files/C#/Others/CiToolRunner.cs rename to Harden-Windows-Security Module/Main files/C#/Others/CiToolHelper.cs index 7b537c29e..59182fa65 100644 --- a/Harden-Windows-Security Module/Main files/C#/Others/CiToolRunner.cs +++ b/Harden-Windows-Security Module/Main files/C#/Others/CiToolHelper.cs @@ -3,18 +3,43 @@ using System.Diagnostics; using System.Globalization; using System.IO; +using System.Text; using System.Text.Json; +// The following code is exact mirror of the same code in AppControl Manager's codebase namespace HardenWindowsSecurity; -internal static class CiToolRunner +// Class to represent a policy with various attributes +public sealed class CiPolicyInfo +{ + public string? PolicyID { get; set; } // Unique identifier for the policy + public string? BasePolicyID { get; set; } // Identifier for the base policy + public string? FriendlyName { get; set; } // Human-readable name of the policy + public Version? Version { get; set; } // Version object representing the policy version + public string? VersionString { get; set; } // Original version string from the policy data + public bool IsSystemPolicy { get; set; } // Indicates if it's a system policy + public bool IsSignedPolicy { get; set; } // Indicates if the policy is signed + public bool IsOnDisk { get; set; } // Indicates if the policy is present on disk + public bool IsEnforced { get; set; } // Indicates if the policy is enforced + public bool IsAuthorized { get; set; } // Indicates if the policy is authorized + internal List? PolicyOptions { get; set; } // List of options or settings related to the policy + + + // A property to format PolicyOptions as a comma-separated string + public string PolicyOptionsDisplay => PolicyOptions is not null ? string.Join(", ", PolicyOptions) : string.Empty; +} + + +// This class contains all the necessary logics to interact with CiTool.exe +// Any code that wants to use CiTool.exe must go through this class rather than contacting it directly +internal static class CiToolHelper { /// /// Converts a 64-bit unsigned integer into a version type, used for converting the numbers from CiTool.exe output to proper versions. /// /// The 64-bit unsigned integer as a string. /// The parsed version - private static Version Measure(string number) + internal static Version Measure(string number) { try { @@ -45,27 +70,21 @@ private static Version Measure(string number) catch (Exception ex) { // Handle errors by printing an error message and returning a default version of 0.0.0.0 - Logger.LogMessage($"Error converting number to version: {ex.Message}", LogTypeIntel.Error); + Logger.LogMessage($"Error converting number to version: {ex.Message}", LogTypeIntel.Information); return new Version(0, 0, 0, 0); } } - internal static JsonSerializerOptions Options => new() - { - // Ignore case when matching JSON property names - PropertyNameCaseInsensitive = true, - }; - /// - /// Gets a list of AppControl policies on the system with filtering + /// Gets a list of App Control policies on the system with filtering /// /// Will include System policies in the output /// Will include Base policies in the output /// Will include Supplemental policies in the output /// /// - internal static List RunCiTool(JsonSerializerOptions options, bool SystemPolicies = false, bool BasePolicies = false, bool SupplementalPolicies = false) + internal static List GetPolicies(bool SystemPolicies = false, bool BasePolicies = false, bool SupplementalPolicies = false) { // Create an empty list of Policy objects to return at the end List policies = []; @@ -83,9 +102,8 @@ internal static List RunCiTool(JsonSerializerOptions options, bool CreateNoWindow = true // Run the process without creating a window }; - // Start the process and capture the output - using Process? process = Process.Start(processStartInfo) ?? throw new InvalidOperationException("There was a problem running the CiTool.exe in the RunCiTool method."); + using Process? process = Process.Start(processStartInfo) ?? throw new InvalidOperationException("There was a problem running the CiTool.exe in the GetPolicies method."); // Read all output as a string string jsonOutput = process.StandardOutput.ReadToEnd(); @@ -95,12 +113,13 @@ internal static List RunCiTool(JsonSerializerOptions options, bool if (process.ExitCode != 0) { - // Throw an exception with the error message throw new InvalidOperationException($"Command execution failed with error code {process.ExitCode}"); } - // Deserialize the JSON into a JsonElement for easy traversal - var rootElement = JsonSerializer.Deserialize(jsonOutput, options); + // Parse the JSON into a JsonElement for easy traversal + using JsonDocument document = JsonDocument.Parse(Encoding.UTF8.GetBytes(jsonOutput)); + + JsonElement rootElement = document.RootElement; // If "Policies" property exists and is an array, start processing each policy if (rootElement.TryGetProperty("Policies", out JsonElement policiesElement) && policiesElement.ValueKind == JsonValueKind.Array) @@ -145,9 +164,9 @@ internal static List RunCiTool(JsonSerializerOptions options, bool /// - /// Removes a deployed AppControl policy from the system + /// Removes a deployed App Control policy from the system /// - /// the GUID which is the policy ID of the policy to be removed, with the curly brackets {} wrapped with double quotes "" + /// The GUID which is the policy ID of the policy to be removed. /// internal static void RemovePolicy(string policyId) { @@ -156,6 +175,11 @@ internal static void RemovePolicy(string policyId) throw new ArgumentException("Policy ID cannot be null or empty.", nameof(policyId)); } + // Remove any curly brackets or double quotes from the policy ID + // They will be added automatically later by the method + policyId = policyId.Trim('"', '"'); + policyId = policyId.Trim('{', '}'); + // Combine the path to CiTool.exe using the system's special folder path string ciToolPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), "CiTool.exe"); @@ -163,29 +187,171 @@ internal static void RemovePolicy(string policyId) ProcessStartInfo processStartInfo = new() { FileName = ciToolPath, - Arguments = $"--remove-policy \"{{{policyId}}}\" -json", // Arguments to remove a AppControl policy + Arguments = $"--remove-policy \"{{{policyId}}}\" -json", // Arguments to remove an App Control policy RedirectStandardOutput = true, // Capture the standard output UseShellExecute = false, // Do not use the OS shell to start the process CreateNoWindow = true // Run the process without creating a window }; // Start the process and capture the output - using Process? process = Process.Start(processStartInfo) ?? throw new InvalidOperationException("There was a problem running the CiTool.exe in the RunCiTool method."); + using Process? process = Process.Start(processStartInfo) ?? throw new InvalidOperationException("There was a problem running the CiTool.exe in the GetPolicies method."); - // Don't need the output if successful - _ = process.StandardOutput.ReadToEnd(); + // Read all output as a string + string jsonOutput = process.StandardOutput.ReadToEnd(); // Wait for the process to complete process.WaitForExit(); if (process.ExitCode != 0) { - // Throw an exception with the error message - throw new InvalidOperationException($"Command execution failed with error code {process.ExitCode}"); + throw new InvalidOperationException($"Command execution failed with error code {process.ExitCode}. Output: {jsonOutput}"); + } + } + + + + + /// + /// Removes multiple deployed App Control policy from the system + /// + /// The GUIDs which are the policy IDs of the policies to be removed. + /// + internal static void RemovePolicy(List policyIds) + { + + foreach (string policyId in policyIds) + { + + if (string.IsNullOrWhiteSpace(policyId)) + { + continue; + } + + // Remove any curly brackets or double quotes from the policy ID + // They will be added automatically later by the method + string ID = policyId.Trim('"', '"'); + ID = ID.Trim('{', '}'); + + // Combine the path to CiTool.exe using the system's special folder path + string ciToolPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), "CiTool.exe"); + + // Set up the process start info to run CiTool.exe with necessary arguments + ProcessStartInfo processStartInfo = new() + { + FileName = ciToolPath, + Arguments = $"--remove-policy \"{{{ID}}}\" -json", // Arguments to remove an App Control policy + RedirectStandardOutput = true, // Capture the standard output + UseShellExecute = false, // Do not use the OS shell to start the process + CreateNoWindow = true // Run the process without creating a window + }; + + // Start the process and capture the output + using Process? process = Process.Start(processStartInfo) ?? throw new InvalidOperationException("There was a problem running the CiTool.exe in the GetPolicies method."); + + // Read all output as a string + string jsonOutput = process.StandardOutput.ReadToEnd(); + + // Wait for the process to complete + process.WaitForExit(); + + if (process.ExitCode != 0) + { + throw new InvalidOperationException($"Command execution failed with error code {process.ExitCode}. Output: {jsonOutput}"); + } + } + } + + + + /// + /// Deploys a Code Integrity policy on the system by accepting the .CIP file path + /// + /// + /// + /// + /// + internal static void UpdatePolicy(string CipPath) + { + if (string.IsNullOrWhiteSpace(CipPath)) + { + throw new ArgumentException("CipPath cannot be null or empty.", nameof(CipPath)); + } + + if (!File.Exists(CipPath)) + { + throw new FileNotFoundException($"The file '{CipPath}' does not exist.", CipPath); + } + + // Combine the path to CiTool.exe using the system's special folder path + string ciToolPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), "CiTool.exe"); + + Logger.LogMessage($"Deploying the following CIP file: {CipPath}", LogTypeIntel.Information); + + // Set up the process start info to run CiTool.exe with necessary arguments + ProcessStartInfo processStartInfo = new() + { + FileName = ciToolPath, + Arguments = $"--update-policy \"{CipPath}\" -json", // Arguments to update the App Control policy + RedirectStandardOutput = true, // Capture the standard output + UseShellExecute = false, // Do not use the OS shell to start the process + CreateNoWindow = true // Run the process without creating a window + }; + + // Start the process and capture the output + using Process? process = Process.Start(processStartInfo) ?? throw new InvalidOperationException("There was a problem running the CiTool.exe in the UpdatePolicy method."); + + // Read all output as a string + string jsonOutput = process.StandardOutput.ReadToEnd(); + + // Wait for the process to complete + process.WaitForExit(); + + if (process.ExitCode != 0) + { + throw new InvalidOperationException($"Command execution failed with error code {process.ExitCode}. Output: {jsonOutput}"); + } + } + + + /// + /// Refreshes the currently deployed policies on the system + /// + /// + internal static void RefreshPolicy() + { + // Combine the path to CiTool.exe using the system's special folder path + string ciToolPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), "CiTool.exe"); + + // Set up the process start info to run CiTool.exe with the refresh argument + ProcessStartInfo processStartInfo = new() + { + FileName = ciToolPath, + Arguments = "--refresh -json", // Arguments to refresh App Control policies + RedirectStandardOutput = true, // Capture the standard output + UseShellExecute = false, // Do not use the OS shell to start the process + CreateNoWindow = true // Run the process without creating a window + }; + + // Start the process and capture the output + using Process? process = Process.Start(processStartInfo) ?? throw new InvalidOperationException("There was a problem running the CiTool.exe in the RefreshPolicy method."); + + // Read all output as a string + string jsonOutput = process.StandardOutput.ReadToEnd(); + + // Wait for the process to complete + process.WaitForExit(); + + if (process.ExitCode != 0) + { + throw new InvalidOperationException($"Command execution failed with error code {process.ExitCode}. Output: {jsonOutput}"); } } + } + + + // Extension methods for JsonElement to simplify retrieving properties with default values internal static class JsonElementExtensions { diff --git a/Harden-Windows-Security Module/Main files/C#/Others/PolicyToCIPConverter.cs b/Harden-Windows-Security Module/Main files/C#/Others/PolicyToCIPConverter.cs new file mode 100644 index 000000000..5c3c3da57 --- /dev/null +++ b/Harden-Windows-Security Module/Main files/C#/Others/PolicyToCIPConverter.cs @@ -0,0 +1,28 @@ +namespace HardenWindowsSecurity; + +internal static class PolicyToCIPConverter +{ + /// + /// Converts a XML policy file to CIP binary file using the ConvertFrom-CIPolicy cmdlet of the ConfigCI module + /// + /// + /// + internal static void Convert(string XmlFilePath, string BinaryFilePath) + { + + // Escape the output policy path for PowerShell + string escapedXMLFile = $"\\\"{XmlFilePath}\\\""; + + // Escape the output policy path for PowerShell + string escapedOutputCIP = $"\\\"{BinaryFilePath}\\\""; + + // Construct the PowerShell script + string script = $"ConvertFrom-CIPolicy -XmlFilePath {escapedXMLFile} -BinaryFilePath {escapedOutputCIP}"; + + Logger.LogMessage($"PowerShell code that will be executed: {script}", LogTypeIntel.Information); + + // Execute the command + ProcessStarter.RunCommand("powershell.exe", $"-NoProfile -Command \"{script}\""); + } + +} diff --git a/Harden-Windows-Security Module/Main files/C#/Protect Methods/DangerousScriptHostsBlocking.cs b/Harden-Windows-Security Module/Main files/C#/Protect Methods/DangerousScriptHostsBlocking.cs index 6becae5f6..5be31aa06 100644 --- a/Harden-Windows-Security Module/Main files/C#/Protect Methods/DangerousScriptHostsBlocking.cs +++ b/Harden-Windows-Security Module/Main files/C#/Protect Methods/DangerousScriptHostsBlocking.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.IO; namespace HardenWindowsSecurity; @@ -6,7 +7,7 @@ namespace HardenWindowsSecurity; public static partial class DownloadsDefenseMeasures { /// - /// Blocks certain dangerous script hosts using AppControl policy + /// Blocks certain dangerous script hosts using App Control policy /// /// public static void DangerousScriptHostsBlocking() @@ -21,22 +22,31 @@ public static void DangerousScriptHostsBlocking() string CIPPath = Path.Combine(GlobalVars.WorkingDir, "Dangerous-Script-Hosts-Blocking.cip"); string XMLPath = Path.Combine(GlobalVars.path, "Resources", "Dangerous-Script-Hosts-Blocking.xml"); - // Use string interpolation without the @ symbol for multiline - string script = $@" - $CurrentBasePolicyNames = [System.Collections.Generic.HashSet[System.String]]@( - ((&""$env:SystemDrive\Windows\System32\CiTool.exe"" -lp -json | ConvertFrom-Json).Policies | - Where-Object -FilterScript {{ ($_.IsSystemPolicy -ne 'True') -and ($_.PolicyID -eq $_.BasePolicyID) }}).FriendlyName - ) - - if (($null -eq $CurrentBasePolicyNames) -or (-NOT ($CurrentBasePolicyNames.Contains('Dangerous-Script-Hosts-Blocking')))) {{ - $null = ConvertFrom-CIPolicy -XmlFilePath '{XMLPath}' -BinaryFilePath '{CIPPath}' - $null = CiTool.exe --update-policy '{CIPPath}' -json - }} - else {{ - Write-Verbose -Message 'The Dangerous-Script-Hosts-Blocking policy is already deployed' -Verbose - }} - "; - - _ = PowerShellExecutor.ExecuteScript(script); + // Run the CiTool and retrieve a list of base policies + List policies = CiToolHelper.GetPolicies(SystemPolicies: false, BasePolicies: true, SupplementalPolicies: false); + + bool isFound = false; + + // loop over all policies + foreach (CiPolicyInfo item in policies) + { + // find the policy with the right name + if (string.Equals(item.FriendlyName, "Dangerous-Script-Hosts-Blocking", StringComparison.OrdinalIgnoreCase)) + { + isFound = true; + break; + } + } + + // If the Dangerous-Script-Hosts-Blocking is not deployed + if (!isFound) + { + PolicyToCIPConverter.Convert(XMLPath, CIPPath); + CiToolHelper.UpdatePolicy(CIPPath); + } + else + { + Logger.LogMessage("The Dangerous-Script-Hosts-Blocking policy is already deployed", LogTypeIntel.Information); + } } } diff --git a/Harden-Windows-Security Module/Main files/C#/Protect Methods/DownloadsDefenseMeasures.cs b/Harden-Windows-Security Module/Main files/C#/Protect Methods/DownloadsDefenseMeasures.cs index f87415693..6451e7790 100644 --- a/Harden-Windows-Security Module/Main files/C#/Protect Methods/DownloadsDefenseMeasures.cs +++ b/Harden-Windows-Security Module/Main files/C#/Protect Methods/DownloadsDefenseMeasures.cs @@ -1,97 +1,128 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Runtime.InteropServices; +using System.Xml; + namespace HardenWindowsSecurity; public static partial class DownloadsDefenseMeasures { + + // GUID for the Downloads folder + private static Guid FolderDownloads = new("374DE290-123F-4565-9164-39C4925E467B"); + + [DllImport("shell32.dll")] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + private static extern int SHGetKnownFolderPath( + ref Guid rfid, uint dwFlags, IntPtr hToken, out IntPtr ppszPath); + + /// /// Prevents executables originating from the Downloads folder from running, using AppControl policy /// public static void Invoke() { + if (GlobalVars.path is null) + { + throw new ArgumentNullException("GlobalVars.path cannot be null."); + } ChangePSConsoleTitle.Set("🎇 Downloads Defense Measures"); Logger.LogMessage("Running the Downloads Defense Measures category", LogTypeIntel.Information); - // PowerShell script with embedded {UserValue} directly in the string using @"" - string script = $@" -$VerbosePreference = 'Continue' -$script:ErrorActionPreference = 'Stop' - -#region Installation And Update - -# a flag indicating the WDACConfig module must be downloaded and installed on the system -[System.Boolean]$ShouldInstallWDACConfigModule = $true - -Write-Verbose -Message 'Getting the latest available version number of the WDACConfig module' -[System.Version]$WDACConfigLatestVersion = Invoke-RestMethod -Uri 'https://raw.githubusercontent.com/HotCakeX/Harden-Windows-Security/main/WDACConfig/version.txt' - -Write-Verbose -Message 'Getting the latest available version of the WDACConfig module from the local system, if it exists' -[System.Management.Automation.PSModuleInfo]$WDACConfigModuleLocalStatus = Get-Module -ListAvailable -Name 'WDACConfig' -Verbose:$false | Sort-Object -Property Version -Descending | Select-Object -First 1 - -# If the WDACConfig module is already installed on the system and its version is greater than or equal to the latest version available on GitHub repo then don't install it again -if (($null -ne $WDACConfigModuleLocalStatus) -and ($WDACConfigModuleLocalStatus.count -gt 0)) {{ - if ($WDACConfigModuleLocalStatus.Version -ge $WDACConfigLatestVersion) {{ - $ShouldInstallWDACConfigModule = $false - Write-Verbose -Message 'Skipping WDACConfig module installation, it is already installed.' - }} - else {{ - [System.String]$ReasonToInstallWDACConfigModule = ""the installed WDACConfig module version $($WDACConfigModuleLocalStatus.Version) is less than the latest available version $($WDACConfigLatestVersion)"" - Write-Verbose -Message 'Removing the WDACConfig module' - try {{ - $null = Uninstall-Module -Name 'WDACConfig' -Force -Verbose:$false -AllVersions - }} - catch {{}} - }} -}} -else {{ - [System.String]$ReasonToInstallWDACConfigModule = 'it is not installed on the system' -}} - -if ($ShouldInstallWDACConfigModule) {{ - Write-Verbose -Message ""Installing the WDACConfig module because $ReasonToInstallWDACConfigModule"" - Install-Module -Name 'WDACConfig' -Force -Verbose:$false -Scope 'AllUsers' -RequiredVersion $WDACConfigLatestVersion -}} - -#endregion Installation And Update - -Write-Verbose -Message 'Getting the currently deployed base policy names' -$CurrentBasePolicyNames = [System.Collections.Generic.HashSet[System.String]](((&""$env:SystemDrive\Windows\System32\CiTool.exe"" -lp -json | ConvertFrom-Json).Policies | Where-Object -FilterScript {{ ($_.IsSystemPolicy -ne 'True') -and ($_.PolicyID -eq $_.BasePolicyID) }}).FriendlyName) - -# Only deploy the Downloads-Defense-Measures policy if it is not already deployed -if (($null -eq $CurrentBasePolicyNames) -or (-NOT ($CurrentBasePolicyNames.Contains('Downloads-Defense-Measures')))) {{ - - Write-Verbose -Message 'Detecting the Downloads folder path on system' - [System.IO.FileInfo]$DownloadsPathSystem = (New-Object -ComObject Shell.Application).NameSpace('shell:Downloads').Self.path - Write-Verbose -Message ""The Downloads folder path on system is $DownloadsPathSystem"" - - # Checking if the Edge preferences file exists - if ([System.IO.File]::Exists(""$env:SystemDrive\Users\{GlobalVars.userName}\AppData\Local\Microsoft\Edge\User Data\Default\Preferences"")) {{ - - Write-Verbose -Message 'Detecting the Downloads path in Edge' - [PSCustomObject]$CurrentUserEdgePreference = ConvertFrom-Json -InputObject (Get-Content -Raw -Path ""$env:SystemDrive\Users\{GlobalVars.userName}\AppData\Local\Microsoft\Edge\User Data\Default\Preferences"") - [System.IO.FileInfo]$DownloadsPathEdge = $CurrentUserEdgePreference.savefile.default_directory - - # Ensure there is an Edge browser profile and it was initialized - if ((-NOT [System.String]::IsNullOrWhitespace($DownloadsPathEdge.FullName))) {{ - - Write-Verbose -Message ""The Downloads path in Edge is $DownloadsPathEdge"" - - # Display a warning for now - if ($DownloadsPathEdge.FullName -ne $DownloadsPathSystem.FullName) {{ - Write-Warning -Message ""The Downloads path in Edge ($($DownloadsPathEdge.FullName)) is different than the system's Downloads path ($($DownloadsPathSystem.FullName))"" - }} - }} - }} - - Write-Verbose -Message 'Creating and deploying the Downloads-Defense-Measures policy' - New-DenyWDACConfig -PathWildCards -PolicyName 'Downloads-Defense-Measures' -FolderPath ""$DownloadsPathSystem\*"" -Deploy -Verbose:$Verbose -EmbeddedVerboseOutput - -}} -else {{ - Write-Verbose -Message 'The Downloads-Defense-Measures policy is already deployed' -}} -"; - - _ = PowerShellExecutor.ExecuteScript(script); + string CIPPath = Path.Combine(GlobalVars.WorkingDir, "Downloads-Defense-Measures.cip"); + string XMLPath = Path.Combine(GlobalVars.path, "Resources", "Downloads-Defense-Measures.xml"); + + // The path to use to save the modified XML policy file and deploy it + string XMLPathToDeploy = Path.Combine(GlobalVars.WorkingDir, "Downloads-Defense-Measures.xml"); + + // Run the CiTool and retrieve a list of base policies + List policies = CiToolHelper.GetPolicies(SystemPolicies: false, BasePolicies: true, SupplementalPolicies: false); + + bool isFound = false; + + // loop over all policies + foreach (CiPolicyInfo item in policies) + { + // find the policy with the right name + if (string.Equals(item.FriendlyName, "Downloads-Defense-Measures", StringComparison.OrdinalIgnoreCase)) + { + isFound = true; + break; + } + } + + // If the Downloads-Defense-Measures is not deployed + if (!isFound) + { + + IntPtr pathPtr = IntPtr.Zero; + + string? downloadsPath = null; + + try + { + // Get the System Downloads folder path + int result = SHGetKnownFolderPath(ref FolderDownloads, 0, IntPtr.Zero, out pathPtr); + + if (result is 0) // S_OK + { + downloadsPath = Marshal.PtrToStringUni(pathPtr); + + if (string.IsNullOrWhiteSpace(downloadsPath)) + { + Logger.LogMessage("The downloads folder path was empty, exiting.", LogTypeIntel.Error); + return; + } + + Logger.LogMessage($"Downloads folder path: {downloadsPath}", LogTypeIntel.Information); + } + else + { + Logger.LogMessage("Failed to retrieve Downloads folder path.", LogTypeIntel.Error); + return; + } + } + finally + { + if (pathPtr != IntPtr.Zero) + { + Marshal.FreeCoTaskMem(pathPtr); // Free memory allocated by SHGetKnownFolderPath + } + } + + string pathToUse = downloadsPath + @"\" + '*'; + + XmlDocument doc = new(); + doc.Load(XMLPath); + + XmlNamespaceManager nsmgr = new(doc.NameTable); + nsmgr.AddNamespace("sip", "urn:schemas-microsoft-com:sipolicy"); + + // Find all 'FileRules/Allow' or 'FileRules/Deny' elements + XmlNodeList fileRules = doc.SelectNodes("//sip:FileRules/*[@FilePath]", nsmgr)!; + + foreach (XmlNode node in fileRules) + { + XmlAttribute filePathAttr = node.Attributes!["FilePath"]!; + if (string.Equals(filePathAttr.Value, "To-Be-Detected", StringComparison.OrdinalIgnoreCase)) + { + filePathAttr.Value = pathToUse; + } + } + + // Save the modified XML to the working directory so we don't modify the module's files + doc.Save(XMLPathToDeploy); + + PolicyToCIPConverter.Convert(XMLPathToDeploy, CIPPath); + CiToolHelper.UpdatePolicy(CIPPath); + } + else + { + Logger.LogMessage("The Downloads-Defense-Measures policy is already deployed", LogTypeIntel.Information); + } + } } diff --git a/Harden-Windows-Security Module/Main files/C#/Types/CiPolicyInfo.cs b/Harden-Windows-Security Module/Main files/C#/Types/CiPolicyInfo.cs deleted file mode 100644 index 2b0b2dd6f..000000000 --- a/Harden-Windows-Security Module/Main files/C#/Types/CiPolicyInfo.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace HardenWindowsSecurity; - -/// -/// Class to represent a policy with various attributes -/// -public sealed class CiPolicyInfo -{ - public string? PolicyID { get; set; } // Unique identifier for the policy - public string? BasePolicyID { get; set; } // Identifier for the base policy - public string? FriendlyName { get; set; } // Human-readable name of the policy - public Version? Version { get; set; } // Version object representing the policy version - public string? VersionString { get; set; } // Original version string from the policy data - public bool IsSystemPolicy { get; set; } // Indicates if it's a system policy - public bool IsSignedPolicy { get; set; } // Indicates if the policy is signed - public bool IsOnDisk { get; set; } // Indicates if the policy is present on disk - public bool IsEnforced { get; set; } // Indicates if the policy is enforced - public bool IsAuthorized { get; set; } // Indicates if the policy is authorized - internal List? PolicyOptions { get; set; }// List of options or settings related to the policy -} diff --git a/Harden-Windows-Security Module/Main files/C#/Unprotect Methods/UnprotectWindowsSecurity.cs b/Harden-Windows-Security Module/Main files/C#/Unprotect Methods/UnprotectWindowsSecurity.cs index ed131e54c..f45f28b15 100644 --- a/Harden-Windows-Security Module/Main files/C#/Unprotect Methods/UnprotectWindowsSecurity.cs +++ b/Harden-Windows-Security Module/Main files/C#/Unprotect Methods/UnprotectWindowsSecurity.cs @@ -233,7 +233,7 @@ public static void RemoveExploitMitigations() public static void RemoveAppControlPolicies(bool DownloadsDefenseMeasures, bool DangerousScriptHostsBlocking) { // Run the CiTool and retrieve a list of base policies - List policies = CiToolRunner.RunCiTool(CiToolRunner.Options, SystemPolicies: false, BasePolicies: true, SupplementalPolicies: false); + List policies = CiToolHelper.GetPolicies(SystemPolicies: false, BasePolicies: true, SupplementalPolicies: false); if (DownloadsDefenseMeasures) { @@ -247,7 +247,7 @@ public static void RemoveAppControlPolicies(bool DownloadsDefenseMeasures, bool Logger.LogMessage("Removing the Downloads-Defense-Measures AppControl policy", LogTypeIntel.Information); // remove the policy - CiToolRunner.RemovePolicy(item.PolicyID!); + CiToolHelper.RemovePolicy(item.PolicyID!); } } } @@ -263,7 +263,7 @@ public static void RemoveAppControlPolicies(bool DownloadsDefenseMeasures, bool Logger.LogMessage("Removing the Dangerous-Script-Hosts-Blocking AppControl policy", LogTypeIntel.Information); // remove the policy - CiToolRunner.RemovePolicy(item.PolicyID!); + CiToolHelper.RemovePolicy(item.PolicyID!); } } } diff --git a/Harden-Windows-Security Module/Main files/Resources/Dangerous-Script-Hosts-Blocking.xml b/Harden-Windows-Security Module/Main files/Resources/Dangerous-Script-Hosts-Blocking.xml index ef4f22e4f..d8b5ce154 100644 --- a/Harden-Windows-Security Module/Main files/Resources/Dangerous-Script-Hosts-Blocking.xml +++ b/Harden-Windows-Security Module/Main files/Resources/Dangerous-Script-Hosts-Blocking.xml @@ -31,9 +31,7 @@ - - @@ -41,7 +39,6 @@ - @@ -51,16 +48,15 @@ - - + - + @@ -78,17 +74,7 @@ 2 {9F0581B7-7E1D-4FDD-8D33-6DBE847D3130} {9F0581B7-7E1D-4FDD-8D33-6DBE847D3130} - - - - true - - - - - 022422 - - + Dangerous-Script-Hosts-Blocking diff --git a/Harden-Windows-Security Module/Main files/Resources/Downloads-Defense-Measures.xml b/Harden-Windows-Security Module/Main files/Resources/Downloads-Defense-Measures.xml new file mode 100644 index 000000000..b98c0343a --- /dev/null +++ b/Harden-Windows-Security Module/Main files/Resources/Downloads-Defense-Measures.xml @@ -0,0 +1,70 @@ + + + 1.0.0.0 + {2E07F7E4-194C-4D20-B7C9-6F44A6C5A234} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 2 + {98FC8E9B-A6B1-431C-B2BE-EB23A86B5DE5} + {98FC8E9B-A6B1-431C-B2BE-EB23A86B5DE5} + + + + Downloads-Defense-Measures + + + + \ No newline at end of file