From dc80e357ce8f8b48f4fec7b5bff8e6ddced999cd Mon Sep 17 00:00:00 2001 From: itm4n <30777390+itm4n@users.noreply.github.com> Date: Thu, 29 Jan 2026 17:36:55 +0100 Subject: [PATCH] Add a check for Office Trusted Locations --- data/Checks.csv | 3 +- info/CHANGELOG.md | 1 + src/check/Hardening.ps1 | 90 ++++++++++++++++++++++++++++++++++++++ src/helper/Environment.ps1 | 2 +- 4 files changed, 94 insertions(+), 2 deletions(-) diff --git a/data/Checks.csv b/data/Checks.csv index 57c3692..3f290d2 100644 --- a/data/Checks.csv +++ b/data/Checks.csv @@ -58,7 +58,8 @@ "HARDEN_DEFAULT_LOCAL_ADMIN", "Invoke-DefaultLocalAdministratorAccountCheck","TA0008 - Lateral Movement", "Hardening - Default Local Administrator Account", "Low", "List", "Audit", "True", "False", "Check whether the default local administrator account is disabled." "HARDEN_CLICKONCE_PROMPT", "Invoke-ClickOnceTrustPromptBehaviorCheck", "TA0001 - Initial Access", "Hardening - ClickOnce Trust Prompt Behavior", "Low", "List", "Audit", "True", "False", "Check whether users are allowed to execute ClickOnce applications from the 'Internet' zone." "HARDEN_OFFICE_MACROS", "Invoke-OfficeMacroConfigurationCheck", "TA0001 - Initial Access", "Hardening - MS Office Macro Settings", "Low", "List", "Audit", "True", "False", "Check whether Office macros are enabled or disabled with a notification." -"HARDEN_OFFICE_PROTECTED_VIEW", "Invoke-OfficeProtectedViewConfigurationCheck","TA0001 - Initial Access", "Hardening - MS Office Protected View Settings", "Low", "List", 'Audit", "True", "False", "Check whether Office Protected View is enabled on all supported applications." +"HARDEN_OFFICE_PROTECTED_VIEW", "Invoke-OfficeProtectedViewConfigurationCheck","TA0001 - Initial Access", "Hardening - MS Office Protected View Settings", "Low", "List", "Audit", "True", "False", "Check whether Office Protected View is enabled on all supported applications." +"HARDEN_OFFICE_TRUSTED_LOCATIONS", "Invoke-OfficeTrustedLocationsCheck", "TA0001 - Initial Access", "Hardening - MS Office Trusted Locations", "Low", "List", "Audit", "True", "False", "Check whether Office Trusted Locations are enabled and whether they contain any directory modifiable as the current user." "CONFIG_PATH_FOLDERS", "Invoke-DllHijackingCheck", "TA0004 - Privilege Escalation", "Configuration - PATH Folder Permissions", "High", "List", "Base", "False", "False", "Check whether the current user has any write permissions on the system-wide PATH folders. If so, the system could be vulnerable to privilege escalation through ghost DLL hijacking." "MISC_HIJACKABLE_DLL", "Invoke-HijackableDllCheck", "TA0004 - Privilege Escalation", "Misc - Known Ghost DLLs", "None", "List", "Base", "False", "False", "Get information about services that are known to be prone to ghost DLL hijacking. Note that their exploitation requires the current user to have write permissions on at least one system-wide PATH folder." "CONFIG_CREDENTIAL_DELEGATION", "Invoke-CredentialDelegationCheck", "TA0006 - Credential Access", "Configuration - Credential Delegation", "Medium", "List", "Extended", "True", "False", "Check whether Credential Delegation is enabled. If so, passwords are very likely to be stored in clear-text in memory, unless another setting prevents that. Note that LSA Protection is not sufficient to protect credentials in this case." diff --git a/info/CHANGELOG.md b/info/CHANGELOG.md index 92ba12a..dd6565f 100644 --- a/info/CHANGELOG.md +++ b/info/CHANGELOG.md @@ -7,6 +7,7 @@ - Add a helper function for enumerating Microsoft Office Trust Center security settings. - Add a check for Microsoft Office macro execution settings. - Add a check for Microsoft Office Protected View settings. +- Add a check for Microsoft Office Trusted Locations. ## 2026-01-28 diff --git a/src/check/Hardening.ps1 b/src/check/Hardening.ps1 index d020655..8fd8ceb 100644 --- a/src/check/Hardening.ps1 +++ b/src/check/Hardening.ps1 @@ -1392,4 +1392,94 @@ function Invoke-OfficeProtectedViewConfigurationCheck { $CheckResult | Add-Member -MemberType "NoteProperty" -Name "Severity" -Value $(if ($GlobalVulnerable) { $BaseSeverity } else { $script:SeverityLevel::None }) $CheckResult } +} + +function Invoke-OfficeTrustedLocationsCheck { + <# + .SYNOPSIS + Check whether Office Trusted Locations are enabled and whether they contain any directory modifiable as the current user + + Author: @itm4n + License: BSD 3-Clause + + .DESCRIPTION + This cmdlet retrieves the Office Trust Center configuration and then iterates over each Office application to determine whether their Trusted Locations are enabled. If so, it iterates over its list of allowed paths and checks whether they are modifiable as a current user. If Trusted Locations are not disabled globally and if at least one modifiable path is found, the Office application is considered vulnerable. + + .EXAMPLE + PS C:\> Invoke-OfficeTrustedLocationsCheck + + Application : Word + Version : 16.0 + Key : HKEY_CURRENT_USER\Software\Microsoft\Office\16.0\Word + Value : AllLocationsDisabled + Data : 0 + Description : Enable Trusted Locations (default) + + Application : Word + Version : 16.0 + Key : HKEY_CURRENT_USER\Software\Microsoft\Office\16.0\Word + Value : AllowNetworkLocations + Data : 0 + Description : Do not allow Trusted Locations on my network (default) + + Application : Word + Version : 16.0 + Key : HKEY_CURRENT_USER\Software\Microsoft\Office\16.0\Word\Security\Trusted Locations + Value : TrustedLocations + Data : C:\Users\Admin\AppData\Roaming\Microsoft\Templates; C:\Program Files\Microsoft Office\root\Templates\; C:\Users\Admin\AppData\Roaming\Microsoft\Word\Startup + Description : Trusted Locations count: 3 + Modifiable : C:\Users\Admin\AppData\Roaming\Microsoft\Templates; C:\Users\Admin\AppData\Roaming\Microsoft\Word\Startup + + ... + #> + + [CmdletBinding()] + param ( + [UInt32] $BaseSeverity + ) + + process { + $AllResults = @() + $Vulnerable = $False + $TrustedLocationSettings = Get-MicrosoftOfficeTrustCenterConfiguration | Where-Object { + $_.Value -eq "AllLocationsDisabled" -or $_.Value -eq "AllowNetworkLocations" -or $_.Value -eq "TrustedLocations" + } + + $Applications = [String[]] ($TrustedLocationSettings | Select-Object -ExpandProperty "Application" -Unique) + + foreach ($Application in $Applications) { + + $AllLocationsDisabled = $TrustedLocationSettings | Where-Object { $_.Application -eq $Application -and $_.Value -eq "AllLocationsDisabled" } + if ($AllLocationsDisabled.Data -eq 1) { + continue + } + + $TrustedLocations = $TrustedLocationSettings | Where-Object { $_.Application -eq $Application -and $_.Value -eq "TrustedLocations" } + $TrustedLocationsModifiable = @() + + foreach ($TrustedLocation in ([String[]] $TrustedLocations.Data)) { + + Get-ModifiablePath -Path $TrustedLocation | Where-Object { $_ -and (-not [String]::IsNullOrEmpty($_.ModifiablePath)) } | ForEach-Object { + $TrustedLocationsModifiable += $_.ModifiablePath + } + } + + $TrustedLocationsModifiable = [String[]] ($TrustedLocationsModifiable | Select-Object -Unique) + + $TrustedLocations.Data = $($TrustedLocations.Data -join "; ") + if ($TrustedLocationsModifiable) { + $Vulnerable = $True + $TrustedLocations | Add-Member -MemberType "NoteProperty" -Name "Modifiable" -Value $($TrustedLocationsModifiable -join "; ") + } + + $AllResults += $TrustedLocationSettings | Where-Object { $_.Application -eq $Application -and $_.Value -eq "AllLocationsDisabled" } + $AllResults += $TrustedLocationSettings | Where-Object { $_.Application -eq $Application -and $_.Value -eq "AllowNetworkLocations" } + $AllResults += $TrustedLocations + } + + $CheckResult = New-Object -TypeName PSObject + $CheckResult | Add-Member -MemberType "NoteProperty" -Name "Result" -Value $AllResults + $CheckResult | Add-Member -MemberType "NoteProperty" -Name "Severity" -Value $(if ($Vulnerable) { $BaseSeverity } else { $script:SeverityLevel::None }) + $CheckResult + } } \ No newline at end of file diff --git a/src/helper/Environment.ps1 b/src/helper/Environment.ps1 index c48c585..03ca38d 100644 --- a/src/helper/Environment.ps1 +++ b/src/helper/Environment.ps1 @@ -1866,7 +1866,7 @@ function Get-MicrosoftOfficeTrustCenterConfiguration { $Result | Add-Member -MemberType "NoteProperty" -Name "Application" -Value $Application $Result | Add-Member -MemberType "NoteProperty" -Name "Version" -Value $Version $Result | Add-Member -MemberType "NoteProperty" -Name "Key" -Value $RegKeyPath - $Result | Add-Member -MemberType "NoteProperty" -Name "Value" -Value $null + $Result | Add-Member -MemberType "NoteProperty" -Name "Value" -Value "TrustedLocations" $Result | Add-Member -MemberType "NoteProperty" -Name "Data" -Value $TrustedLocations $Result | Add-Member -MemberType "NoteProperty" -Name "Description" -Value "Trusted Locations count: $($TrustedLocations.Length)" $AllResults += $Result