mirror of
https://github.com/PowerShellMafia/PowerSploit
synced 2026-06-08 12:13:33 +00:00
Fixed bug in Get-ModifiablePath that resulted in spaces being expanded to the current directory location
Fixed other logic bugs in Get-ModifiablePath Fixed bug in Add-ServiceDacl when the [ServiceProcess.ServiceController] wasn't loaded yet by Get-Service Error handling for Get-CachedGPPPassword Changed some Write-Warnings to Write-Verbose Updated Privesc Pester tests for PowerUp
This commit is contained in:
+55
-37
@@ -865,27 +865,34 @@ function Get-ModifiablePath {
|
||||
else {
|
||||
ForEach($SeparationCharacterSet in $SeparationCharacterSets) {
|
||||
$TargetPath.Split($SeparationCharacterSet) | Where-Object {$_ -and ($_.trim() -ne '')} | ForEach-Object {
|
||||
if(($SeparationCharacterSet -notmatch ' ')) {
|
||||
$TempPath = $([System.Environment]::ExpandEnvironmentVariables($_))
|
||||
|
||||
if(Test-Path -Path $TempPath -ErrorAction SilentlyContinue) {
|
||||
$CandidatePaths += Resolve-Path -Path $TempPath | Select-Object -ExpandProperty Path
|
||||
}
|
||||
else {
|
||||
# if the path doesn't exist, check if the parent folder allows for modification
|
||||
try {
|
||||
$ParentPath = Split-Path $TempPath -Parent
|
||||
if($ParentPath -and (Test-Path -Path $ParentPath )) {
|
||||
$CandidatePaths += Resolve-Path -Path $ParentPath -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Path
|
||||
}
|
||||
if(($SeparationCharacterSet -notmatch ' ')) {
|
||||
|
||||
$TempPath = $([System.Environment]::ExpandEnvironmentVariables($_)).Trim()
|
||||
|
||||
if($TempPath -and ($TempPath -ne '')) {
|
||||
if(Test-Path -Path $TempPath -ErrorAction SilentlyContinue) {
|
||||
# if the path exists, resolve it and add it to the candidate list
|
||||
$CandidatePaths += Resolve-Path -Path $TempPath | Select-Object -ExpandProperty Path
|
||||
}
|
||||
catch {
|
||||
# because Split-Path doesn't handle -ErrorAction SilentlyContinue nicely
|
||||
|
||||
else {
|
||||
# if the path doesn't exist, check if the parent folder allows for modification
|
||||
try {
|
||||
$ParentPath = (Split-Path -Path $TempPath -Parent).Trim()
|
||||
if($ParentPath -and ($ParentPath -ne '') -and (Test-Path -Path $ParentPath )) {
|
||||
$CandidatePaths += Resolve-Path -Path $ParentPath | Select-Object -ExpandProperty Path
|
||||
}
|
||||
}
|
||||
catch {
|
||||
# trap because Split-Path doesn't handle -ErrorAction SilentlyContinue nicely
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
$CandidatePaths += Resolve-Path -Path $([System.Environment]::ExpandEnvironmentVariables($_)) -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Path
|
||||
# if the separator contains a space
|
||||
$CandidatePaths += Resolve-Path -Path $([System.Environment]::ExpandEnvironmentVariables($_)) -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Path | ForEach-Object {$_.Trim()} | Where-Object {($_ -ne '') -and (Test-Path -Path $_)}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1024,9 +1031,9 @@ function Add-ServiceDacl {
|
||||
service with using the GetServiceHandle Win32 API call and then uses
|
||||
QueryServiceObjectSecurity to retrieve a copy of the security descriptor for the service.
|
||||
|
||||
.PARAMETER Service
|
||||
.PARAMETER Name
|
||||
|
||||
An array of one or more ServiceProcess.ServiceController objects from Get-Service. Required.
|
||||
An array of one or more service names to add a service Dacl for. Passable on the pipeline.
|
||||
|
||||
.EXAMPLE
|
||||
|
||||
@@ -1051,10 +1058,11 @@ function Add-ServiceDacl {
|
||||
|
||||
[OutputType('ServiceProcess.ServiceController')]
|
||||
param (
|
||||
[Parameter(Mandatory=$True, ValueFromPipeline=$True)]
|
||||
[ServiceProcess.ServiceController[]]
|
||||
[Parameter(Position=0, Mandatory=$True, ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)]
|
||||
[Alias('ServiceName')]
|
||||
[String[]]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
$Service
|
||||
$Name
|
||||
)
|
||||
|
||||
BEGIN {
|
||||
@@ -1062,8 +1070,8 @@ function Add-ServiceDacl {
|
||||
[OutputType([IntPtr])]
|
||||
param (
|
||||
[Parameter(Mandatory=$True, ValueFromPipeline=$True)]
|
||||
[ServiceProcess.ServiceController]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[ValidateScript({ $_ -as 'ServiceProcess.ServiceController' })]
|
||||
$Service
|
||||
)
|
||||
|
||||
@@ -1078,13 +1086,17 @@ function Add-ServiceDacl {
|
||||
}
|
||||
|
||||
PROCESS {
|
||||
ForEach ($IndividualService in $Service) {
|
||||
ForEach($ServiceName in $Name) {
|
||||
|
||||
$IndividualService = Get-Service -Name $ServiceName -ErrorAction Stop
|
||||
|
||||
try {
|
||||
Write-Verbose "Add-ServiceDacl IndividualService : $($IndividualService.Name)"
|
||||
$ServiceHandle = Get-ServiceReadControlHandle -Service $IndividualService
|
||||
}
|
||||
catch {
|
||||
$ServiceHandle = $Null
|
||||
Write-Warning "Error opening up the service handle with read control for: $($IndividualService.Name)"
|
||||
Write-Verbose "Error opening up the service handle with read control for $($IndividualService.Name) : $_"
|
||||
}
|
||||
|
||||
if ($ServiceHandle -and ($ServiceHandle -ne [IntPtr]::Zero)) {
|
||||
@@ -1214,7 +1226,7 @@ function Set-ServiceBinPath {
|
||||
}
|
||||
catch {
|
||||
$ServiceHandle = $Null
|
||||
Write-Warning "Error opening up the service handle with read control for $($TargetService.Name) : $_"
|
||||
Write-Verbose "Error opening up the service handle with read control for $IndividualService : $_"
|
||||
}
|
||||
|
||||
if ($ServiceHandle -and ($ServiceHandle -ne [IntPtr]::Zero)) {
|
||||
@@ -1224,7 +1236,7 @@ function Set-ServiceBinPath {
|
||||
$Result = $Advapi32::ChangeServiceConfig($ServiceHandle, $SERVICE_NO_CHANGE, $SERVICE_NO_CHANGE, $SERVICE_NO_CHANGE, "$binPath", [IntPtr]::Zero, [IntPtr]::Zero, [IntPtr]::Zero, [IntPtr]::Zero, [IntPtr]::Zero, [IntPtr]::Zero);$LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error()
|
||||
|
||||
if ($Result -ne 0) {
|
||||
Write-Verbose "binPath for $($TargetService.Name) successfully set to '$binPath'"
|
||||
Write-Verbose "binPath for $IndividualService successfully set to '$binPath'"
|
||||
$True
|
||||
}
|
||||
else {
|
||||
@@ -1364,7 +1376,7 @@ function Test-ServiceDaclPermission {
|
||||
|
||||
ForEach($IndividualService in $Name) {
|
||||
|
||||
$TargetService = Get-Service -Name $IndividualService | Add-ServiceDacl
|
||||
$TargetService = $IndividualService | Add-ServiceDacl
|
||||
|
||||
if($TargetService -and $TargetService.Dacl) {
|
||||
|
||||
@@ -1381,7 +1393,7 @@ function Test-ServiceDaclPermission {
|
||||
ForEach($TargetPermission in $TargetPermissions) {
|
||||
# check permissions && style
|
||||
if (($ServiceDacl.AccessRights -band $AccessMask[$TargetPermission]) -ne $AccessMask[$TargetPermission]) {
|
||||
Write-Verbose "Current user doesn't have '$TargetPermission' for $($TargetService.Name)"
|
||||
# Write-Verbose "Current user doesn't have '$TargetPermission' for $($TargetService.Name)"
|
||||
$AllMatched = $False
|
||||
break
|
||||
}
|
||||
@@ -1394,7 +1406,7 @@ function Test-ServiceDaclPermission {
|
||||
ForEach($TargetPermission in $TargetPermissions) {
|
||||
# check permissions || style
|
||||
if (($ServiceDacl.AccessRights -band $AccessMask[$TargetPermission]) -eq $AccessMask[$TargetPermission]) {
|
||||
Write-Verbose "Current user has '$TargetPermission' for $($TargetService.Name)"
|
||||
Write-Verbose "Current user has '$TargetPermission' for $IndividualService"
|
||||
$TargetService
|
||||
break
|
||||
}
|
||||
@@ -1404,7 +1416,7 @@ function Test-ServiceDaclPermission {
|
||||
}
|
||||
}
|
||||
else {
|
||||
Write-Warning "Error enumerating the Dacl for service $($TargetService.Name)"
|
||||
Write-Verbose "Error enumerating the Dacl for service $IndividualService"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1434,6 +1446,7 @@ function Get-ServiceUnquoted {
|
||||
|
||||
https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/windows/local/trusted_service_path.rb
|
||||
#>
|
||||
[CmdletBinding()] param()
|
||||
|
||||
# find all paths to service .exe's that have a space in the path and aren't quoted
|
||||
$VulnServices = Get-WmiObject -Class win32_service | Where-Object {$_} | Where-Object {($_.pathname -ne $null) -and ($_.pathname.trim() -ne '')} | Where-Object { (-not $_.pathname.StartsWith("`"")) -and (-not $_.pathname.StartsWith("'"))} | Where-Object {($_.pathname.Substring(0, $_.pathname.ToLower().IndexOf(".exe") + 4)) -match ".* .*"}
|
||||
@@ -1441,7 +1454,7 @@ function Get-ServiceUnquoted {
|
||||
if ($VulnServices) {
|
||||
ForEach ($Service in $VulnServices) {
|
||||
|
||||
$ModifiableFiles = $Service.pathname | Get-ModifiablePath
|
||||
$ModifiableFiles = $Service.pathname.split(' ') | Get-ModifiablePath
|
||||
|
||||
$ModifiableFiles | Where-Object {$_ -and $_.ModifiablePath -and ($_.ModifiablePath -ne '')} | Foreach-Object {
|
||||
$ServiceRestart = Test-ServiceDaclPermission -PermissionSet 'Restart' -Name $Service.name
|
||||
@@ -1487,6 +1500,7 @@ function Get-ModifiableServiceFile {
|
||||
|
||||
Get a set of potentially exploitable service binares/config files.
|
||||
#>
|
||||
[CmdletBinding()] param()
|
||||
|
||||
Get-WMIObject -Class win32_service | Where-Object {$_ -and $_.pathname} | ForEach-Object {
|
||||
|
||||
@@ -1537,6 +1551,7 @@ function Get-ModifiableService {
|
||||
|
||||
Get a set of potentially exploitable services.
|
||||
#>
|
||||
[CmdletBinding()] param()
|
||||
|
||||
Get-Service | Test-ServiceDaclPermission -PermissionSet 'ChangeConfig' | ForEach-Object {
|
||||
|
||||
@@ -1612,7 +1627,7 @@ function Get-ServiceDetail {
|
||||
$_
|
||||
}
|
||||
catch{
|
||||
Write-Warning "Error: $_"
|
||||
Write-Verbose "Error: $_"
|
||||
$null
|
||||
}
|
||||
}
|
||||
@@ -3689,12 +3704,15 @@ function Get-CachedGPPPassword {
|
||||
# discover any locally cached GPP .xml files
|
||||
$XMlFiles = Get-ChildItem -Path $AllUsers -Recurse -Include 'Groups.xml','Services.xml','Scheduledtasks.xml','DataSources.xml','Printers.xml','Drives.xml' -Force -ErrorAction SilentlyContinue
|
||||
|
||||
if ( -not $XMlFiles ) { throw 'No preference files found.' }
|
||||
if ( -not $XMlFiles ) {
|
||||
Write-Verbose 'No preference files found.'
|
||||
}
|
||||
else {
|
||||
Write-Verbose "Found $($XMLFiles | Measure-Object | Select-Object -ExpandProperty Count) files that could contain passwords."
|
||||
|
||||
Write-Verbose "Found $($XMLFiles | Measure-Object | Select-Object -ExpandProperty Count) files that could contain passwords."
|
||||
|
||||
ForEach ($File in $XMLFiles) {
|
||||
Get-GppInnerFields $File.Fullname
|
||||
ForEach ($File in $XMLFiles) {
|
||||
Get-GppInnerFields $File.Fullname
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3839,7 +3857,7 @@ function Invoke-AllChecks {
|
||||
|
||||
"`n`n[*] Checking %PATH% for potentially hijackable DLL locations..."
|
||||
$Results = Find-PathDLLHijack
|
||||
$Results | Foreach-Object {
|
||||
$Results | Where-Object {$_} | Foreach-Object {
|
||||
$AbuseString = "Write-HijackDll -DllPath '$($_.ModifiablePath)\wlbsctrl.dll'"
|
||||
$_ | Add-Member Noteproperty 'AbuseFunction' $AbuseString
|
||||
$_
|
||||
|
||||
+47
-6
@@ -129,7 +129,7 @@ Describe 'Get-ModifiablePath' {
|
||||
Describe 'Get-CurrentUserTokenGroupSid' {
|
||||
|
||||
if(-not $(Test-IsAdmin)) {
|
||||
Throw "'Add-ServiceDacl' Pester test needs local administrator privileges."
|
||||
Throw "'Get-CurrentUserTokenGroupSid' Pester test needs local administrator privileges."
|
||||
}
|
||||
|
||||
It 'Should not throw.' {
|
||||
@@ -167,21 +167,62 @@ Describe 'Add-ServiceDacl' {
|
||||
{Get-Service | Add-ServiceDacl} | Should Not Throw
|
||||
}
|
||||
|
||||
It 'Should accept a service as a parameter argument.' {
|
||||
$Service = Get-Service | Select-Object -First 1
|
||||
$ServiceWithDacl = Add-ServiceDacl -Service $Service
|
||||
It 'Should fail for a non-existent service.' {
|
||||
$ServiceName = Get-RandomName
|
||||
{$Result = Add-ServiceDacl -Name $ServiceName} | Should Throw
|
||||
}
|
||||
|
||||
It 'Should accept a service name as a parameter argument.' {
|
||||
$ServiceName = Get-Service | Select-Object -First 1 | Select-Object -ExpandProperty Name
|
||||
$ServiceWithDacl = Add-ServiceDacl -Name $ServiceName
|
||||
|
||||
if(-not $ServiceWithDacl.Dacl) {
|
||||
Throw "'Add-ServiceDacl' doesn't return a Dacl for a service passed as parameter."
|
||||
}
|
||||
}
|
||||
|
||||
It 'Should accept an array of service names as a parameter argument.' {
|
||||
$ServiceNames = Get-Service | Select-Object -First 5 | Select-Object -ExpandProperty Name
|
||||
$ServicesWithDacl = Add-ServiceDacl -Name $ServiceNames
|
||||
|
||||
if(-not $ServicesWithDacl.Dacl) {
|
||||
Throw "'Add-ServiceDacl' doesn't return Dacls for an array of service names as a parameter."
|
||||
}
|
||||
}
|
||||
|
||||
It 'Should accept a service object on the pipeline.' {
|
||||
$Service = Get-Service | Select-Object -First 1
|
||||
$ServiceWithDacl = $Service | Add-ServiceDacl
|
||||
|
||||
if(-not $ServiceWithDacl.Dacl) {
|
||||
Throw "'Add-ServiceDacl' doesn't return a Dacl for a service passed as parameter."
|
||||
Throw "'Add-ServiceDacl' doesn't return a Dacl for a service object on the pipeline."
|
||||
}
|
||||
}
|
||||
|
||||
It 'Should accept a service name on the pipeline.' {
|
||||
$ServiceName = Get-Service | Select-Object -First 1 | Select-Object -ExpandProperty Name
|
||||
$ServiceWithDacl = $ServiceName | Add-ServiceDacl
|
||||
|
||||
if(-not $ServiceWithDacl.Dacl) {
|
||||
Throw "'Add-ServiceDacl' doesn't return a Dacl for a service name on the pipeline."
|
||||
}
|
||||
}
|
||||
|
||||
It 'Should accept multiple service objects on the pipeline.' {
|
||||
$Services = Get-Service | Select-Object -First 5
|
||||
$ServicesWithDacl = $Services | Add-ServiceDacl
|
||||
|
||||
if(-not $ServicesWithDacl.Dacl) {
|
||||
Throw "'Add-ServiceDacl' doesn't return Dacls for multiple service objects on the pipeline."
|
||||
}
|
||||
}
|
||||
|
||||
It 'Should accept multiple service names on the pipeline.' {
|
||||
$ServiceNames = Get-Service | Select-Object -First 5 | Select-Object -ExpandProperty Name
|
||||
$ServicesWithDacl = $ServiceNames | Add-ServiceDacl
|
||||
|
||||
if(-not $ServicesWithDacl.Dacl) {
|
||||
Throw "'Add-ServiceDacl' doesn't return Dacls for multiple service names on the pipeline."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -407,7 +448,7 @@ Describe 'Test-ServiceDaclPermission' {
|
||||
Describe 'Get-ServiceUnquoted' {
|
||||
|
||||
if(-not $(Test-IsAdmin)) {
|
||||
Throw "'Get-ServicePermission' Pester test needs local administrator privileges."
|
||||
Throw "'Get-ServiceUnquoted' Pester test needs local administrator privileges."
|
||||
}
|
||||
|
||||
It "Should not throw." {
|
||||
|
||||
Reference in New Issue
Block a user