diff options
author | Harmj0y <will@harmj0y.net> | 2016-06-23 17:51:17 -0400 |
---|---|---|
committer | Harmj0y <will@harmj0y.net> | 2016-06-23 17:51:17 -0400 |
commit | 8dea905998fbebfbcc14bc08cd3dd43a0d671a97 (patch) | |
tree | bb7dbf03daf163c1316cd57882178e8891f60b5f | |
parent | 4b40e8609c75b00a6ccbf58fc121882975854f59 (diff) | |
download | PowerSploit-8dea905998fbebfbcc14bc08cd3dd43a0d671a97.tar.gz PowerSploit-8dea905998fbebfbcc14bc08cd3dd43a0d671a97.zip |
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
-rw-r--r-- | Privesc/PowerUp.ps1 | 90 | ||||
-rw-r--r-- | Tests/Privesc.tests.ps1 | 53 |
2 files changed, 101 insertions, 42 deletions
diff --git a/Privesc/PowerUp.ps1 b/Privesc/PowerUp.ps1 index 39e571a..0b62245 100644 --- a/Privesc/PowerUp.ps1 +++ b/Privesc/PowerUp.ps1 @@ -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 - } + $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 $_ diff --git a/Tests/Privesc.tests.ps1 b/Tests/Privesc.tests.ps1 index a36338e..9b9872b 100644 --- a/Tests/Privesc.tests.ps1 +++ b/Tests/Privesc.tests.ps1 @@ -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." { |