Skip to content

Commit

Permalink
Add a generic function for querying an object's security information
Browse files Browse the repository at this point in the history
  • Loading branch information
itm4n committed Jan 8, 2025
1 parent 6721a5b commit 7f7387a
Show file tree
Hide file tree
Showing 7 changed files with 278 additions and 195 deletions.
4 changes: 4 additions & 0 deletions info/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## 2025-01-08

### Added

- Wrapper function for querying an object's security information in a generic way.

### Changed

- Refactor file, directory, registry key ACL check.
Expand Down
46 changes: 25 additions & 21 deletions src/check/Credentials.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -670,6 +670,7 @@ function Invoke-HiveFileShadowCopyPermissionCheck {

begin {
$AllResults = @()
$FileHandles = @()
$CurrentUserSids = Get-CurrentUserSid
$FsRedirectionValue = Disable-Wow64FileSystemRedirection
}
Expand All @@ -682,36 +683,35 @@ function Invoke-HiveFileShadowCopyPermissionCheck {
foreach ($HiveFile in "SAM", "SECURITY", "SYSTEM") {

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

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

$PermissionReference = @(
$script:FileAccessRight::ReadData
)
$FileHandles += $FileHandle

foreach ($Ace in $FileDacl.Access) {
$SecurityInfo = Get-ObjectSecurityInfo -Handle $FileHandle -Type File
if ($null -eq $SecurityInfo) { continue }

if ($Ace.AceType -notmatch "AccessAllowed") { continue }
foreach ($Ace in $SecurityInfo.Dacl) {

$Permissions = [Enum]::GetValues($script:FileAccessRight) | Where-Object {
($Ace.AccessMask -band ($script:FileAccessRight::$_)) -eq ($script:FileAccessRight::$_)
}
if ($Ace.AceType -notmatch "AccessAllowed") { continue }

if (Compare-Object -ReferenceObject $Permissions -DifferenceObject $PermissionReference -IncludeEqual -ExcludeDifferent) {
$IdentityReference = $($Ace | Select-Object -ExpandProperty "SecurityIdentifier").ToString()
if ($CurrentUserSids -notcontains $IdentityReference) { continue }

$IdentityReference = $($Ace | Select-Object -ExpandProperty "SecurityIdentifier").ToString()
$Permissions = $script:FileAccessRight.GetEnumValues() |
Where-Object {
($Ace.AccessMask -band ($script:FileAccessRight::$_)) -eq ($script:FileAccessRight::$_)
}

if ($CurrentUserSids -contains $IdentityReference) {
if ($Permissions -notcontains $script:FileAccessRight::ReadData) { continue }

$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
}
}
$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
}
}
}
Expand All @@ -724,6 +724,10 @@ function Invoke-HiveFileShadowCopyPermissionCheck {

end {
Restore-Wow64FileSystemRedirection -OldValue $FsRedirectionValue

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

Expand Down
88 changes: 46 additions & 42 deletions src/check/Misc.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -639,66 +639,70 @@ function Invoke-NamedPipePermissionCheck {
[CmdletBinding()]
param()

$UserIdentity = [System.Security.Principal.WindowsIdentity]::GetCurrent()
$CurrentUserSids = Get-CurrentUserSid

ForEach ($NamedPipe in $(Get-ChildItem -Path "\\.\pipe\")) {

$NamedPipeDacl = Get-FileDacl -Path $NamedPipe.FullName

if ($null -eq $NamedPipeDacl) { continue }

if ($UserIdentity.User.Value -match $NamedPipeDacl.OwnerSid) { continue }

if ($null -eq $NamedPipeDacl.Access) {

$Result = New-Object -TypeName PSObject
$Result | Add-Member -MemberType "NoteProperty" -Name "Pipe" -Value $NamedPipe.FullName
$Result | Add-Member -MemberType "NoteProperty" -Name "Owner" -Value $NamedPipeDacl.Owner
# $Result | Add-Member -MemberType "NoteProperty" -Name "Group" -Value $NamedPipeDacl.Group
$Result | Add-Member -MemberType "NoteProperty" -Name "AceType" -Value "AccessAllowed"
$Result | Add-Member -MemberType "NoteProperty" -Name "AccessRights" -Value "GenericAll"
$Result | Add-Member -MemberType "NoteProperty" -Name "SecurityIdentifier" -Value "S-1-1-0"
$Result | Add-Member -MemberType "NoteProperty" -Name "IdentityName" -Value (Convert-SidToName -Sid "S-1-1-0")
$Result
continue
}
begin {
$UserIdentity = [System.Security.Principal.WindowsIdentity]::GetCurrent()
$CurrentUserSids = Get-CurrentUserSid
$NamedPipeHandles = @()

$PermissionReference = @(
$script:FileAccessRight::Delete,
$script:FileAccessRight::WriteDac,
$script:FileAccessRight::WriteOwner,
$script:FileAccessRight::FileWriteEa,
$script:FileAccessRight::FileWriteAttributes
$script:FileAccessRight::FileWriteAttributes,
$script:FileAccessRight::AllAccess
)
}

ForEach ($Ace in $NamedPipeDacl.Access) {
process {
ForEach ($NamedPipe in $(Get-ChildItem -Path "\\.\pipe\")) {

if ($Ace.AceType -notmatch "AccessAllowed") { continue }
$NamedPipeHandle = Get-FileHandle -Path $NamedPipe.FullName -AccessRights $script:FileAccessRight::ReadControl
if ($NamedPipeHandle -eq -1) { continue }

$Permissions = [Enum]::GetValues($script:FileAccessRight) | Where-Object {
($Ace.AccessMask -band ($script:FileAccessRight::$_)) -eq ($script:FileAccessRight::$_)
}
$NamedPipeHandles += $NamedPipeHandle

if (Compare-Object -ReferenceObject $Permissions -DifferenceObject $PermissionReference -IncludeEqual -ExcludeDifferent) {
$NamedPipeDacl = Get-ObjectSecurityInfo -Handle $NamedPipeHandle -Type File
if ($null -eq $NamedPipeDacl) { continue }

$IdentityReference = $($Ace | Select-Object -ExpandProperty "SecurityIdentifier").ToString()
# Ignore named pipes owned by the current user.
if ($UserIdentity.User.Value -match $NamedPipeDacl.OwnerSid) { continue }

if ($CurrentUserSids -contains $IdentityReference) {
foreach ($Ace in $NamedPipeDacl.Dacl) {

$Result = New-Object -TypeName PSObject
$Result | Add-Member -MemberType "NoteProperty" -Name "Pipe" -Value $NamedPipe.FullName
$Result | Add-Member -MemberType "NoteProperty" -Name "Owner" -Value $NamedPipeDacl.Owner
# $Result | Add-Member -MemberType "NoteProperty" -Name "Group" -Value $NamedPipeDacl.Group
$Result | Add-Member -MemberType "NoteProperty" -Name "AceType" -Value ($Ace | Select-Object -ExpandProperty "AceType")
$Result | Add-Member -MemberType "NoteProperty" -Name "AccessRights" -Value ($Ace.AccessMask -as $script:FileAccessRight)
$Result | Add-Member -MemberType "NoteProperty" -Name "SecurityIdentifier" -Value $IdentityReference
$Result | Add-Member -MemberType "NoteProperty" -Name "IdentityName" -Value (Convert-SidToName -Sid $IdentityReference)
$Result
if ($Ace.AceType -notmatch "AccessAllowed") { continue }

$Permissions = $script:FileAccessRight.GetEnumValues() |
Where-Object {
($Ace.AccessMask -band ($script:FileAccessRight::$_)) -eq ($script:FileAccessRight::$_)
}

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

$IdentityReference = $($Ace | Select-Object -ExpandProperty "SecurityIdentifier").ToString()

if ($CurrentUserSids -contains $IdentityReference) {

$Result = New-Object -TypeName PSObject
$Result | Add-Member -MemberType "NoteProperty" -Name "Pipe" -Value $NamedPipe.FullName
$Result | Add-Member -MemberType "NoteProperty" -Name "Owner" -Value $NamedPipeDacl.Owner
$Result | Add-Member -MemberType "NoteProperty" -Name "Group" -Value $NamedPipeDacl.Group
$Result | Add-Member -MemberType "NoteProperty" -Name "AceType" -Value ($Ace | Select-Object -ExpandProperty "AceType")
$Result | Add-Member -MemberType "NoteProperty" -Name "AccessRights" -Value ($Ace.AccessMask -as $script:FileAccessRight)
$Result | Add-Member -MemberType "NoteProperty" -Name "SecurityIdentifier" -Value $IdentityReference
$Result | Add-Member -MemberType "NoteProperty" -Name "IdentityName" -Value (Convert-SidToName -Sid $IdentityReference)
$Result
}
}
}
}
}

end {
foreach ($NamedPipeHandle in $NamedPipeHandles) {
$null = $script:Kernel32::CloseHandle($NamedPipeHandle)
}
}
}

function Invoke-UserSessionCheck {
Expand Down
35 changes: 30 additions & 5 deletions src/core/WinApi.Enum.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,19 @@ $script:SeverityLevel = New-Enum $Module WinApiModule.SeverityLevel UInt32 @{
}

$script:SystemErrorCode = New-Enum $Module WinApiModule.SystemErrorCode UInt32 @{
ERROR_SUCCESS = 0
ERROR_INVALID_FUNCTION = 1
ERROR_INSUFFICIENT_BUFFER = 122
ERROR_ENVVAR_NOT_FOUND = 203
}

$script:FileShareMode = New-Enum $Module WinApiModule.FileShareMode UInt32 @{
None = 0x00000000
Read = 0x00000001
Write = 0x00000002
Delete = 0x00000004
} -BitField

$script:FileAccessRight = New-Enum $Module WinApiModule.FileAccessRight UInt32 @{
ReadData = 0x00000001
WriteData = 0x00000002
Expand All @@ -26,10 +34,10 @@ $script:FileAccessRight = New-Enum $Module WinApiModule.FileAccessRight UInt32 @
WriteOwner = 0x00080000
Synchronize = 0x00100000
AccessSystemSecurity = 0x01000000
AllAccess = 0x001f01ff
GenericRead = 0x00120089 # FILE_READ_ATTRIBUTES | FILE_READ_DATA | FILE_READ_EA | STANDARD_RIGHTS_READ | SYNCHRONIZE
GenericWrite = 0x00120116 # FILE_APPEND_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_DATA | FILE_WRITE_EA | STANDARD_RIGHTS_WRITE | SYNCHRONIZE
GenericExecute = 0x001200a0 # FILE_EXECUTE | FILE_READ_ATTRIBUTES | STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE
GenericAll = 0x001f01ff
} -BitField

$script:DirectoryAccessRight = New-Enum $Module WinApiModule.DirectoryAccessRight UInt32 @{
Expand All @@ -48,10 +56,10 @@ $script:DirectoryAccessRight = New-Enum $Module WinApiModule.DirectoryAccessRigh
WriteOwner = 0x00080000
Synchronize = 0x00100000
AccessSystemSecurity = 0x01000000
AllAccess = 0x000f000f
GenericRead = 0x00120089
GenericWrite = 0x00120116
GenericExecute = 0x001200a0
GenericAll = 0x000f000f
}

$script:RegistryKeyAccessRight = New-Enum $Module WinApiModule.RegistryKeyAccessRight UInt32 @{
Expand All @@ -65,9 +73,9 @@ $script:RegistryKeyAccessRight = New-Enum $Module WinApiModule.RegistryKeyAccess
ReadControl = 0x00020000
WriteDac = 0x00040000
WriteOwner = 0x00080000
AllAccess = 0x000f003f
GenericRead = 0x00020019 # STANDARD_RIGHTS_READ | KEY_NOTIFY | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE
GenericWrite = 0x00020006 # STANDARD_RIGHTS_WRITE | KEY_SET_VALUE | KEY_CREATE_SUB_KEY
GenericAll = 0x000f003f
}

$script:ServiceAccessRight = New-Enum $Module WinApiModule.ServiceAccessRight UInt32 @{
Expand All @@ -86,10 +94,10 @@ $script:ServiceAccessRight = New-Enum $Module WinApiModule.ServiceAccessRight UI
WriteOwner = 0x00080000
Synchronize = 0x00100000
AccessSystemSecurity = 0x01000000
AllAccess = 0x000f01ff
GenericRead = 0x0002008d # STANDARD_RIGHTS_READ | SERVICE_QUERY_CONFIG | SERVICE_QUERY_STATUS | SERVICE_INTERROGATE | SERVICE_ENUMERATE_DEPENDENTS
GenericWrite = 0x00020002 # STANDARD_RIGHTS_WRITE | SERVICE_CHANGE_CONFIG
GenericExecute = 0x00020170 # STANDARD_RIGHTS_EXECUTE | SERVICE_START | SERVICE_STOP | SERVICE_PAUSE_CONTINUE | SERVICE_USER_DEFINED_CONTROL
AllAccess = 0x000f01ff
} -BitField

$script:ServiceControlManagerAccessRight = New-Enum $Module WinApiModule.ServiceControlManagerAccessRight UInt32 @{
Expand Down Expand Up @@ -599,4 +607,21 @@ $script:USER_AUTH_FLAGS = New-Enum $Module WinApiModule.USER_AUTH_FLAGS UInt32 @
AF_OP_COMM = 0x00000002
AF_OP_SERVER = 0x00000004
AF_OP_ACCOUNTS = 0x00000008
} -BitField
} -BitField

$script:SE_OBJECT_TYPE = New-Enum $Module WinApiModule.SE_OBJECT_TYPE UInt32 @{
SE_UNKNOWN_OBJECT_TYPE = 0
SE_FILE_OBJECT = 1
SE_SERVICE = 2
SE_PRINTER = 3
SE_REGISTRY_KEY = 4
SE_LMSHARE = 5
SE_KERNEL_OBJECT = 6
SE_WINDOW_OBJECT = 7
SE_DS_OBJECT = 8
SE_DS_OBJECT_ALL = 9
SE_PROVIDER_DEFINED_OBJECT = 10
SE_WMIGUID_OBJECT = 11
SE_REGISTRY_WOW64_32KEY = 12
SE_REGISTRY_WOW64_64KEY = 13
}
Loading

0 comments on commit 7f7387a

Please sign in to comment.