From bc7be3bdfff885549b44b58d41992735ea1ac728 Mon Sep 17 00:00:00 2001 From: Michael Koehler Date: Fri, 29 Sep 2017 21:48:00 -0400 Subject: [PATCH 1/4] Get-ModifiablePath - Added test to exclude ParentPath of \ from candidates as c:\ is always modifiable and not relevant. This only comes up with parameters being misread as paths. --- Privesc/PowerUp.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Privesc/PowerUp.ps1 b/Privesc/PowerUp.ps1 index 072b03e..465ad6b 100644 --- a/Privesc/PowerUp.ps1 +++ b/Privesc/PowerUp.ps1 @@ -853,7 +853,7 @@ function Get-ModifiablePath { # 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)) { + if ($ParentPath -and ($ParentPath -ne '') -and ($ParentPath -ne '\') -and (Test-Path -Path $ParentPath )) { $CandidatePaths += Resolve-Path -Path $ParentPath -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Path } } @@ -880,7 +880,7 @@ function Get-ModifiablePath { # 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 )) { + if ($ParentPath -and ($ParentPath -ne '') -and ($ParentPath -ne '\') -and (Test-Path -Path $ParentPath )) { $CandidatePaths += Resolve-Path -Path $ParentPath | Select-Object -ExpandProperty Path } } From 5443a4e5d8ceae1057e8471d6fa34976d517ef70 Mon Sep 17 00:00:00 2001 From: Michael Koehler Date: Fri, 29 Sep 2017 22:02:08 -0400 Subject: [PATCH 2/4] Get-ModifiablePath - Handled System.UnauthorizedAccessException --- Privesc/PowerUp.ps1 | 48 +++++++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/Privesc/PowerUp.ps1 b/Privesc/PowerUp.ps1 index 465ad6b..542aa89 100644 --- a/Privesc/PowerUp.ps1 +++ b/Privesc/PowerUp.ps1 @@ -900,37 +900,43 @@ function Get-ModifiablePath { $CandidatePaths | Sort-Object -Unique | ForEach-Object { $CandidatePath = $_ - Get-Acl -Path $CandidatePath | Select-Object -ExpandProperty Access | Where-Object {($_.AccessControlType -match 'Allow')} | ForEach-Object { + try + { + Get-Acl -Path $CandidatePath | Select-Object -ExpandProperty Access | Where-Object {($_.AccessControlType -match 'Allow')} | ForEach-Object { - $FileSystemRights = $_.FileSystemRights.value__ + $FileSystemRights = $_.FileSystemRights.value__ - $Permissions = $AccessMask.Keys | Where-Object { $FileSystemRights -band $_ } | ForEach-Object { $accessMask[$_] } + $Permissions = $AccessMask.Keys | Where-Object { $FileSystemRights -band $_ } | ForEach-Object { $accessMask[$_] } - # the set of permission types that allow for modification - $Comparison = Compare-Object -ReferenceObject $Permissions -DifferenceObject @('GenericWrite', 'GenericAll', 'MaximumAllowed', 'WriteOwner', 'WriteDAC', 'WriteData/AddFile', 'AppendData/AddSubdirectory') -IncludeEqual -ExcludeDifferent + # the set of permission types that allow for modification + $Comparison = Compare-Object -ReferenceObject $Permissions -DifferenceObject @('GenericWrite', 'GenericAll', 'MaximumAllowed', 'WriteOwner', 'WriteDAC', 'WriteData/AddFile', 'AppendData/AddSubdirectory') -IncludeEqual -ExcludeDifferent - if($Comparison) { - if ($_.IdentityReference -notmatch '^S-1-5.*') { - if(-not ($TranslatedIdentityReferences[$_.IdentityReference])) { - # translate the IdentityReference if it's a username and not a SID - $IdentityUser = New-Object System.Security.Principal.NTAccount($_.IdentityReference) - $TranslatedIdentityReferences[$_.IdentityReference] = $IdentityUser.Translate([System.Security.Principal.SecurityIdentifier]) | Select-Object -ExpandProperty Value + if($Comparison) { + if ($_.IdentityReference -notmatch '^S-1-5.*') { + if(-not ($TranslatedIdentityReferences[$_.IdentityReference])) { + # translate the IdentityReference if it's a username and not a SID + $IdentityUser = New-Object System.Security.Principal.NTAccount($_.IdentityReference) + $TranslatedIdentityReferences[$_.IdentityReference] = $IdentityUser.Translate([System.Security.Principal.SecurityIdentifier]) | Select-Object -ExpandProperty Value + } + $IdentitySID = $TranslatedIdentityReferences[$_.IdentityReference] + } + else { + $IdentitySID = $_.IdentityReference } - $IdentitySID = $TranslatedIdentityReferences[$_.IdentityReference] - } - else { - $IdentitySID = $_.IdentityReference - } - if($CurrentUserSids -contains $IdentitySID) { - New-Object -TypeName PSObject -Property @{ - ModifiablePath = $CandidatePath - IdentityReference = $_.IdentityReference - Permissions = $Permissions + if($CurrentUserSids -contains $IdentitySID) { + New-Object -TypeName PSObject -Property @{ + ModifiablePath = $CandidatePath + IdentityReference = $_.IdentityReference + Permissions = $Permissions + } } } } } + catch [System.UnauthorizedAccessException] { + # Get-ACL access failure means user has no access + } } } } From 173ba5c9e0876658d4c3a36ba812c4581a553d07 Mon Sep 17 00:00:00 2001 From: Michael Koehler Date: Fri, 29 Sep 2017 22:05:23 -0400 Subject: [PATCH 3/4] Get-CurrentUserTokenGroupSid - Handled SID being blank --- Privesc/PowerUp.ps1 | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/Privesc/PowerUp.ps1 b/Privesc/PowerUp.ps1 index 542aa89..3720a5b 100644 --- a/Privesc/PowerUp.ps1 +++ b/Privesc/PowerUp.ps1 @@ -996,16 +996,19 @@ function Get-CurrentUserTokenGroupSid { For ($i=0; $i -lt $TokenGroups.GroupCount; $i++) { # convert each token group SID to a displayable string $SidString = '' - $Result = $Advapi32::ConvertSidToStringSid($TokenGroups.Groups[$i].SID, [ref]$SidString);$LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error() - if($Result -eq 0) { - Write-Verbose "Error: $(([ComponentModel.Win32Exception] $LastError).Message)" - } - else { - $GroupSid = New-Object PSObject - $GroupSid | Add-Member Noteproperty 'SID' $SidString - # cast the atttributes field as our SidAttributes enum - $GroupSid | Add-Member Noteproperty 'Attributes' ($TokenGroups.Groups[$i].Attributes -as $SidAttributes) - $GroupSid + if ($TokenGroups.Groups[$i].SID -and $TokenGroups.Groups[$i].SID -ne '') + { + $Result = $Advapi32::ConvertSidToStringSid($TokenGroups.Groups[$i].SID, [ref]$SidString);$LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error() + if($Result -eq 0) { + Write-Verbose "Error: $(([ComponentModel.Win32Exception] $LastError).Message)" + } + else { + $GroupSid = New-Object PSObject + $GroupSid | Add-Member Noteproperty 'SID' $SidString + # cast the atttributes field as our SidAttributes enum + $GroupSid | Add-Member Noteproperty 'Attributes' ($TokenGroups.Groups[$i].Attributes -as $SidAttributes) + $GroupSid + } } } } From 198d9f78dd9f5d5dc57d2cb1876628a6c14bdda3 Mon Sep 17 00:00:00 2001 From: Michael Koehler Date: Fri, 29 Sep 2017 22:12:15 -0400 Subject: [PATCH 4/4] local:Get-GPPInnerFields - Only output a result if one of Password, Username, Changed or NewName is not blank. --- Privesc/PowerUp.ps1 | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/Privesc/PowerUp.ps1 b/Privesc/PowerUp.ps1 index 3720a5b..cf29633 100644 --- a/Privesc/PowerUp.ps1 +++ b/Privesc/PowerUp.ps1 @@ -3681,22 +3681,24 @@ function Get-CachedGPPPassword { $Password += , $DecryptedPassword } - # put [BLANK] in variables - if (-not $Password) {$Password = '[BLANK]'} - if (-not $UserName) {$UserName = '[BLANK]'} - if (-not $Changed) {$Changed = '[BLANK]'} - if (-not $NewName) {$NewName = '[BLANK]'} - - # Create custom object to output results - $ObjectProperties = @{'Passwords' = $Password; - 'UserNames' = $UserName; - 'Changed' = $Changed; - 'NewName' = $NewName; - 'File' = $File} - - $ResultsObject = New-Object -TypeName PSObject -Property $ObjectProperties - Write-Verbose "The password is between {} and may be more than one value." - if ($ResultsObject) {Return $ResultsObject} + if ($Password -or $UserName -or $Changed -or $NewName) { + # put [BLANK] in variables + if (-not $Password) {$Password = '[BLANK]'} + if (-not $UserName) {$UserName = '[BLANK]'} + if (-not $Changed) {$Changed = '[BLANK]'} + if (-not $NewName) {$NewName = '[BLANK]'} + + # Create custom object to output results + $ObjectProperties = @{'Passwords' = $Password; + 'UserNames' = $UserName; + 'Changed' = $Changed; + 'NewName' = $NewName; + 'File' = $File} + + $ResultsObject = New-Object -TypeName PSObject -Property $ObjectProperties + Write-Verbose "The password is between {} and may be more than one value." + if ($ResultsObject) {Return $ResultsObject} + } } catch {Write-Error $Error[0]}