获得登录权限

时间:2014-07-15 06:28:31

标签: windows security winapi

如果给定用户有SeInteractiveLogonRight和SeRemoteInteractiveLogonRight to find out,我会尝试user rights。最初我认为我使用了GetTokenInformation函数,提供了TokenPrivileges的TOKEN_INFORMATION_CLASS。不幸的是,它没有成功,因为只返回了特权,没有用户权限,如SeInteractiveLogonRight和SeRemoteInteractiveLogonRight。

This page最后有一句相当神秘的句子:

  

GetTokenInformation函数将获取有关帐户的信息   权限,如果TokenGroups,而不是TokenPrivileges,被指定为   TokenInformationClass参数的值。

我不明白这一点,因为如果我调用此函数传递TokenGroups,我得到的只是组sids - 本地和域。没有返回类似登录权限的内容。你能解释一下吗?

现在,如果有其他方式获取我想要的信息,请告诉我。我尝试调用LsaEnumerateAccountRights,但这不起作用,因为如果帐户直接持有特权,而不是作为组成员资格的一部分,则返回特权。我需要找到有效的权限,即使它是通过多级组成员身份获得的。

与上述GetTokenInformation相反,确实返回了有效权限,但我似乎无法找到返回登录权限的方法。

因为在stackoverflow上习惯显示一些代码,所以这是我的。对不起它的powershell,因为这个问题更适合c ++开发者,但这就是我推动它的方式。

这不是一个PowerShell问题,如果你能提供任何与c ++相关的指针,他们也会提供帮助,我只需要在概念上解决这个问题。语言并不重要。

GetTokenInformation代码基于some code from github,位于以下位置:

#Function written by Matt Graeber, Twitter: @mattifestation, Blog: http://www.exploit-monday.com/
Function Get-DelegateType
{
  Param
  (
      [OutputType([Type])]

      [Parameter( Position = 0)]
      [Type[]]
      $Parameters = (New-Object Type[](0)),

      [Parameter( Position = 1 )]
      [Type]
      $ReturnType = [Void]
  )

  $Domain = [AppDomain]::CurrentDomain
  $DynAssembly = New-Object System.Reflection.AssemblyName('ReflectedDelegate')
  $AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, [System.Reflection.Emit.AssemblyBuilderAccess]::Run)
  $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('InMemoryModule', $false)
  $TypeBuilder = $ModuleBuilder.DefineType('MyDelegateType', 'Class, Public, Sealed, AnsiClass, AutoClass', [System.MulticastDelegate])
  $ConstructorBuilder = $TypeBuilder.DefineConstructor('RTSpecialName, HideBySig, Public', [System.Reflection.CallingConventions]::Standard, $Parameters)
  $ConstructorBuilder.SetImplementationFlags('Runtime, Managed')
  $MethodBuilder = $TypeBuilder.DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $ReturnType, $Parameters)
  $MethodBuilder.SetImplementationFlags('Runtime, Managed')

  Write-Output $TypeBuilder.CreateType()
}


#Function written by Matt Graeber, Twitter: @mattifestation, Blog: http://www.exploit-monday.com/
Function Get-ProcAddress
{
  Param
  (
      [OutputType([IntPtr])]

      [Parameter( Position = 0, Mandatory = $True )]
      [String]
      $Module,

      [Parameter( Position = 1, Mandatory = $True )]
      [String]
      $Procedure
  )

  # Get a reference to System.dll in the GAC
  $SystemAssembly = [AppDomain]::CurrentDomain.GetAssemblies() |
      Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split('\\')[-1].Equals('System.dll') }
  $UnsafeNativeMethods = $SystemAssembly.GetType('Microsoft.Win32.UnsafeNativeMethods')
  # Get a reference to the GetModuleHandle and GetProcAddress methods
  $GetModuleHandle = $UnsafeNativeMethods.GetMethod('GetModuleHandle')
  $GetProcAddress = $UnsafeNativeMethods.GetMethod('GetProcAddress')
  # Get a handle to the module specified
  $Kern32Handle = $GetModuleHandle.Invoke($null, @($Module))
  $tmpPtr = New-Object IntPtr
  $HandleRef = New-Object System.Runtime.InteropServices.HandleRef($tmpPtr, $Kern32Handle)

  # Return the address of the function
  Write-Output $GetProcAddress.Invoke($null, @([System.Runtime.InteropServices.HandleRef]$HandleRef, $Procedure))
}

$Domain = [AppDomain]::CurrentDomain
$DynamicAssembly = New-Object System.Reflection.AssemblyName('DynamicAssembly')
$AssemblyBuilder = $Domain.DefineDynamicAssembly($DynamicAssembly, [System.Reflection.Emit.AssemblyBuilderAccess]::Run)
$ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('DynamicModule', $false)
$ConstructorInfo = [System.Runtime.InteropServices.MarshalAsAttribute].GetConstructors()[0]

#ENUMs
$TypeBuilder = $ModuleBuilder.DefineEnum('TOKEN_INFORMATION_CLASS', 'Public', [UInt32])
$TypeBuilder.DefineLiteral('TokenUser', [UInt32] 1) | Out-Null
$TypeBuilder.DefineLiteral('TokenGroups', [UInt32] 2) | Out-Null
$TypeBuilder.DefineLiteral('TokenPrivileges', [UInt32] 3) | Out-Null
$TypeBuilder.DefineLiteral('TokenOwner', [UInt32] 4) | Out-Null
$TypeBuilder.DefineLiteral('TokenPrimaryGroup', [UInt32] 5) | Out-Null
$TypeBuilder.DefineLiteral('TokenDefaultDacl', [UInt32] 6) | Out-Null
$TypeBuilder.DefineLiteral('TokenSource', [UInt32] 7) | Out-Null
$TypeBuilder.DefineLiteral('TokenType', [UInt32] 8) | Out-Null
$TypeBuilder.DefineLiteral('TokenImpersonationLevel', [UInt32] 9) | Out-Null
$TypeBuilder.DefineLiteral('TokenStatistics', [UInt32] 10) | Out-Null
$TypeBuilder.DefineLiteral('TokenRestrictedSids', [UInt32] 11) | Out-Null
$TypeBuilder.DefineLiteral('TokenSessionId', [UInt32] 12) | Out-Null
$TypeBuilder.DefineLiteral('TokenGroupsAndPrivileges', [UInt32] 13) | Out-Null
$TypeBuilder.DefineLiteral('TokenSessionReference', [UInt32] 14) | Out-Null
$TypeBuilder.DefineLiteral('TokenSandBoxInert', [UInt32] 15) | Out-Null
$TypeBuilder.DefineLiteral('TokenAuditPolicy', [UInt32] 16) | Out-Null
$TypeBuilder.DefineLiteral('TokenOrigin', [UInt32] 17) | Out-Null
$TypeBuilder.DefineLiteral('TokenElevationType', [UInt32] 18) | Out-Null
$TypeBuilder.DefineLiteral('TokenLinkedToken', [UInt32] 19) | Out-Null
$TypeBuilder.DefineLiteral('TokenElevation', [UInt32] 20) | Out-Null
$TypeBuilder.DefineLiteral('TokenHasRestrictions', [UInt32] 21) | Out-Null
$TypeBuilder.DefineLiteral('TokenAccessInformation', [UInt32] 22) | Out-Null
$TypeBuilder.DefineLiteral('TokenVirtualizationAllowed', [UInt32] 23) | Out-Null
$TypeBuilder.DefineLiteral('TokenVirtualizationEnabled', [UInt32] 24) | Out-Null
$TypeBuilder.DefineLiteral('TokenIntegrityLevel', [UInt32] 25) | Out-Null
$TypeBuilder.DefineLiteral('TokenUIAccess', [UInt32] 26) | Out-Null
$TypeBuilder.DefineLiteral('TokenMandatoryPolicy', [UInt32] 27) | Out-Null
$TypeBuilder.DefineLiteral('TokenLogonSid', [UInt32] 28) | Out-Null
$TypeBuilder.DefineLiteral('TokenIsAppContainer', [UInt32] 29) | Out-Null
$TypeBuilder.DefineLiteral('TokenCapabilities', [UInt32] 30) | Out-Null
$TypeBuilder.DefineLiteral('TokenAppContainerSid', [UInt32] 31) | Out-Null
$TypeBuilder.DefineLiteral('TokenAppContainerNumber', [UInt32] 32) | Out-Null
$TypeBuilder.DefineLiteral('TokenUserClaimAttributes', [UInt32] 33) | Out-Null
$TypeBuilder.DefineLiteral('TokenDeviceClaimAttributes', [UInt32] 34) | Out-Null
$TypeBuilder.DefineLiteral('TokenRestrictedUserClaimAttributes', [UInt32] 35) | Out-Null
$TypeBuilder.DefineLiteral('TokenRestrictedDeviceClaimAttributes', [UInt32] 36) | Out-Null
$TypeBuilder.DefineLiteral('TokenDeviceGroups', [UInt32] 37) | Out-Null
$TypeBuilder.DefineLiteral('TokenRestrictedDeviceGroups', [UInt32] 38) | Out-Null
$TypeBuilder.DefineLiteral('TokenSecurityAttributes', [UInt32] 39) | Out-Null
$TypeBuilder.DefineLiteral('TokenIsRestricted', [UInt32] 40) | Out-Null
$TypeBuilder.DefineLiteral('MaxTokenInfoClass', [UInt32] 41) | Out-Null
$TOKEN_INFORMATION_CLASS = $TypeBuilder.CreateType()

$GetTokenInformationAddr = Get-ProcAddress advapi32.dll GetTokenInformation
$GetTokenInformationDelegate = Get-DelegateType @([IntPtr], $TOKEN_INFORMATION_CLASS, [IntPtr], [UInt32], [UInt32].MakeByRefType()) ([Bool])
$GetTokenInformation = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($GetTokenInformationAddr, $GetTokenInformationDelegate)    

$LookupPrivilegeNameWAddr = Get-ProcAddress advapi32.dll LookupPrivilegeNameW
$LookupPrivilegeNameWDelegate = Get-DelegateType @([IntPtr], [IntPtr], [IntPtr], [UInt32].MakeByRefType()) ([Bool])
$LookupPrivilegeNameW = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($LookupPrivilegeNameWAddr, $LookupPrivilegeNameWDelegate)

$LookupAccountSidWAddr = Get-ProcAddress advapi32.dll LookupAccountSidW
$LookupAccountSidWDelegate = Get-DelegateType @([IntPtr], [IntPtr], [IntPtr], [UInt32].MakeByRefType(), [IntPtr], [UInt32].MakeByRefType(), [UInt32].MakeByRefType()) ([Bool])
$LookupAccountSidW = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($LookupAccountSidWAddr, $LookupAccountSidWDelegate)

#Struct LUID
$Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit'
$TypeBuilder = $ModuleBuilder.DefineType('LUID', $Attributes, [System.ValueType], 8)
$TypeBuilder.DefineField('LowPart', [UInt32], 'Public') | Out-Null
$TypeBuilder.DefineField('HighPart', [Int32], 'Public') | Out-Null
$LUID = $TypeBuilder.CreateType()

#Struct LUID_AND_ATTRIBUTES
$Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit'
$TypeBuilder = $ModuleBuilder.DefineType('LUID_AND_ATTRIBUTES', $Attributes, [System.ValueType], 12)
$TypeBuilder.DefineField('Luid', $LUID, 'Public') | Out-Null
$TypeBuilder.DefineField('Attributes', [UInt32], 'Public') | Out-Null
$LUID_AND_ATTRIBUTES = $TypeBuilder.CreateType()

#Struct SID_AND_ATTRIBUTES
$Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit'
$TypeBuilder = $ModuleBuilder.DefineType('SID_AND_ATTRIBUTES', $Attributes, [System.ValueType], 16)
$TypeBuilder.DefineField('Sid', [IntPtr], 'Public') | Out-Null
$TypeBuilder.DefineField('Attributes', [UInt32], 'Public') | Out-Null
$SID_AND_ATTRIBUTES = $TypeBuilder.CreateType()

#Struct TOKEN_PRIVILEGES
$Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit'
$TypeBuilder = $ModuleBuilder.DefineType('TOKEN_PRIVILEGES', $Attributes, [System.ValueType], 16)
$TypeBuilder.DefineField('PrivilegeCount', [UInt32], 'Public') | Out-Null
$TypeBuilder.DefineField('Privileges', $LUID_AND_ATTRIBUTES, 'Public') | Out-Null
$TOKEN_PRIVILEGES = $TypeBuilder.CreateType()

#Struct TOKEN_GROUPS
$Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit'
$TypeBuilder = $ModuleBuilder.DefineType('TOKEN_GROUPS', $Attributes, [System.ValueType], 16)
$TypeBuilder.DefineField('GroupCount', [UInt32], 'Public') | Out-Null
$TypeBuilder.DefineField('Groups', $SID_AND_ATTRIBUTES, 'Public') | Out-Null
$TOKEN_GROUPS = $TypeBuilder.CreateType()

#Used to add 64bit memory addresses
Function Add-SignedIntAsUnsigned
{
  Param(
  [Parameter(Position = 0, Mandatory = $true)]
  [Int64]
  $Value1,

  [Parameter(Position = 1, Mandatory = $true)]
  [Int64]
  $Value2
  )

  [Byte[]]$Value1Bytes = [BitConverter]::GetBytes($Value1)
  [Byte[]]$Value2Bytes = [BitConverter]::GetBytes($Value2)
  [Byte[]]$FinalBytes = [BitConverter]::GetBytes([UInt64]0)

  if ($Value1Bytes.Count -eq $Value2Bytes.Count)
  {
    $CarryOver = 0
    for ($i = 0; $i -lt $Value1Bytes.Count; $i++)
    {
      #Add bytes
      [UInt16]$Sum = $Value1Bytes[$i] + $Value2Bytes[$i] + $CarryOver

      $FinalBytes[$i] = $Sum -band 0x00FF

      if (($Sum -band 0xFF00) -eq 0x100)
      {
        $CarryOver = 1
      }
      else
      {
        $CarryOver = 0
      }
    }
  }
  else
  {
    Throw "Cannot add bytearrays of different sizes"
  }

  return [BitConverter]::ToInt64($FinalBytes, 0)
}


#this is the account
$accountName = 'mydomain\myaccount'

#this cruft here is so that we get UPN for the WindowsIdentity conscturctor
add-type -AssemblyName System.DirectoryServices.AccountManagement
$pc = new-object System.DirectoryServices.AccountManagement.PrincipalContext Domain,$env:USERDOMAIN
$p = [System.DirectoryServices.AccountManagement.UserPrincipal]::FindByIdentity($pc,$accountName)


#and finally
$wi = new-object System.Security.Principal.WindowsIdentity $p.UserPrincipalName


[UInt32]$TokenPrivilegesSize = 10000
[IntPtr]$TokenPrivilegesPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($TokenPrivilegesSize)
[UInt32]$RealSize = 0
$Success = $GetTokenInformation.Invoke($wi.Token, $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)
        {
            $PrivilegeName + "(Enabled)" | Write-Host
        }
        else
        {
            $PrivilegeName + "(Available)" | Write-Host
        }

        [System.Runtime.InteropServices.Marshal]::FreeHGlobal($PrivilegeNamePtr)
    }
}
[System.Runtime.InteropServices.Marshal]::FreeHGlobal($TokenPrivilegesPtr)
[UInt32]$TokenGroupsSize = 10000
[IntPtr]$TokenGroupsPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($TokenGroupsSize)
[UInt32]$RealSize = 0
$Success = $GetTokenInformation.Invoke($wi.Token, $TOKEN_INFORMATION_CLASS::TokenGroups, $TokenGroupsPtr, $TokenGroupsSize, [Ref]$RealSize)
if (-not $Success)
{
    $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
    Write-Warning "GetTokenInformation failed to retrieve Token SessionId. ErrorCode: $ErrorCode"
}
else
{
    $TokenGroups = [System.Runtime.InteropServices.Marshal]::PtrToStructure($TokenGroupsPtr, [Type]$TOKEN_GROUPS)

    #Loop through each privilege
    [IntPtr]$GroupsBasePtr = [IntPtr](Add-SignedIntAsUnsigned $TokenGroupsPtr ([System.Runtime.InteropServices.Marshal]::OffsetOf([Type]$TOKEN_GROUPS, "Groups")))
    $SidAndAttributeSize = [System.Runtime.InteropServices.Marshal]::SizeOf([Type]$SID_AND_ATTRIBUTES)
    for ($i = 0; $i -lt $TokenGroups.GroupCount; $i++)
    {
        $SidAndAttributePtr = [IntPtr](Add-SignedIntAsUnsigned $GroupsBasePtr ($SidAndAttributeSize * $i))

        $SidAndAttribute = [System.Runtime.InteropServices.Marshal]::PtrToStructure($SidAndAttributePtr, [Type]$SID_AND_ATTRIBUTES)

        $Sid = $SidAndAttribute.Sid

        [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, $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"
        }

        $Domain + "/" + $Username | Write-Host

        [System.Runtime.InteropServices.Marshal]::FreeHGlobal($UsernameBuffer)
        $UsernameBuffer = [IntPtr]::Zero
        [System.Runtime.InteropServices.Marshal]::FreeHGlobal($DomainBuffer)
        $DomainBuffer = [IntPtr]::Zero




    }
}
[System.Runtime.InteropServices.Marshal]::FreeHGlobal($TokenGroupsPtr)

修改

根据评论我还尝试使用TokenGroupsAndPrivileges令牌信息类,但它似乎列出了没有登录权限的相同权限列表。

1 个答案:

答案 0 :(得分:0)

尽管MSDN说的是,令牌不会携带权利信息。为GetTokenInformation调用TokenGroups会为您提供帐户所在群组的传递列表。您可以通过在每个群组上调用LsaEnumerateAccountRights来获取权限。

这将有效,因为您拥有所有组。如果您查询的用户的TokenGroups不是直接在您的本地管理员组中,而是在属于您的本地管理员组的组中,您将从GetTokenInformation调用中收到本地管理员组SID。现在,如果您的本地管理员组拥有本地LSA数据库中的本地登录权限,则会LsaEnumerateAccountRights返回该权限。

此答案基于评论中链接的Harry Johnston's answer