Skip to content

Commit

Permalink
Merge and refactor hive file permission checks
Browse files Browse the repository at this point in the history
  • Loading branch information
itm4n committed Jan 10, 2025
1 parent aabd09b commit 1ee9cc1
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 158 deletions.
3 changes: 1 addition & 2 deletions build/Checks.csv
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@
"APP_PROCESSES", "Invoke-RunningProcessCheck", "TA0043 - Reconnaissance", "Running processes", "None", "Table", "Extended", "True", "False", "Get information about the currently running processes that are not owned by the current user. Processes such as 'svchost.exe' are filtered out."
"SCHTASKS_IMAGE_PERMISSIONS", "Invoke-ScheduledTaskImagePermissionCheck", "TA0004 - Privilege Escalation", "Scheduled task image file permissions", "High", "List", "Base", "False", "False", "Check whether the current user has any write permissions on a scheduled task's binary or its folder. Note that low-privileged users cannot list all the scheduled tasks."
"SCHTASKS_UNQUOTED_PATH", "Invoke-ScheduledTaskUnquotedPathCheck", "TA0004 - Privilege Escalation", "Scheduled task unquoted paths", "Medium", "List", "Experimental", "False", "False", "Check whether there are scheduled tasks configured with an exploitable unquoted path. Note that low-privileged users cannot list all the scheduled tasks."
"CREDS_SENSITIVE_HIVE_FILES", "Invoke-HiveFilePermissionCheck", "TA0006 - Credential Access", "Hive file permissions", "Medium", "List", "Base", "False", "False", "Check whether the current user has read permissions on the SAM/SYSTEM/SECURITY files in the system folder (CVE-2021-36934 - HiveNightmare)."
"CREDS_SENSITIVE_HIVE_FILES_VSS", "Invoke-HiveFileShadowCopyPermissionCheck", "TA0006 - Credential Access", "Hive file shadow copy permissions", "High", "List", "Base", "False", "False", "Check whether the current user has read permissions on the SAM/SYSTEM/SECURITY files stored in volume shadow copies (CVE-2021-36934 - HiveNightmare)."
"CREDS_SENSITIVE_HIVE_FILES", "Invoke-HiveFilePermissionCheck", "TA0006 - Credential Access", "Hive file permissions", "Medium", "List", "Base", "False", "False", "Check whether the current user has read permissions on the SAM/SYSTEM/SECURITY hive files, either in the system folder or in volume shadow copies (CVE-2021-36934 - HiveNightmare)."
"CREDS_UNATTEND", "Invoke-UnattendFileCredentialCheck", "TA0006 - Credential Access", "Unattend file credentials", "Medium", "List", "Base", "True", "False", "Check whether there are any 'unattend' files and whether they contain clear-text credentials."
"CREDS_WINLOGON", "Invoke-WinLogonCredentialCheck", "TA0006 - Credential Access", "WinLogon credentials", "Medium", "List", "Base", "True", "False", "Check whether the 'WinLogon' registry key contains clear-text credentials. Note that entries with an empty password field are filtered out."
"CREDS_CRED_FILES", "Invoke-CredentialFileCheck", "TA0006 - Credential Access", "Credential files", "None", "List", "Extended", "False", "False", "Get information about the current user's CREDENTIAL files."
Expand Down
4 changes: 4 additions & 0 deletions info/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
- Helper function for enumerating all processes and threads.
- Check for process and thread permissions.

### Changed

- Merge and refactor hive file permission checks (CVE-2021-36934).

## 2025-01-09

### Changed
Expand Down
185 changes: 30 additions & 155 deletions src/check/Credentials.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -520,13 +520,13 @@ function Invoke-PowerShellHistoryCredentialCheck {
function Invoke-HiveFilePermissionCheck {
<#
.SYNOPSIS
Checks for READ access on the SAM, SYSTEM and SECURITY hive files (including potential backups).
Check for read access on hive files.
Author: @itm4n
License: BSD 3-Clause
.DESCRIPTION
Checks for READ access on the SAM, SYSTEM and SECURITY hive files (including potential backups).
This cmdlet constructs a list of hive file paths, on the active filesystem, and in shadow copies, and checks whether the current use has read access. This vulnerability was initially referenced as CVE-2021-36934, also known as "HiveNightmare".
.EXAMPLE
PS C:\> Invoke-HiveFilePermissionCheck
Expand All @@ -542,177 +542,56 @@ function Invoke-HiveFilePermissionCheck {
Path : C:\Windows\System32\config\SECURITY
IdentityReference : BUILTIN\Users
Permissions : ReadData, ReadExtendedAttributes, Execute, ReadAttributes, ReadControl, Synchronize
#>

[CmdletBinding()]
param(
[UInt32] $BaseSeverity
)

begin {
$AllResults = @()
$FsRedirectionValue = Disable-Wow64FileSystemRedirection
}

process {
$CurrentUserSids = Get-CurrentUserSid

$TranslatedIdentityReferences = @{}

$ArrayOfPaths = New-Object System.Collections.ArrayList
[void] $ArrayOfPaths.Add($(Join-Path -Path $env:SystemRoot -ChildPath "repair\SAM"))
[void] $ArrayOfPaths.Add($(Join-Path -Path $env:SystemRoot -ChildPath "System32\config\RegBack\SAM"))
[void] $ArrayOfPaths.Add($(Join-Path -Path $env:SystemRoot -ChildPath "System32\config\SAM"))
[void] $ArrayOfPaths.Add($(Join-Path -Path $env:SystemRoot -ChildPath "repair\SYSTEM"))
[void] $ArrayOfPaths.Add($(Join-Path -Path $env:SystemRoot -ChildPath "System32\config\SYSTEM"))
[void] $ArrayOfPaths.Add($(Join-Path -Path $env:SystemRoot -ChildPath "System32\config\RegBack\SYSTEM"))
[void] $ArrayOfPaths.Add($(Join-Path -Path $env:SystemRoot -ChildPath "repair\SECURITY"))
[void] $ArrayOfPaths.Add($(Join-Path -Path $env:SystemRoot -ChildPath "System32\config\SECURITY"))
[void] $ArrayOfPaths.Add($(Join-Path -Path $env:SystemRoot -ChildPath "System32\config\RegBack\SECURITY"))

foreach ($Path in [string[]] $ArrayOfPaths) {

try {
$Acl = Get-Acl -Path $Path -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Access
if ($null -eq $Acl) { Write-Verbose "ACL is null"; continue }

foreach ($Ace in $Acl) {

$PermissionReference = @(
$script:FileAccessRight::ReadData
)
$Permissions = [enum]::GetValues($script:FileAccessRight) | Where-Object {
($Ace.FileSystemRights.value__ -band ($script:FileAccessRight::$_)) -eq ($script:FileAccessRight::$_)
}

if (Compare-Object -ReferenceObject $Permissions -DifferenceObject $PermissionReference -IncludeEqual -ExcludeDifferent) {

if ($Ace.IdentityReference -notmatch '^S-1-5.*' -and $Ace.IdentityReference -notmatch '^S-1-15-.*') {
if (-not ($TranslatedIdentityReferences[$Ace.IdentityReference])) {

try {
# translate the IdentityReference if it's a username and not a SID
$IdentityUser = New-Object System.Security.Principal.NTAccount($Ace.IdentityReference)
$TranslatedIdentityReferences[$Ace.IdentityReference] = $IdentityUser.Translate([System.Security.Principal.SecurityIdentifier]) | Select-Object -ExpandProperty Value
}
catch {
# If we cannot resolve the SID, go to the next ACE.
continue
}
}
$IdentitySID = $TranslatedIdentityReferences[$Ace.IdentityReference]
}
else {
$IdentitySID = $Ace.IdentityReference
}

if ($CurrentUserSids -contains $IdentitySID) {
$Result = New-Object -TypeName PSObject
$Result | Add-Member -MemberType "NoteProperty" -Name "Path" -Value $Path
$Result | Add-Member -MemberType "NoteProperty" -Name "IdentityReference" -Value $Ace.IdentityReference
$Result | Add-Member -MemberType "NoteProperty" -Name "Permissions" -Value ($Permissions -join ", ")
$AllResults += $Result
}
}
}
}
catch {
$null = $_
}
}

$CheckResult = New-Object -TypeName PSObject
$CheckResult | Add-Member -MemberType "NoteProperty" -Name "Result" -Value $AllResults
$CheckResult | Add-Member -MemberType "NoteProperty" -Name "Severity" -Value $(if ($AllResults) { $BaseSeverity } else { $script:SeverityLevel::None })
$CheckResult
}

end {
Restore-Wow64FileSystemRedirection -OldValue $FsRedirectionValue
}
}

function Invoke-HiveFileShadowCopyPermissionCheck {
<#
.SYNOPSIS
Checks for READ access on the SAM, SYSTEM and SECURITY hive files in shadow copies.
Author: @SAERXCIT, @itm4n
License: BSD 3-Clause
.DESCRIPTION
Checks for READ access on the SAM, SYSTEM and SECURITY hive files in shadow copies.
.EXAMPLE
PS C:\> Invoke-HiveFileShadowCopyPermissionCheck
Volume : HarddiskVolumeShadowCopy1
Path : \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1\Windows\System32\config\SAM
IdentityReference : BUILTIN\Users
AccessRights : ReadData, ReadExtendedAttributes, Execute, ReadAttributes, ReadControl, Synchronize
Permissions : ReadData, ReadExtendedAttributes, Execute, ReadAttributes, ReadControl, Synchronize
Volume : HarddiskVolumeShadowCopy1
Path : \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1\Windows\System32\config\SECURITY
IdentityReference : BUILTIN\Users
AccessRights : ReadData, ReadExtendedAttributes, Execute, ReadAttributes, ReadControl, Synchronize
Permissions : ReadData, ReadExtendedAttributes, Execute, ReadAttributes, ReadControl, Synchronize
Volume : HarddiskVolumeShadowCopy1
Path : \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1\Windows\System32\config\SYSTEM
IdentityReference : BUILTIN\Users
AccessRights : ReadData, ReadExtendedAttributes, Execute, ReadAttributes, ReadControl, Synchronize
Permissions : ReadData, ReadExtendedAttributes, Execute, ReadAttributes, ReadControl, Synchronize
#>

[CmdletBinding()]
param(
param (
[UInt32] $BaseSeverity
)

begin {
$AllResults = @()
$FileHandles = @()
$CurrentUserSids = Get-CurrentUserSid
$HiveFilePaths = @()
$HiveFileNames = @("SAM", "SYSTEM", "SECURITY", "SOFTWARE")
$SubFolderPaths = @("repair", "System32\config", "System32\config\RegBack")
$ShadowCopies = Get-VolumeShadowCopyInformation
$FsRedirectionValue = Disable-Wow64FileSystemRedirection
}

process {
foreach($ShadowCopy in $(Get-VolumeShadowCopyInformation)) {

$ConfigPath = $(Join-Path -Path $ShadowCopy.Path -ChildPath "Windows\System32\config")

foreach ($HiveFile in "SAM", "SECURITY", "SYSTEM") {

$Path = $(Join-Path -Path $ConfigPath -ChildPath $HiveFile)

$FileHandle = Get-FileHandle -Path $Path -AccessRights $script:FileAccessRight::ReadControl
if ($FileHandle -eq -1) { continue }

$FileHandles += $FileHandle

$SecurityInfo = Get-ObjectSecurityInfo -Handle $FileHandle -Type File
if ($null -eq $SecurityInfo) { continue }

foreach ($Ace in $SecurityInfo.Dacl) {

if ($Ace.AceType -notmatch "AccessAllowed") { continue }

$IdentityReference = $($Ace | Select-Object -ExpandProperty "SecurityIdentifier").ToString()
if ($CurrentUserSids -notcontains $IdentityReference) { continue }

$Permissions = $script:FileAccessRight.GetEnumValues() |
Where-Object {
($Ace.AccessMask -band ($script:FileAccessRight::$_)) -eq ($script:FileAccessRight::$_)
}
$AllResults = @()
$BasePaths = @($env:SystemRoot)
$ShadowCopies | ForEach-Object { $BasePaths += Join-Path -Path $_.Path -ChildPath "Windows" }

foreach ($BasePath in $BasePaths) {
foreach ($SubFolderPath in $SubFolderPaths) {
foreach ($HiveFileName in $HiveFileNames) {
$HiveFilePath = Join-Path -Path $BasePath -ChildPath $SubFolderPath
$HiveFilePath = Join-Path -Path $HiveFilePath -ChildPath $HiveFileName
$HiveFilePaths += $HiveFilePath
}
}
}

if ($Permissions -notcontains $script:FileAccessRight::ReadData) { continue }
foreach ($HiveFilePath in $HiveFilePaths) {

$Result = New-Object -TypeName PSObject
$Result | Add-Member -MemberType "NoteProperty" -Name "Volume" -Value $ShadowCopy.Volume
$Result | Add-Member -MemberType "NoteProperty" -Name "Path" -Value $Path
$Result | Add-Member -MemberType "NoteProperty" -Name "IdentityReference" -Value (Convert-SidToName -Sid $IdentityReference)
$Result | Add-Member -MemberType "NoteProperty" -Name "AccessRights" -Value ($Permissions -join ", ")
$AllResults += $Result
}
Get-ObjectAccessRight -Name $HiveFilePath -Type File -AccessRights @($script:FileAccessRight::ReadData) -ErrorAction SilentlyContinue | ForEach-Object {
$Result = New-Object -TypeName PSObject
$Result | Add-Member -MemberType "NoteProperty" -Name "Path" -Value $_.ModifiablePath
$Result | Add-Member -MemberType "NoteProperty" -Name "IdentityReference" -Value $_.IdentityReference
$Result | Add-Member -MemberType "NoteProperty" -Name "Permissions" -Value ($_.Permissions -join ", ")
$AllResults += $Result
}
}

Expand All @@ -724,10 +603,6 @@ function Invoke-HiveFileShadowCopyPermissionCheck {

end {
Restore-Wow64FileSystemRedirection -OldValue $FsRedirectionValue

foreach ($FileHandle in $FileHandles) {
$null = $script:Kernel32::CloseHandle($FileHandle)
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/helper/AccessControl.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ function Get-ObjectAccessRight {
.DESCRIPTION
This cmdlet retrieves the ACL of an object and returns the ACEs that grant modification permissions to the current user. It should be noted that, in case of deny ACEs, restricted rights are removed from the permission list of the ACEs.
.PARAMETER Path
.PARAMETER Name
A mandatory parameter representing the name of an object.
.PARAMETER Type
Expand Down

0 comments on commit 1ee9cc1

Please sign in to comment.