Get-TokenInformation.ps1
#Gets important information about the token such as the logon type associated with the logon function Get-TokenInformation { param ( [Parameter(Position=0, Mandatory=$true)] [IntPtr] $hToken ) $ReturnObj = $null $TokenStatsSize = [System.Runtime.InteropServices.Marshal]::SizeOf([Type]$TOKEN_STATISTICS) [IntPtr]$TokenStatsPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($TokenStatsSize) [UInt32]$RealSize = 0 $Success = $GetTokenInformation.Invoke($hToken, $TOKEN_INFORMATION_CLASS::TokenStatistics, $TokenStatsPtr, $TokenStatsSize, [Ref]$RealSize) if (-not $Success) { $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() Write-Warning "GetTokenInformation failed. Error code: $ErrorCode" } else { $TokenStats = [System.Runtime.InteropServices.Marshal]::PtrToStructure($TokenStatsPtr, [Type]$TOKEN_STATISTICS) #Query LSA to determine what the logontype of the session is that the token corrosponds to, as well as the username/domain of the logon $LuidPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal([System.Runtime.InteropServices.Marshal]::SizeOf([Type]$LUID)) [System.Runtime.InteropServices.Marshal]::StructureToPtr($TokenStats.AuthenticationId, $LuidPtr, $false) [IntPtr]$LogonSessionDataPtr = [IntPtr]::Zero $ReturnVal = $LsaGetLogonSessionData.Invoke($LuidPtr, [Ref]$LogonSessionDataPtr) if ($ReturnVal -ne 0 -and $LogonSessionDataPtr -eq [IntPtr]::Zero) { Write-Warning "Call to LsaGetLogonSessionData failed. Error code: $ReturnVal. LogonSessionDataPtr = $LogonSessionDataPtr" } else { $LogonSessionData = [System.Runtime.InteropServices.Marshal]::PtrToStructure($LogonSessionDataPtr, [Type]$SECURITY_LOGON_SESSION_DATA) if ($LogonSessionData.Username.Buffer -ne [IntPtr]::Zero -and $LogonSessionData.LoginDomain.Buffer -ne [IntPtr]::Zero) { #Get the username and domainname associated with the token $Username = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($LogonSessionData.Username.Buffer, $LogonSessionData.Username.Length/2) $Domain = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($LogonSessionData.LoginDomain.Buffer, $LogonSessionData.LoginDomain.Length/2) #If UserName is for the computer account, figure out what account it actually is (SYSTEM, NETWORK SERVICE) #Only do this for the computer account because other accounts return correctly. Also, doing this for a domain account #results in querying the domain controller which is unwanted. if ($Username -ieq "$($env:COMPUTERNAME)`$") { [UInt32]$Size = 100 [UInt32]$NumUsernameChar = $Size / 2 [UInt32]$NumDomainChar = $Size / 2 [UInt32]$SidNameUse = 0 $UsernameBuffer = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($Size) $DomainBuffer = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($Size) $Success = $LookupAccountSidW.Invoke([IntPtr]::Zero, $LogonSessionData.Sid, $UsernameBuffer, [Ref]$NumUsernameChar, $DomainBuffer, [Ref]$NumDomainChar, [Ref]$SidNameUse) if ($Success) { $Username = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($UsernameBuffer) $Domain = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($DomainBuffer) } else { $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() Write-Warning "Error calling LookupAccountSidW. Error code: $ErrorCode" } [System.Runtime.InteropServices.Marshal]::FreeHGlobal($UsernameBuffer) $UsernameBuffer = [IntPtr]::Zero [System.Runtime.InteropServices.Marshal]::FreeHGlobal($DomainBuffer) $DomainBuffer = [IntPtr]::Zero } $ReturnObj = New-Object PSObject $ReturnObj | Add-Member -Type NoteProperty -Name Domain -Value $Domain $ReturnObj | Add-Member -Type NoteProperty -Name Username -Value $Username $ReturnObj | Add-Member -Type NoteProperty -Name hToken -Value $hToken $ReturnObj | Add-Member -Type NoteProperty -Name LogonType -Value $LogonSessionData.LogonType #Query additional info about the token such as if it is elevated $ReturnObj | Add-Member -Type NoteProperty -Name IsElevated -Value $false $TokenElevationSize = [System.Runtime.InteropServices.Marshal]::SizeOf([Type]$TOKEN_ELEVATION) $TokenElevationPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($TokenElevationSize) [UInt32]$RealSize = 0 $Success = $GetTokenInformation.Invoke($hToken, $TOKEN_INFORMATION_CLASS::TokenElevation, $TokenElevationPtr, $TokenElevationSize, [Ref]$RealSize) if (-not $Success) { $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() Write-Warning "GetTokenInformation failed to retrieve TokenElevation status. ErrorCode: $ErrorCode" } else { $TokenElevation = [System.Runtime.InteropServices.Marshal]::PtrToStructure($TokenelevationPtr, [Type]$TOKEN_ELEVATION) if ($TokenElevation.TokenIsElevated -ne 0) { $ReturnObj.IsElevated = $true } } [System.Runtime.InteropServices.Marshal]::FreeHGlobal($TokenElevationPtr) #Query the token type to determine if the token is a primary or impersonation token $ReturnObj | Add-Member -Type NoteProperty -Name TokenType -Value "UnableToRetrieve" [UInt32]$TokenTypeSize = 4 [IntPtr]$TokenTypePtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($TokenTypeSize) [UInt32]$RealSize = 0 $Success = $GetTokenInformation.Invoke($hToken, $TOKEN_INFORMATION_CLASS::TokenType, $TokenTypePtr, $TokenTypeSize, [Ref]$RealSize) if (-not $Success) { $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() Write-Warning "GetTokenInformation failed to retrieve TokenImpersonationLevel status. ErrorCode: $ErrorCode" } else { [UInt32]$TokenType = [System.Runtime.InteropServices.Marshal]::PtrToStructure($TokenTypePtr, [Type][UInt32]) switch($TokenType) { 1 {$ReturnObj.TokenType = "Primary"} 2 {$ReturnObj.TokenType = "Impersonation"} } } [System.Runtime.InteropServices.Marshal]::FreeHGlobal($TokenTypePtr) #Query the impersonation level if the token is an Impersonation token if ($ReturnObj.TokenType -ieq "Impersonation") { $ReturnObj | Add-Member -Type NoteProperty -Name ImpersonationLevel -Value "UnableToRetrieve" [UInt32]$ImpersonationLevelSize = 4 [IntPtr]$ImpersonationLevelPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($ImpersonationLevelSize) #sizeof uint32 [UInt32]$RealSize = 0 $Success = $GetTokenInformation.Invoke($hToken, $TOKEN_INFORMATION_CLASS::TokenImpersonationLevel, $ImpersonationLevelPtr, $ImpersonationLevelSize, [Ref]$RealSize) if (-not $Success) { $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() Write-Warning "GetTokenInformation failed to retrieve TokenImpersonationLevel status. ErrorCode: $ErrorCode" } else { [UInt32]$ImpersonationLevel = [System.Runtime.InteropServices.Marshal]::PtrToStructure($ImpersonationLevelPtr, [Type][UInt32]) switch ($ImpersonationLevel) { 0 { $ReturnObj.ImpersonationLevel = "SecurityAnonymous" } 1 { $ReturnObj.ImpersonationLevel = "SecurityIdentification" } 2 { $ReturnObj.ImpersonationLevel = "SecurityImpersonation" } 3 { $ReturnObj.ImpersonationLevel = "SecurityDelegation" } } } [System.Runtime.InteropServices.Marshal]::FreeHGlobal($ImpersonationLevelPtr) } #Query the token sessionid $ReturnObj | Add-Member -Type NoteProperty -Name SessionID -Value "Unknown" [UInt32]$TokenSessionIdSize = 4 [IntPtr]$TokenSessionIdPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($TokenSessionIdSize) [UInt32]$RealSize = 0 $Success = $GetTokenInformation.Invoke($hToken, $TOKEN_INFORMATION_CLASS::TokenSessionId, $TokenSessionIdPtr, $TokenSessionIdSize, [Ref]$RealSize) if (-not $Success) { $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() Write-Warning "GetTokenInformation failed to retrieve Token SessionId. ErrorCode: $ErrorCode" } else { [UInt32]$TokenSessionId = [System.Runtime.InteropServices.Marshal]::PtrToStructure($TokenSessionIdPtr, [Type][UInt32]) $ReturnObj.SessionID = $TokenSessionId } [System.Runtime.InteropServices.Marshal]::FreeHGlobal($TokenSessionIdPtr) #Query the token privileges $ReturnObj | Add-Member -Type NoteProperty -Name PrivilegesEnabled -Value @() $ReturnObj | Add-Member -Type NoteProperty -Name PrivilegesAvailable -Value @() [UInt32]$TokenPrivilegesSize = 1000 [IntPtr]$TokenPrivilegesPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($TokenPrivilegesSize) [UInt32]$RealSize = 0 $Success = $GetTokenInformation.Invoke($hToken, $TOKEN_INFORMATION_CLASS::TokenPrivileges, $TokenPrivilegesPtr, $TokenPrivilegesSize, [Ref]$RealSize) if (-not $Success) { $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() Write-Warning "GetTokenInformation failed to retrieve Token SessionId. ErrorCode: $ErrorCode" } else { $TokenPrivileges = [System.Runtime.InteropServices.Marshal]::PtrToStructure($TokenPrivilegesPtr, [Type]$TOKEN_PRIVILEGES) #Loop through each privilege [IntPtr]$PrivilegesBasePtr = [IntPtr](Add-SignedIntAsUnsigned $TokenPrivilegesPtr ([System.Runtime.InteropServices.Marshal]::OffsetOf([Type]$TOKEN_PRIVILEGES, "Privileges"))) $LuidAndAttributeSize = [System.Runtime.InteropServices.Marshal]::SizeOf([Type]$LUID_AND_ATTRIBUTES) for ($i = 0; $i -lt $TokenPrivileges.PrivilegeCount; $i++) { $LuidAndAttributePtr = [IntPtr](Add-SignedIntAsUnsigned $PrivilegesBasePtr ($LuidAndAttributeSize * $i)) $LuidAndAttribute = [System.Runtime.InteropServices.Marshal]::PtrToStructure($LuidAndAttributePtr, [Type]$LUID_AND_ATTRIBUTES) #Lookup privilege name [UInt32]$PrivilegeNameSize = 60 $PrivilegeNamePtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($PrivilegeNameSize) $PLuid = $LuidAndAttributePtr #The Luid structure is the first object in the LuidAndAttributes structure, so a ptr to LuidAndAttributes also points to Luid $Success = $LookupPrivilegeNameW.Invoke([IntPtr]::Zero, $PLuid, $PrivilegeNamePtr, [Ref]$PrivilegeNameSize) if (-not $Success) { $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() Write-Warning "Call to LookupPrivilegeNameW failed. Error code: $ErrorCode. RealSize: $PrivilegeNameSize" } $PrivilegeName = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($PrivilegeNamePtr) #Get the privilege attributes $PrivilegeStatus = "" $Enabled = $false if ($LuidAndAttribute.Attributes -eq 0) { $Enabled = $false } if (($LuidAndAttribute.Attributes -band $Win32Constants.SE_PRIVILEGE_ENABLED_BY_DEFAULT) -eq $Win32Constants.SE_PRIVILEGE_ENABLED_BY_DEFAULT) #enabled by default { $Enabled = $true } if (($LuidAndAttribute.Attributes -band $Win32Constants.SE_PRIVILEGE_ENABLED) -eq $Win32Constants.SE_PRIVILEGE_ENABLED) #enabled { $Enabled = $true } if (($LuidAndAttribute.Attributes -band $Win32Constants.SE_PRIVILEGE_REMOVED) -eq $Win32Constants.SE_PRIVILEGE_REMOVED) #SE_PRIVILEGE_REMOVED. This should never exist. Write a warning if it is found so I can investigate why/how it was found. { Write-Warning "Unexpected behavior: Found a token with SE_PRIVILEGE_REMOVED. Please report this as a bug. " } if ($Enabled) { $ReturnObj.PrivilegesEnabled += ,$PrivilegeName } else { $ReturnObj.PrivilegesAvailable += ,$PrivilegeName } [System.Runtime.InteropServices.Marshal]::FreeHGlobal($PrivilegeNamePtr) } } [System.Runtime.InteropServices.Marshal]::FreeHGlobal($TokenPrivilegesPtr) } else { Write-Verbose "Call to LsaGetLogonSessionData succeeded. This SHOULD be SYSTEM since there is no data. $($LogonSessionData.UserName.Length)" } #Free LogonSessionData $ntstatus = $LsaFreeReturnBuffer.Invoke($LogonSessionDataPtr) $LogonSessionDataPtr = [IntPtr]::Zero if ($ntstatus -ne 0) { Write-Warning "Call to LsaFreeReturnBuffer failed. Error code: $ntstatus" } } [System.Runtime.InteropServices.Marshal]::FreeHGlobal($LuidPtr) $LuidPtr = [IntPtr]::Zero } [System.Runtime.InteropServices.Marshal]::FreeHGlobal($TokenStatsPtr) $TokenStatsPtr = [IntPtr]::Zero return $ReturnObj } |