Skip to content

Commit

Permalink
Refactor service DACL check to use the generic helper function Get-Mo…
Browse files Browse the repository at this point in the history
…dificationRight
  • Loading branch information
itm4n committed Jan 9, 2025
1 parent 9a16b10 commit e3348f5
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 117 deletions.
7 changes: 7 additions & 0 deletions info/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Changelog

## 2025-01-09

### Removed

- The cmdlet 'Get-ModifiableService' was replaced by the more generic helper function 'Get-ModificationRight'.
- The helper function 'Convert-NameToSid' embedded within 'Get-ModificationRight' was removed as it is no longer needed.

## 2025-01-08

### Added
Expand Down
43 changes: 25 additions & 18 deletions src/check/Services.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -245,20 +245,24 @@ function Invoke-ServicePermissionCheck {
License: BSD 3-Clause
.DESCRIPTION
This is based on the original "Get-ModifiableService" from PowerUp.
This cmdlet enumerates Windows services and checks their DACL to see if the current user has any modification right on them.
.EXAMPLE
PS C:\> Invoke-ServicePermissionCheck
Name : DVWS
ImagePath : C:\DVWS\Vuln Service\service.exe
User : LocalSystem
Status : Stopped
UserCanStart : True
UserCanStop : True
.LINK
https://github.com/PowerShellMafia/PowerSploit/blob/master/Privesc/PowerUp.ps1
Name : UnquotedService
DisplayName :
User : LocalSystem
ImagePath : C:\Workspace\Test Service\cmd.exe /c net user add
StartMode : Manual
Type : Win32OwnProcess
RegistryKey : HKLM\SYSTEM\CurrentControlSet\Services
RegistryPath : HKLM\SYSTEM\CurrentControlSet\Services\UnquotedService
Status : Stopped
UserCanStart : False
UserCanStop : False
IdentityReference : BUILTIN\Users (S-1-5-32-545)
Permissions : ChangeConfig
#>

[CmdletBinding()]
Expand All @@ -269,14 +273,17 @@ function Invoke-ServicePermissionCheck {
process {
$AllResults = @()

Get-ServiceFromRegistry -FilterLevel 1 | Get-ModifiableService | ForEach-Object {

$Result = $_.PSObject.Copy()
$Result | Add-Member -MemberType "NoteProperty" -Name "Status" -Value $(Get-ServiceStatus -Name $_.Name)
$Result | Add-Member -MemberType "NoteProperty" -Name "UserCanStart" -Value $(Test-ServiceDiscretionaryAccessControlList -Service $_ -Permissions "Start")
$Result | Add-Member -MemberType "NoteProperty" -Name "UserCanStop" -Value $(Test-ServiceDiscretionaryAccessControlList -Service $_ -Permissions "Stop")

$AllResults += $Result
Get-ServiceFromRegistry -FilterLevel 1 | ForEach-Object {
$ServiceObject = $_
Get-ModificationRight -Path $ServiceObject.Name -Type Service | ForEach-Object {
$Result = $ServiceObject.PSObject.Copy()
$Result | Add-Member -MemberType "NoteProperty" -Name "Status" -Value $(Get-ServiceStatus -Name $ServiceObject.Name)
$Result | Add-Member -MemberType "NoteProperty" -Name "UserCanStart" -Value $(Test-ServiceDiscretionaryAccessControlList -Service $ServiceObject -Permissions "Start")
$Result | Add-Member -MemberType "NoteProperty" -Name "UserCanStop" -Value $(Test-ServiceDiscretionaryAccessControlList -Service $ServiceObject -Permissions "Stop")
$Result | Add-Member -MemberType "NoteProperty" -Name "IdentityReference" -Value $_.IdentityReference
$Result | Add-Member -MemberType "NoteProperty" -Name "Permissions" -Value ($_.Permissions -join ", ")
$AllResults += $Result
}
}

$CheckResult = New-Object -TypeName PSObject
Expand Down
99 changes: 0 additions & 99 deletions src/helper/AccessControl.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -94,26 +94,6 @@ function Get-ModificationRight {

$CurrentUserSids = Get-CurrentUserSid
$CurrentUserDenySids = Get-CurrentUserDenySid

$ResolvedIdentities = @{}

function Convert-NameToSid {

param([String] $Name)

if (($Name -match '^S-1-5.*') -or ($Name -match '^S-1-15-.*')) { $Name; return }

if (-not ($ResolvedIdentities[$Name])) {
$Identity = New-Object System.Security.Principal.NTAccount($Name)
try {
$ResolvedIdentities[$Name] = $Identity.Translate([System.Security.Principal.SecurityIdentifier]) | Select-Object -ExpandProperty Value
}
catch {
$null = $_
}
}
$ResolvedIdentities[$Name]
}
}

process {
Expand Down Expand Up @@ -662,85 +642,6 @@ function Get-ExploitableUnquotedPath {
}
}

function Get-ModifiableService {
<#
.SYNOPSIS
Helper - Get services on which the current user has modification permissions.
Author: @itm4n
License: BSD 3-Clause
.DESCRIPTION
This cmdlet retrieves the DACL of a service, and checks whether the current user has modification permissions on it such as 'ChangeConfig' or 'WriteOwner'.
.PARAMETER Service
A mandatory service object returned by 'Get-ServiceFromRegistry' (or 'Get-Service').
.EXAMPLE
PS C:\> Get-ServiceFromRegistry -FilterLevel 2 | Get-ModifiableService
#>

[CmdletBinding()]
param (
[Parameter(Position=0, Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
[ValidateNotNullOrEmpty()]
[Object[]] $Service
)

begin {
$ModificationPermissions = @(
$script:ServiceAccessRight::ChangeConfig,
$script:ServiceAccessRight::WriteDac,
$script:ServiceAccessRight::WriteOwner,
$script:ServiceAccessRight::AllAccess
)

$CurrentUserSids = Get-CurrentUserSid
}

process {
foreach ($ServiceObject in $Service) {
$ServiceHandle = Get-ServiceHandle -Name $ServiceObject.Name -AccessRights $script:ServiceAccessRight::ReadControl
if ($ServiceHandle -eq [IntPtr]::Zero) { continue }

$SecurityInfo = Get-ObjectSecurityInfo -Handle $ServiceHandle -Type Service
if ($null -eq $SecurityInfo) {
$null = $script:Advapi32::CloseServiceHandle($ServiceHandle)
continue
}

foreach ($Ace in $SecurityInfo.Dacl) {

# Ignore ACEs that do not match our identity.
if ($CurrentUserSids -notcontains $Ace.SecurityIdentifier) { continue }

# Ignore deny ACEs
if ($Ace.AceType -ne "AccessAllowed") {
Write-Warning "Unhandled ACE type found ('$($Ace.AceType)') for service '$($ServiceObject.Name)'."
continue
}

$Permissions = $Ace.AccessMask -as $script:ServiceAccessRight

foreach ($ModificationPermission in $ModificationPermissions) {

if ($Permissions -contains $ModificationPermission) {

$Result = $ServiceObject.PSObject.Copy()
$Result | Add-Member -MemberType "NoteProperty" -Name "AccessRights" -Value $Permissions
$Result | Add-Member -MemberType "NoteProperty" -Name "IdentityReference" -Value $(Convert-SidToName -Sid $Ace.SecurityIdentifier)
$Result
}

break
}
}

$null = $script:Advapi32::CloseServiceHandle($ServiceHandle)
}
}
}

function Get-ModifiableRootFolder {
<#
.SYNOPSIS
Expand Down

0 comments on commit e3348f5

Please sign in to comment.