diff --git a/CYBRHardeningCheck/Hardening_HealthCheck_Report.html b/CYBRHardeningCheck/Hardening_HealthCheck_Report.html index a7bc8f3..b4e0698 100644 --- a/CYBRHardeningCheck/Hardening_HealthCheck_Report.html +++ b/CYBRHardeningCheck/Hardening_HealthCheck_Report.html @@ -704,6 +704,11 @@ content:"\f057"; } +details summary.Ignore:before,details ul li div.Ignore:before { +color:#D3D3D3; +content:"\f05e"; +} + @keyframes sweep { 0% { margin-left:-1em; diff --git a/CYBRHardeningCheck/Main.ps1 b/CYBRHardeningCheck/Main.ps1 index d1f1caa..d53a3f2 100644 --- a/CYBRHardeningCheck/Main.ps1 +++ b/CYBRHardeningCheck/Main.ps1 @@ -24,7 +24,7 @@ $global:InDebug = $PSBoundParameters.Debug.IsPresent $global:InVerbose = $PSBoundParameters.Verbose.IsPresent # Script Version -$ScriptVersion = "3.0" +$ScriptVersion = "3.1" # Set Log file path $global:LOG_FILE_PATH = "$ScriptLocation\Hardening_HealthCheck.log" @@ -159,12 +159,12 @@ param( $Item.Output = $(Get-SummaryOutput -Component $Item.Component -Status $Item.Status -Details $Item.Output) } # Count Errors - If($item.Status -ne "Good") + If($item.Status -ne "Good" -and $item.Status -ne "Ignore") { $summary.errors++ } } - $summary.hardeningPercentage = ($summary.errors / $sortedHardeningStatus.count) + $summary.hardeningPercentage = 1-($summary.errors / @($sortedHardeningStatus | Where-Object { $_.Status -ne "Ignore" }).count) # return the Hardening setup and the Summary return @( $sortedHardeningStatus, $summary ) @@ -406,12 +406,20 @@ Function Out-HardeningFolderPath { # Start a background job to search all InstallationAutomation folders and limit it to the maximum number of Total Components found # Might want to add in the future filter on the actual components folder names (e.g. "CPM|PVWA|PSM|AIM") Start-Job -Name FileCollection -ScriptBlock {Get-ChildItem -Path "$ENV:SystemDrive\*" -Include "InstallationAutomation" -Recurse -Directory -ErrorAction SilentlyContinue | Select-Object -First $args[0] } -ArgumentList $TotalComponentsFound | Out-Null - While((Get-Job -Name FileCollection).State -eq "Running") + + # set a timeout of max 2 minutes + $timeout = [TimeSpan]::FromMinutes(2) + While((Get-Job -Name FileCollection | Where-Object { $_.State -eq "Running" -and (($now - $_.PSBeginTime) -lt $timeout)} )) { Write-Progress -Activity "Searching for Hardening folders..." -PercentComplete $x - If($x -eq 100){ $x = 1 } Else { $x += 1 } - } + If($x -eq 100){ $x = 1 } Else { $x += 1 } + } Write-Progress -Activity "Searching for Hardening folders..." -Completed + if((Get-Job -Name FileCollection).State -ne "Completed" -and $x -lt 100) + { + Write-LogMessage -type "Warning" -Msg "Timeout reached - canceling search" + Get-Job -Name FileCollection | Stop-Job + } $allFolders = Receive-Job -Name FileCollection -AutoRemoveJob -Wait Write-LogMessage -Type Debug -Msg "Found $($allFolders.FullName.Count) folders named 'InstallationAutomation'" If($allFolders.FullName.Count -gt 1) @@ -453,7 +461,10 @@ If($ExecutionContext.SessionState.LanguageMode -ne "FullLanguage") } Write-LogMessage -Type Info -MSG "Starting script (v$ScriptVersion)" -Header -LogFile $LOG_FILE_PATH -if($InDebug) { Write-LogMessage -Type Info -MSG "Running in Debug Mode" -LogFile $LOG_FILE_PATH } +if($InDebug) { + Write-LogMessage -Type Info -MSG "Running in Debug Mode, not stopping for debug messages" -LogFile $LOG_FILE_PATH + $DebugPreference = "Continue" +} if($InVerbose) { Write-LogMessage -Type Info -MSG "Running in Verbose Mode" -LogFile $LOG_FILE_PATH } Write-LogMessage -Type Debug -MSG "Running PowerShell version $($PSVersionTable.PSVersion.Major) compatible of versions $($PSVersionTable.PSCompatibleVersions -join ", ")" -LogFile $LOG_FILE_PATH # Verify the Powershell version is compatible diff --git a/CYBRHardeningCheck/PVWA/PVWAHardeningSteps.psm1 b/CYBRHardeningCheck/PVWA/PVWAHardeningSteps.psm1 index 807174f..48cf454 100644 --- a/CYBRHardeningCheck/PVWA/PVWAHardeningSteps.psm1 +++ b/CYBRHardeningCheck/PVWA/PVWAHardeningSteps.psm1 @@ -74,7 +74,7 @@ Function PVWA_IIS_Registry_Shares return $res } catch{ - Write-LogMessage -Type "Error" -Msg "Could not verify PVWA IIS Registry Shares. Error: $(Join-ExceptionMessage $_.Exception)" + Write-LogMessage -Type "Error" -Msg "Could not verify PVWA IIS Registry Shares. Error: $(Join-ExceptionMessage $_.Exception)" [ref]$refOutput.Value = "Could not verify PVWA IIS Registry Shares." return "Bad" } @@ -126,7 +126,7 @@ Function PVWA_IIS_WebDAV return $res } catch{ - Write-LogMessage -Type "Error" -Msg "Could not verify if Web DAV Publishing is installed. Error: $(Join-ExceptionMessage $_.Exception)" + Write-LogMessage -Type "Error" -Msg "Could not verify if Web DAV Publishing is installed. Error: $(Join-ExceptionMessage $_.Exception)" [ref]$refOutput.Value = "Could not verify if Web DAV Publishing is installed." return "Bad" } @@ -166,7 +166,7 @@ Function PVWA_Cryptography_Settings $res = "Good" $iisPath = "iis:\Sites\Default Web Site\PasswordVault" $filter = "/appSettings/add[@key='AdvancedFIPSCryptography']" - $value = "yes" + $value = "value.value" } Process { try{ @@ -177,16 +177,21 @@ Function PVWA_Cryptography_Settings $currentValue = Get-WebConfigurationProperty -PSPath $iisPath -filter $filter -name $value if($null -ne $currentValue) { - if($currentValue.ToLower() -ne $value) + if($currentValue.ToLower() -ne 'yes') { $res = "Warning" - [ref]$refOutput.Value = "AdvancedFIPSCryptography is not properly set in PVWA Configuration. Current value: $currentValue" + [ref]$refOutput.Value = "AdvancedFIPSCryptography is set but does not have the correct value configured. Current value is: $currentValue" + } + else + { + $res = "Good" + [ref]$refOutput.Value = "AdvancedFIPSCryptography is set and has the correct value of 'yes'" } } else { $res = "Warning" - [ref]$refOutput.Value = "AdvancedFIPSCryptography is not set in PVWA Configuration" + [ref]$refOutput.Value = "AdvancedFIPSCryptography key has not been set at the 'PasswordVault' level" } Write-LogMessage -Type Info -Msg "Finish verify if Web DAV Publishing is installed" @@ -194,7 +199,7 @@ Function PVWA_Cryptography_Settings return $res } catch{ - Write-LogMessage -Type "Error" -Msg "Could not verify PVWA Cryptography Mode Settings. Error: $(Join-ExceptionMessage $_.Exception)" + Write-LogMessage -Type "Error" -Msg "Could not verify PVWA Cryptography Mode Settings. Error: $(Join-ExceptionMessage $_.Exception)" [ref]$refOutput.Value = "Could not verify PVWA Cryptography Mode Settings." return "Bad" } @@ -252,7 +257,7 @@ Function PVWA_IIS_MimeTypes return $res } catch{ - Write-LogMessage -Type "Error" -Msg "Could not verify allowed mime types. Error: $(Join-ExceptionMessage $_.Exception)" + Write-LogMessage -Type "Error" -Msg "Could not verify allowed mime types. Error: $(Join-ExceptionMessage $_.Exception)" [ref]$refOutput.Value = "Could not verify allowed mime types." return "Bad" } @@ -310,7 +315,7 @@ Function PVWA_AnonymousAuthentication return $res } catch{ - Write-LogMessage -Type "Error" -Msg "Could not verify Anonymous Authentication in application pools. Error: $(Join-ExceptionMessage $_.Exception)" + Write-LogMessage -Type "Error" -Msg "Could not verify Anonymous Authentication in application pools. Error: $(Join-ExceptionMessage $_.Exception)" [ref]$refOutput.Value = "Could not verify Anonymous Authentication in application pools." return "Bad" } @@ -368,7 +373,7 @@ Function PVWA_DirectoryBrowsing return $res } catch{ - Write-LogMessage -Type "Error" -Msg "Could not verify Directory Browsing. Error: $(Join-ExceptionMessage $_.Exception)" + Write-LogMessage -Type "Error" -Msg "Could not verify Directory Browsing. Error: $(Join-ExceptionMessage $_.Exception)" [ref]$refOutput.Value = "Could not verify Directory Browsing." return "Bad" } @@ -532,7 +537,7 @@ Function PVWA_IIS_SSL_TLS_Settings return $res } catch{ - Write-LogMessage -Type "Error" -Msg "Could not validate hardening machine use only TLS 1.2. Error: $(Join-ExceptionMessage $_.Exception)" + Write-LogMessage -Type "Error" -Msg "Could not validate hardening machine use only TLS 1.2. Error: $(Join-ExceptionMessage $_.Exception)" [ref]$refOutput.Value = "Could not validate hardening machine use only TLS 1.2." return "Bad" } @@ -625,7 +630,7 @@ Function PVWA_IIS_Cypher_Suites return $res } catch{ - Write-LogMessage -Type "Error" -Msg "Could not validate Cypher Suites. Error: $(Join-ExceptionMessage $_.Exception)" + Write-LogMessage -Type "Error" -Msg "Could not validate Cypher Suites. Error: $(Join-ExceptionMessage $_.Exception)" [ref]$refOutput.Value = "Could not validate Cypher Suites." return "Bad" } @@ -749,7 +754,7 @@ Function PVWA_Scheduled_Task_Service_LocalUser return $res } catch{ - Write-LogMessage -Type "Error" -Msg "Could not validate Scheduled Task Service configuration. Error: $(Join-ExceptionMessage $_.Exception)" + Write-LogMessage -Type "Error" -Msg "Could not validate Scheduled Task Service configuration. Error: $(Join-ExceptionMessage $_.Exception)" [ref]$refOutput.Value = "Could not validate Scheduled Task Service configuration." return "Bad" } @@ -859,7 +864,7 @@ Function PVWA_NonSystemDrive return $res } catch{ - Write-LogMessage -Type "Error" -Msg "Could not validate PVWA is not installed on the system drive. Error: $(Join-ExceptionMessage $_.Exception)" + Write-LogMessage -Type "Error" -Msg "Could not validate PVWA is not installed on the system drive. Error: $(Join-ExceptionMessage $_.Exception)" [ref]$refOutput.Value = "Could not validate PVWA is not installed on the system drive." return "Bad" } @@ -943,7 +948,7 @@ Function PVWA_IIS_Hardening return $res } catch{ - Write-LogMessage -Type "Error" -Msg "Could not validate PVWA IIS hardening configuration. Error: $(Join-ExceptionMessage $_.Exception)" + Write-LogMessage -Type "Error" -Msg "Could not validate PVWA IIS hardening configuration. Error: $(Join-ExceptionMessage $_.Exception)" [ref]$refOutput.Value = "Could not validate PVWA IIS hardening configuration." return "Bad" } @@ -1016,7 +1021,7 @@ Function PVWA_AdditionalAppPool return $res } catch{ - Write-LogMessage -Type "Error" -Msg "Could not validate PVWA application pool settings. Error: $(Join-ExceptionMessage $_.Exception)" + Write-LogMessage -Type "Error" -Msg "Could not validate PVWA application pool settings. Error: $(Join-ExceptionMessage $_.Exception)" [ref]$refOutput.Value = "Could not validate PVWA application pool settings." return "Bad" } @@ -1076,7 +1081,7 @@ Function PVWA_CredFileHardening Write-LogMessage -Type Info -Msg "Finish validating PVWA component credential file" return $res } catch { - Write-LogMessage -Type "Error" -Msg "Could not validate the PVWA component credential file. Error: $(Join-ExceptionMessage $_.Exception)" + Write-LogMessage -Type "Error" -Msg "Could not validate the PVWA component credential file. Error: $(Join-ExceptionMessage $_.Exception)" [ref]$refOutput.Value = "Could not validate PVWA component credential file." return "Bad" } diff --git a/CYBRHardeningCheck/Vault/VaultHardeningSteps.psm1 b/CYBRHardeningCheck/Vault/VaultHardeningSteps.psm1 index d1e0490..030edb3 100644 --- a/CYBRHardeningCheck/Vault/VaultHardeningSteps.psm1 +++ b/CYBRHardeningCheck/Vault/VaultHardeningSteps.psm1 @@ -689,6 +689,7 @@ Function Vault_KeysProtection $KeysFolderLocalAdmins = $KeysFolderLocalSystem = $true foreach ($path in $KeysLocations) { + $path = '"'+$path+'"' Write-LogMessage -Type Verbose -Msg "Checking '$path' permissions..." if ((Compare-UserPermissions -path $path -identity $(Get-LocalAdministrators) -rights "FullControl" -outStatus ([ref]$myRef)) -ne "Good") { @@ -738,4 +739,4 @@ Function Vault_KeysProtection { # Write output to HTML } -} \ No newline at end of file +} diff --git a/CYBRHardeningCheck/bin/CommonUtil.psd1 b/CYBRHardeningCheck/bin/CommonUtil.psd1 index 1f4adba..5233ddc 100644 Binary files a/CYBRHardeningCheck/bin/CommonUtil.psd1 and b/CYBRHardeningCheck/bin/CommonUtil.psd1 differ diff --git a/CYBRHardeningCheck/bin/CommonUtil.psm1 b/CYBRHardeningCheck/bin/CommonUtil.psm1 index bcb787b..3197830 100644 --- a/CYBRHardeningCheck/bin/CommonUtil.psm1 +++ b/CYBRHardeningCheck/bin/CommonUtil.psm1 @@ -1220,22 +1220,32 @@ Function Get-ServiceInstallPath .PARAMETER ServiceName The service name to query. Just one. #> - param ($ServiceName) + param ( + [Parameter(Mandatory=$true)] + [String]$ServiceName + ) Begin { } Process { $retInstallPath = $Null try{ - if ($null -eq $m_ServiceList) + # Search only if user is an admin (will always fail otherwise) + if(Test-CurrentUserLocalAdmin) { - Set-Variable -Name m_ServiceList -Value $(Get-ChildItem "HKLM:\System\CurrentControlSet\Services" | ForEach-Object { Get-ItemProperty $_.PSPath }) -Scope Script - #$m_ServiceList = Get-Reg -Hive "LocalMachine" -Key System\CurrentControlSet\Services -Value $null + if ($null -eq $m_ServiceList) + { + Set-Variable -Name m_ServiceList -Value $(Get-ChildItem "HKLM:\System\CurrentControlSet\Services" | ForEach-Object { Get-ItemProperty $_.PSPath }) -Scope Script + } + $regPath = $m_ServiceList | Where-Object {$_.PSChildName -eq $ServiceName} + If ($Null -ne $regPath) + { + $retInstallPath = $regPath.ImagePath.Substring($regPath.ImagePath.IndexOf('"'),$regPath.ImagePath.LastIndexOf('"')+1) + } } - $regPath = $m_ServiceList | Where-Object {$_.PSChildName -eq $ServiceName} - If ($Null -ne $regPath) + else { - $retInstallPath = $regPath.ImagePath.Substring($regPath.ImagePath.IndexOf('"'),$regPath.ImagePath.LastIndexOf('"')+1) + Write-LogMessage -Type "Warning" -Msg "Skipping Service install path check as user is not a local admin" } } catch{ @@ -2555,9 +2565,9 @@ Function Start-HardeningSteps if ($(ConvertTo-Bool $step.Enable) -eq $False) { Write-LogMessage -Type Debug -Msg "Step $($step.Name) is disabled" - $refHardeningStepStatus.Status = "Bad" + $refHardeningStepStatus.Status = "Ignore" $refHardeningStepStatus.Output = "Step is disabled, verification was not performed" - $AllStepsArray += New-Object PSObject -Property @{Name=$step.Name;CompletedSuccessfully=$false} + $AllStepsArray += New-Object PSObject -Property @{Name=$step.Name;CompletedSuccessfully=$true} } else { @@ -2586,7 +2596,6 @@ Function Start-HardeningSteps Write-LogMessage -Type Info -Msg "Finished Step $($step.DisplayName)" } # Add to steps array - #Write-LogMessage -Type Debug -Msg "$($refHardeningStepStatus.Name) ($($refHardeningStepStatus.Status)): $($refHardeningStepStatus.Output)" Write-LogMessage -Type Debug -Msg "$($refHardeningStepStatus.Name) ($($refHardeningStepStatus.Status))" $AllHardeningStepsStatus += $refHardeningStepStatus } diff --git a/CYBRHardeningCheck/bin/GeneralHardeningSteps.psd1 b/CYBRHardeningCheck/bin/GeneralHardeningSteps.psd1 index 7494579..f88271e 100644 Binary files a/CYBRHardeningCheck/bin/GeneralHardeningSteps.psd1 and b/CYBRHardeningCheck/bin/GeneralHardeningSteps.psd1 differ diff --git a/CYBRHardeningCheck/bin/GeneralHardeningSteps.psm1 b/CYBRHardeningCheck/bin/GeneralHardeningSteps.psm1 index e5c1855..b9aed86 100644 --- a/CYBRHardeningCheck/bin/GeneralHardeningSteps.psm1 +++ b/CYBRHardeningCheck/bin/GeneralHardeningSteps.psm1 @@ -58,7 +58,7 @@ Function ImportingINFConfiguration # Get the Component relative INF file path $INFconfigFilePath = Get-CurrentComponentFolderPath -FileName $INFconfigFileName - if(!Test-Path $INFconfigFilePath) + if(!(Test-Path $INFconfigFilePath)) { # INF Configuration was not found Throw "Could not find configuration file in path: $INFconfigFilePath" @@ -415,14 +415,29 @@ Function RemoteDesktopServices $UserDir = "$($env:WinDir)\system32\GroupPolicy\User\registry.pol" $RegPath = "Software\Policies\Microsoft\Windows NT\Terminal Services" + + # init variables + $regShadowData = $reMaxIdleTimeData = 0 + # Checking for cases where PSM is installed vs. CPM/PVWA are installed + If($(Get-DetectedComponents).Name -contains "PSM") + { + # Set values according to PSM hardening + $regShadowData = '4' + $reMaxIdleTimeData = '1800000' + } + else { + # Set values according to general CPM/PVWA hardening + $regShadowData = '0' + $reMaxIdleTimeData = '1' + } - if((Compare-PolicyEntry -EntryTitle "Set rules for remote control of Remote Desktop Services user sessions" -UserDir $UserDir -RegPath $RegPath -RegName 'Shadow' -RegData '4' -outStatus ([ref]$myRef)) -ne "Good") + if((Compare-PolicyEntry -EntryTitle "Set rules for remote control of Remote Desktop Services user sessions" -UserDir $UserDir -RegPath $RegPath -RegName 'Shadow' -RegData $regShadowData -outStatus ([ref]$myRef)) -ne "Good") { $tmpStatus += $myRef.Value + "
" $statusChanged = $true } - if((Compare-PolicyEntry -EntryTitle "Set time limit for active but idle Remote Desktop Services sessions" -UserDir $UserDir -RegPath $RegPath -RegName 'MaxIdleTime' -RegData '1800000' -outStatus ([ref]$myRef)) -ne "Good") + if((Compare-PolicyEntry -EntryTitle "Set time limit for active but idle Remote Desktop Services sessions" -UserDir $UserDir -RegPath $RegPath -RegName 'MaxIdleTime' -RegData $reMaxIdleTimeData -outStatus ([ref]$myRef)) -ne "Good") { $tmpStatus += $myRef.Value + "
" $statusChanged = $true