diff --git a/Harden-Windows-Security.ps1 b/Harden-Windows-Security.ps1 index 8ee1a52cd..976369821 100644 --- a/Harden-Windows-Security.ps1 +++ b/Harden-Windows-Security.ps1 @@ -70,7 +70,7 @@ Function P { Add-AppxPackage -Path 'Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle' -DependencyPath 'Microsoft.VCLibs.x64.14.00.Desktop.appx', $MicrosoftUIXamlDownloadedFileName } finally { - try { + try { Remove-Item -Path 'Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle', 'Microsoft.VCLibs.x64.14.00.Desktop.appx', $MicrosoftUIXamlDownloadedFileName -Force Pop-Location } @@ -151,14 +151,7 @@ Function P { Function AppControl { <# .DESCRIPTION - This function installs the AppControl Manager MSIX package on the system. - It does so by securely generating a unique self-signed certificate on the user's system and then using it to sign the MSIX package. - Everything happens locally and no certificate comes from outside of the device. - The certificate is added to the Local Machine's Trust Root Certification Authorities Store with only public keys, ensuring no private key exists to be used to sign anything else. - Its existence with public key is needed so that you can use the AppControl Manager app; without it the app will not launch as it will be considered untrusted by the system. - The 2 files, AppControlManager.dll and AppControlManager.exe inside of the MSIX app installation folder will be added to the Attack Surface Reduction rules exclusion list if they don't already exist in there, so the app will work properly. - The function creates a new directory in the TEMP directory for its operations and it will be deleted at the end. - The function checks for the existence of any previous self-signed certificates generated by it and will remove them if it detects any, guaranteeing no unnecessary leftover remains on the user's system. + Please refer to the provided link for all of the information about this function and detailed overview of the entire process. .PARAMETER MSIXPath The path to the AppControlManager MSIX file. If not provided, the latest MSIX file will be downloaded from the GitHub. It must have the version number and architecture in its file name as provided on GitHub or produced by Visual Studio. .PARAMETER SignTool @@ -174,8 +167,7 @@ Function AppControl { ) $ErrorActionPreference = 'Stop' if (!([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) { - Write-Warning -Message 'Please run this function as an Administrator' - return + Write-Warning -Message 'Please run this function as an Administrator'; return } Write-Verbose -Message 'Detecting the CPU Arch' switch ($Env:PROCESSOR_ARCHITECTURE) { @@ -283,25 +275,11 @@ public static class SecureStringGenerator } if ([System.String]::IsNullOrWhiteSpace($SignTool)) { - - Write-Verbose -Message 'Checking if nuget source is available in PowerShell' - if (-NOT (Get-PackageSource | Where-Object -FilterScript { $_.Name -ieq 'nuget.org' })) { - Write-Verbose -Message 'Registering the nuget.org package source because it was not found in the system.' - $null = Register-PackageSource -Name 'nuget.org' -ProviderName 'NuGet' -Location 'https://api.nuget.org/v3/index.json' - } - - Write-Verbose -Message 'Finding the latest version of the Microsoft.Windows.SDK.BuildTools package from NuGet' - - # Minimum is simply used to limit the number of the fetched packages - [Microsoft.PackageManagement.Packaging.SoftwareIdentity[]]$Package = Find-Package -Name 'Microsoft.Windows.SDK.BuildTools' -Source 'nuget.org' -AllVersions -Force -MinimumVersion '10.0.26100.1' - [Microsoft.PackageManagement.Packaging.SoftwareIdentity]$Package = $Package | Sort-Object -Property { [System.Version]$_.Version } -Descending | Select-Object -First 1 - - Write-Verbose -Message 'Downloading SignTool.exe from NuGet...' - $null = Save-Package -InputObject $Package -Path $WorkingDir -Force - + Write-Verbose -Message 'Finding the latest version of the Microsoft.Windows.SDK.BuildTools package from NuGet and Downloading it' + [System.String]$LatestSignToolVersion = (Invoke-RestMethod -Uri 'https://api.nuget.org/v3-flatcontainer/Microsoft.Windows.SDK.BuildTools/index.json').versions | Select-Object -Last 1 + Invoke-WebRequest -Uri "https://api.nuget.org/v3-flatcontainer/Microsoft.Windows.SDK.BuildTools/${LatestSignToolVersion}/Microsoft.Windows.SDK.BuildTools.${LatestSignToolVersion}.nupkg" -OutFile (Join-Path -Path $WorkingDir -ChildPath 'Microsoft.Windows.SDK.BuildTools.zip') Write-Verbose -Message 'Extracting the nupkg' - Expand-Archive -Path "$WorkingDir\*.nupkg" -DestinationPath $WorkingDir -Force - + Expand-Archive -Path "$WorkingDir\Microsoft.Windows.SDK.BuildTools.zip" -DestinationPath $WorkingDir -Force # Saving .nupkg as .zip to satisfy Windows PowerShell Write-Verbose -Message 'Finding the Signtool.exe path in the extracted directory' [System.String]$SignTool = (Get-Item -Path "$WorkingDir\bin\*\$CPUArch\signtool.exe").FullName } @@ -359,7 +337,6 @@ public static class SecureStringGenerator $PossibleExistingApp | Remove-AppxPackage -AllUsers } } - # Get the details of the currently installed app before attempting to install the new one [System.String]$InstalledAppVersionBefore = $PossibleExistingApp.Version [System.String]$InstalledAppArchitectureBefore = $PossibleExistingApp.Architecture @@ -369,14 +346,11 @@ public static class SecureStringGenerator Write-Verbose -Message "Installing AppControl Manager MSIX Package version '$InstallingAppVersion' with architecture '$InstallingAppArchitecture'" Add-AppPackage -Path $MSIXPath -ForceUpdateFromAnyVersion -DeferRegistrationWhenPackagesAreInUse # -ForceTargetApplicationShutdown will shutdown the application if its open. - Write-Verbose -Message "Finding the certificate that was just created by its thumbprint again from the 'Local Machine/Trusted Root Certification Authorities' store" - [System.Security.Cryptography.X509Certificates.X509Certificate2]$TheCert2 = foreach ($Cert2 in (Get-ChildItem -Path 'Cert:\LocalMachine\Root' -CodeSigningCert)) { - if ($Cert.Thumbprint -eq $NewCertificateThumbprint) { $Cert2 } + Write-Verbose -Message "Finding the certificate that was just created by its thumbprint again from the 'Local Machine/Trusted Root Certification Authorities' store and removing it" + foreach ($Cert2 in (Get-ChildItem -Path 'Cert:\LocalMachine\Root' -CodeSigningCert)) { + if ($Cert.Thumbprint -eq $NewCertificateThumbprint) { $Cert2 | Remove-Item -Force } } - Write-Verbose -Message 'Removing the certificate that has private + public keys' - $TheCert2 | Remove-Item -Force - Write-Verbose -Message "Adding the certificate to the 'Local Machine/Trusted Root Certification Authorities' store with public key only. This safely stores the certificate on your device, ensuring its private key does not exist so cannot be used to sign anything else." $null = Import-Certificate -FilePath $CertificateOutputPath -CertStoreLocation 'Cert:\LocalMachine\Root'