update Doc + test + sample for token.py

This commit is contained in:
hakril
2018-12-20 22:48:16 +01:00
parent 8dc2d443d5
commit 986664d01f
5 changed files with 600 additions and 210 deletions
@@ -0,0 +1,10 @@
(cmd) python debug\debugger_on_setup.py
== With on_setup ==
Setup called: <WinProcess "whoami.exe" pid 29796 at 0x4ccb790>
<whoami output>
Process exit: <WinProcess "whoami.exe" pid 29796 (DEAD) at 0x4ccb790>
== Without on_setup ==
Exception: EXCEPTION_BREAKPOINT(0x80000003L)
<whoami output>
Process exit: <WinProcess "whoami.exe" pid 33328 (DEAD) at 0x4ccbdb0>
@@ -0,0 +1,21 @@
(cmd) python token\token_demo.py
Our process token is <Token TokenId=0x3f1f98fd Type=TokenPrimary(0x1L)>
Retrieving some infos
Username: <hakril>
User: <PSID "S-1-5-21-184905214-2723199098-2761450773-1001">
- lookup : ('WILLIE', 'hakril')
Primary group: <PSID "S-1-5-21-184905214-2723199098-2761450773-513">
- lookup : ('WILLIE', 'Aucun')
Token Groups is <TokenGroups count=15>
First group SID is <PSID "S-1-5-21-184905214-2723199098-2761450773-513">
Some sid and attributes:
- S-1-5-21-184905214-2723199098-2761450773-513: 7
- S-1-1-0: 7
- S-1-5-114: 16
Duplicate token is <Token TokenId=0x3f1fac85 Type=TokenImpersonation(0x2L) ImpersonationLevel=SecurityImpersonation(0x2L)>
Enabling <SeShutDownPrivilege>
Current thread token is <None>
Setting impersonation token !
Current thread token is <Token TokenId=0x3f1fac85 Type=TokenImpersonation(0x2L) ImpersonationLevel=SecurityImpersonation(0x2L)>
+61
View File
@@ -0,0 +1,61 @@
Token
"""""
.. module:: windows.winobject.token
This module expose the :class:`Token` object that can be primarily retrieved through:
* :data:`windows.winobject.process.WinProcess.token`
* :data:`windows.winobject.process.WinThread.token`
* :data:`windows.current_process.token <windows.winobject.process.CurrentProcess.token>`
* :data:`windows.current_thread.token <windows.winobject.process.CurrentThread.token>`
.. note::
See sample :ref:`token_sample`
Token
'''''
.. autoclass:: Token
:members:
:inherited-members:
TokenGroups
'''''''''''
.. autoclass:: TokenGroups
:show-inheritance:
:members:
:inherited-members:
TokenPrivileges
'''''''''''''''
.. autoclass:: TokenPrivileges
:show-inheritance:
:special-members: __getitem__, __setitem__
:members:
:inherited-members:
TokenSecurityAttributesInformation
''''''''''''''''''''''''''''''''''
.. autoclass:: TokenSecurityAttributesInformation
:show-inheritance:
:members:
:inherited-members:
TokenSecurityAttributeV1
''''''''''''''''''''''''
.. autoclass:: TokenSecurityAttributeV1
:show-inheritance:
:members:
:inherited-members:
+101 -21
View File
@@ -1,28 +1,108 @@
import pytest
import os
import windows
import windows.security
import windows.generated_def as gdef
@pytest.fixture
def curtok():
return windows.current_process.token
@pytest.fixture
def newtok():
return windows.current_process.token.duplicate()
def test_token_info(curtok):
assert isinstance(curtok.computername, basestring)
assert isinstance(curtok.username, basestring)
assert isinstance(curtok.integrity, (int, long))
assert isinstance(curtok.is_elevated, (bool))
def test_lower_integrity(newtok):
assert newtok.integrity != 123
# Change token integrity
newtok.integrity = 123
# newtok.integrity retrieve the integrity at each call so this in enough
assert newtok.integrity == 123
def test_token_user(curtok):
user_sid = curtok.user
assert user_sid
computername, username = windows.security.lookup_sid(user_sid)
assert computername == windows.system.computer_name
assert username == os.environ["USERNAME"]
def test_token_id(curtok):
ntok = curtok.duplicate()
assert ntok.id != curtok.id
mid = ntok.modified_id
aid = ntok.authentication_id
ntok.enable_privilege("SeShutDownPrivilege")
mid2 = ntok.modified_id
aid2 = ntok.authentication_id
ntok.integrity -= 1
assert ntok.modified_id != mid2 != mid
assert ntok.authentication_id == aid2 == aid
def test_token_info():
token = windows.current_process.token
assert isinstance(token.computername, basestring)
assert isinstance(token.username, basestring)
assert isinstance(token.integrity, (int, long))
assert isinstance(token.is_elevated, (bool))
def test_lower_integrity(proc32):
# Lowering the integrity in remote process
# Because we don't want to mess with the token of our testing process
proc32.execute_python("import windows")
# We stock the handle becase lowering the integrity
# will mess with token retrieval
proc32.execute_python("token = windows.current_process.token")
proc32.execute_python("token.integrity = 123")
# execute_python will raise this in our own process :)
proc32.execute_python("assert token.integrity == 123")
def test_enable_privilege(newtok):
PRIVILEGE_NAME = "SeShutdownPrivilege"
assert not newtok.privileges[PRIVILEGE_NAME] & gdef.SE_PRIVILEGE_ENABLED
newtok.enable_privilege(PRIVILEGE_NAME)
assert newtok.privileges[PRIVILEGE_NAME] & gdef.SE_PRIVILEGE_ENABLED
def test_token_elevation():
tok = windows.current_process.token
assert tok.TokenElevation
def test_adjust_privilege(newtok):
PRIVILEGE_NAME = "SeShutdownPrivilege"
PRIVILEGE2_NAME = "SeTimeZonePrivilege"
tok_dup = newtok.duplicate()
assert not tok_dup.privileges[PRIVILEGE_NAME] & gdef.SE_PRIVILEGE_ENABLED
assert not tok_dup.privileges[PRIVILEGE2_NAME] & gdef.SE_PRIVILEGE_ENABLED
# Enable privilege in another token.
privs = newtok.privileges
assert not privs[PRIVILEGE_NAME] & gdef.SE_PRIVILEGE_ENABLED
assert not privs[PRIVILEGE2_NAME] & gdef.SE_PRIVILEGE_ENABLED
privs[PRIVILEGE_NAME] = gdef.SE_PRIVILEGE_ENABLED
privs[PRIVILEGE2_NAME] = gdef.SE_PRIVILEGE_ENABLED
tok_dup.adjust_privileges(privs)
assert tok_dup.privileges[PRIVILEGE_NAME] & gdef.SE_PRIVILEGE_ENABLED
assert tok_dup.privileges[PRIVILEGE2_NAME] & gdef.SE_PRIVILEGE_ENABLED
assert not newtok.privileges[PRIVILEGE_NAME] & gdef.SE_PRIVILEGE_ENABLED
newtok.enable_privilege(PRIVILEGE_NAME)
assert newtok.privileges[PRIVILEGE_NAME] & gdef.SE_PRIVILEGE_ENABLED
def test_token_groups(curtok):
groups = curtok.groups
groups_size = groups.GroupCount
assert groups_size > 0
assert len(groups.sids) == groups_size
assert len(groups.sids_and_attributes) == groups_size
def test_token_duplicate(newtok):
x = newtok.duplicate()
assert x.type == newtok.type
primtok = newtok.duplicate(type=gdef.TokenPrimary)
assert primtok.type == gdef.TokenPrimary
with pytest.raises(WindowsError):
assert x.impersonation_level
with pytest.raises(ValueError):
# duplicate TokenPrimary -> TokenImpersonation require explicit impersonation_level
primtok.duplicate(type=gdef.TokenImpersonation)
for i in range(gdef.SecurityAnonymous, gdef.SecurityDelegation + 1):
x = newtok.duplicate(type=gdef.TokenImpersonation, impersonation_level=i)
assert x.type == gdef.TokenImpersonation
assert x.impersonation_level == i
# def test_token_groups
+407 -189
View File
@@ -1,38 +1,23 @@
import ctypes
import functools
from __builtin__ import type as bltn_type
import windows
from windows import utils
from windows import winproxy
import windows.generated_def as gdef
import windows.security
import functools
# Move to windows.security ?
def lookup_privilege(luid, system_name=None):
pass
# stolen from windows.utils :D (refactor !)
def lookup_privilege_name(privilege_value):
if isinstance(privilege_value, tuple):
luid = LUID(privilege_value[1], privilege_value[0])
privilege_value = luid
size = DWORD(0x100)
buff = ctypes.c_buffer(size.value)
winproxy.LookupPrivilegeNameA(None, privilege_value, buff, size)
return buff[:size.value]
KNOW_INTEGRITY_LEVEL = [
gdef.SECURITY_MANDATORY_UNTRUSTED_RID,
gdef.SECURITY_MANDATORY_LOW_RID,
gdef.SECURITY_MANDATORY_MEDIUM_RID,
gdef.SECURITY_MANDATORY_MEDIUM_PLUS_RID,
gdef.SECURITY_MANDATORY_HIGH_RID,
gdef.SECURITY_MANDATORY_SYSTEM_RID,
gdef.SECURITY_MANDATORY_PROTECTED_PROCESS_RID
]
know_integrity_level_mapper = gdef.FlagMapper(*KNOW_INTEGRITY_LEVEL)
KNOW_INTEGRITY_LEVEL = gdef.FlagMapper(
gdef.SECURITY_MANDATORY_UNTRUSTED_RID,
gdef.SECURITY_MANDATORY_LOW_RID,
gdef.SECURITY_MANDATORY_MEDIUM_RID,
gdef.SECURITY_MANDATORY_MEDIUM_PLUS_RID,
gdef.SECURITY_MANDATORY_HIGH_RID,
gdef.SECURITY_MANDATORY_SYSTEM_RID,
gdef.SECURITY_MANDATORY_PROTECTED_PROCESS_RID
)
# Voodoo to fix lookup-strangeness in class declaration
def meta_craft(x):
@@ -48,10 +33,18 @@ class TokenGroups(gdef.TOKEN_GROUPS):
@property
def sids_and_attributes(self):
"""The sids and attributes of each group
:type: [:class:`~windows.generated_def.winstructs.SID_AND_ATTRIBUTES`] - A list of :class:`~windows.generated_def.winstructs.SID_AND_ATTRIBUTES`
"""
return self._groups # Something else ?
@property
def sids(self):
"""The sids of each group
:type: [:class:`~windows.generated_def.winstructs.PSID`] - A list of :class:`~windows.generated_def.winstructs.PSID`
"""
return [g.Sid for g in self._groups]
def __repr__(self):
@@ -60,19 +53,87 @@ class TokenGroups(gdef.TOKEN_GROUPS):
TokenGroupsType = TokenGroups # Prevent confusion with token.TokenGroups
class TokenPrivileges(gdef.TOKEN_PRIVILEGES):
"""Improved ``TOKEN_PRIVILEGES`` usable like a mapping"""
@property
def _privileges(self):
return windows.utils.resized_array(self.Privileges, self.PrivilegeCount)
@property
def all(self):
"""The list of all privileges
:returns: [:class:`~windows.generated_def.winstructs.LUID_AND_ATTRIBUTES`] - A list of :class:`~windows.generated_def.winstructs.LUID_AND_ATTRIBUTES`
"""
return list(self._privileges)
def keys(self):
"""The name of all privileges in the TokenPrivileges
:returns: [:class:`str`] - A list of name
"""
return [self._lookup_name(p.Luid) for p in self._privileges]
__iter__ = keys
def items(self):
"""The (name, Attribute) of all privileges in the TokenPrivileges
:returns: [(:class:`str`, :class:`int`)] - A list of (name, Attribute) tuple
"""
return [(self._lookup_name(p.Luid), p.Attributes) for p in self._privileges]
def _get_priv_by_name(self, name):
luid = self._lookup_value(name)
x = [p for p in self._privileges if p.Luid == luid]
if not x:
return None
assert len(x) == 1
return x[0]
def __getitem__(self, name):
"""Retrieve the attribute value for privilege ``name``
:raises: KeyError if privilege ``name`` not in the TokenPrivileges
:returns: :class:`int`
"""
priv = self._get_priv_by_name(name)
if not priv:
raise KeyError(name)
return priv.Attributes
def __setitem__(self, name, value):
"""Set the attribute value for privilege ``name``
:raises: KeyError if privilege ``name`` not in the TokenPrivileges
"""
priv = self._get_priv_by_name(name)
if not priv:
raise KeyError(name)
priv.Attributes = value
# __delitem__ that set SE_PRIVILEGE_REMOVED ?
def _lookup_name(self, luid):
size = gdef.DWORD(0x100)
buff = ctypes.c_buffer(size.value)
winproxy.LookupPrivilegeNameA(None, luid, buff, size)
return buff[:size.value]
def _lookup_value(self, name):
luid = gdef.LUID()
winproxy.LookupPrivilegeValueA(None, name, ctypes.byref(luid))
return luid
TokenPrivilegesType = TokenPrivileges
class TokenSecurityAttributesInformation(gdef.TOKEN_SECURITY_ATTRIBUTES_INFORMATION):
@property
def attributes(self):
"""Return all the attributes as :class:`TokenSecurityAttributeV1`
:type: [:class:`TokenSecurityAttributeV1`] - A list of token security attributes
"""
tptr = ctypes.cast(self.Attribute.pAttributeV1, ctypes.POINTER(TokenSecurityAttributeV1))
# Well look like this cast does NOT keep a ref to self.
# Setup the base object ref ourself
@@ -93,10 +154,12 @@ class TokenSecurityAttributeV1(gdef.TOKEN_SECURITY_ATTRIBUTE_V1):
@property
def name(self):
"""The name of the security attribute"""
return self.Name.str
@property
def values(self):
"""The values of the security attribute"""
array_name = self.VALUE_ARRAY_PTR_BY_TYPE[self.ValueType]
return getattr(self.Values, array_name)[:self.ValueCount]
@@ -104,9 +167,16 @@ class TokenSecurityAttributeV1(gdef.TOKEN_SECURITY_ATTRIBUTE_V1):
return """<{0} name="{1}">""".format(type(self).__name__, self.name)
# https://docs.microsoft.com/en-us/windows/desktop/SecAuthZ/access-tokens
class Token(utils.AutoHandle):
"""The token of a process"""
"""Represent a Windows Token.
The attributes only documented by a type are from the :class:`~windows.generated_def.winstructs.TOKEN_INFORMATION_CLASS`, such return values may be improved version of the structure.
.. note::
see `[MSDN] TOKEN_INFORMATION_CLASS <https://docs.microsoft.com/en-us/windows/desktop/api/winnt/ne-winnt-_token_information_class>`_
"""
def __init__(self, handle):
self._handle = handle
@@ -119,7 +189,7 @@ class Token(utils.AutoHandle):
raise
return cbsize.value
def _get_token_infomations(self, infos_class, rtype):
def get_token_infomations(self, infos_class, rtype):
required_size = self._get_required_token_information_size(infos_class)
requested_size = max(required_size, ctypes.sizeof(rtype))
buffer = utils.BUFFER(rtype, 1)(size=requested_size)
@@ -128,136 +198,285 @@ class Token(utils.AutoHandle):
return buffer[0]
craft = meta_craft(_get_token_infomations)
def set_informations(self, info_type, infos):
return winproxy.SetTokenInformation(self.handle, info_type, ctypes.byref(infos), ctypes.sizeof(infos))
craft = meta_craft(get_token_infomations)
# https://docs.microsoft.com/en-us/windows/desktop/api/winnt/ne-winnt-_token_information_class
TokenUser = craft(gdef.TokenUser, gdef.TOKEN_USER)
TokenGroups = craft(gdef.TokenGroups , TokenGroupsType)
TokenPrivileges = craft(gdef.TokenPrivileges , TokenPrivilegesType)
TokenOwner = craft(gdef.TokenOwner, gdef.TOKEN_OWNER )
TokenPrimaryGroup = craft(gdef.TokenPrimaryGroup, gdef.TOKEN_PRIMARY_GROUP)
TokenDefaultDacl = craft(gdef.TokenDefaultDacl, gdef.TOKEN_DEFAULT_DACL )
TokenSource = craft(gdef.TokenSource, gdef.TOKEN_SOURCE)
TokenType = craft(gdef.TokenType, gdef.TOKEN_TYPE)
TokenImpersonationLevel = craft(gdef.TokenImpersonationLevel, gdef.SECURITY_IMPERSONATION_LEVEL)
TokenStatistics = craft(gdef.TokenStatistics, gdef.TOKEN_STATISTICS)
TokenRestrictedSids = craft(gdef.TokenRestrictedSids, TokenGroupsType)
TokenSessionId = craft(gdef.TokenSessionId, gdef.DWORD)
TokenGroupsAndPrivileges = craft(gdef.TokenGroupsAndPrivileges, gdef.TOKEN_GROUPS_AND_PRIVILEGES)
TokenUser = craft(gdef.TokenUser, gdef.TOKEN_USER) #: :class:`~windows.generated_def.winstructs.TOKEN_USER`
TokenGroups = craft(gdef.TokenGroups , TokenGroupsType) #: :class:`TokenGroups`
TokenPrivileges = craft(gdef.TokenPrivileges , TokenPrivilegesType) #: :class:`TokenPrivileges`
TokenOwner = craft(gdef.TokenOwner, gdef.TOKEN_OWNER) #: :class:`~windows.generated_def.winstructs.TOKEN_OWNER`
TokenPrimaryGroup = craft(gdef.TokenPrimaryGroup, gdef.TOKEN_PRIMARY_GROUP) #: :class:`~windows.generated_def.winstructs.TOKEN_PRIMARY_GROUP`
TokenDefaultDacl = craft(gdef.TokenDefaultDacl, gdef.TOKEN_DEFAULT_DACL) #: :class:`~windows.generated_def.winstructs.TOKEN_DEFAULT_DACL`
TokenSource = craft(gdef.TokenSource, gdef.TOKEN_SOURCE) #: :class:`~windows.generated_def.winstructs.TOKEN_SOURCE`
TokenType = craft(gdef.TokenType, gdef.TOKEN_TYPE) #: :class:`~windows.generated_def.winstructs.TOKEN_TYPE`
TokenImpersonationLevel = craft(gdef.TokenImpersonationLevel, gdef.SECURITY_IMPERSONATION_LEVEL) #: :class:`~windows.generated_def.winstructs.SECURITY_IMPERSONATION_LEVEL`
TokenStatistics = craft(gdef.TokenStatistics, gdef.TOKEN_STATISTICS) #: :class:`~windows.generated_def.winstructs.TOKEN_STATISTICS`
TokenRestrictedSids = craft(gdef.TokenRestrictedSids, TokenGroupsType) #: :class:`~windows.generated_def.winstructs.TokenGroups`
TokenSessionId = craft(gdef.TokenSessionId, gdef.DWORD) #: :class:`~windows.generated_def.winstructs.DWORD`
TokenGroupsAndPrivileges = craft(gdef.TokenGroupsAndPrivileges, gdef.TOKEN_GROUPS_AND_PRIVILEGES) #: :class:`~windows.generated_def.winstructs.TOKEN_GROUPS_AND_PRIVILEGES`
# TokenSessionReference = craft(gdef.TokenSessionReference, ???) # Reserved.
TokenSandBoxInert = craft(gdef.TokenSandBoxInert, gdef.DWORD)
TokenSandBoxInert = craft(gdef.TokenSandBoxInert, gdef.DWORD) #: :class:`~windows.generated_def.winstructs.DWORD`
# TokenAuditPolicy = craft(gdef.TokenAuditPolicy, ???) # Reserved.
TokenOrigin = craft(gdef.TokenOrigin, gdef.TOKEN_ORIGIN)
TokenElevationType = craft(gdef.TokenElevationType, gdef.TOKEN_ELEVATION_TYPE)
TokenLinkedToken = craft(gdef.TokenLinkedToken, gdef.TOKEN_LINKED_TOKEN)
TokenElevation = craft(gdef.TokenElevation, gdef.TOKEN_ELEVATION)
TokenHasRestrictions = craft(gdef.TokenHasRestrictions, gdef.DWORD)
TokenAccessInformation = craft(gdef.TokenAccessInformation, gdef.TOKEN_ACCESS_INFORMATION )
TokenVirtualizationAllowed = craft(gdef.TokenVirtualizationAllowed, gdef.DWORD)
TokenVirtualizationEnabled = craft(gdef.TokenVirtualizationEnabled, gdef.DWORD)
TokenIntegrityLevel = craft(gdef.TokenIntegrityLevel, gdef.TOKEN_MANDATORY_LABEL )
TokenUIAccess = craft(gdef.TokenUIAccess, gdef.DWORD)
TokenMandatoryPolicy = craft(gdef.TokenMandatoryPolicy, gdef.TOKEN_MANDATORY_POLICY)
TokenLogonSid = craft(gdef.TokenLogonSid, TokenGroupsType)
TokenIsAppContainer = craft(gdef.TokenIsAppContainer, gdef.DWORD)
TokenCapabilities = craft(gdef.TokenCapabilities, TokenGroupsType)
TokenAppContainerSid = craft(gdef.TokenAppContainerSid, gdef.TOKEN_APPCONTAINER_INFORMATION)
TokenAppContainerNumber = craft(gdef.TokenAppContainerNumber, gdef.DWORD)
TokenUserClaimAttributes = craft(gdef.TokenUserClaimAttributes, gdef.CLAIM_SECURITY_ATTRIBUTES_INFORMATION)
TokenDeviceClaimAttributes = craft(gdef.TokenDeviceClaimAttributes, gdef.CLAIM_SECURITY_ATTRIBUTES_INFORMATION)
TokenOrigin = craft(gdef.TokenOrigin, gdef.TOKEN_ORIGIN) #: :class:`~windows.generated_def.winstructs.TOKEN_ORIGIN`
TokenElevationType = craft(gdef.TokenElevationType, gdef.TOKEN_ELEVATION_TYPE) #: :class:`~windows.generated_def.winstructs.TOKEN_ELEVATION_TYPE`
TokenLinkedToken = craft(gdef.TokenLinkedToken, gdef.TOKEN_LINKED_TOKEN) #: :class:`~windows.generated_def.winstructs.TOKEN_LINKED_TOKEN`
TokenElevation = craft(gdef.TokenElevation, gdef.TOKEN_ELEVATION) #: :class:`~windows.generated_def.winstructs.TOKEN_ELEVATION`
TokenHasRestrictions = craft(gdef.TokenHasRestrictions, gdef.DWORD) #: :class:`~windows.generated_def.winstructs.DWORD`
TokenAccessInformation = craft(gdef.TokenAccessInformation, gdef.TOKEN_ACCESS_INFORMATION) #: :class:`~windows.generated_def.winstructs.TOKEN_ACCESS_INFORMATION`
TokenVirtualizationAllowed = craft(gdef.TokenVirtualizationAllowed, gdef.DWORD) #: :class:`~windows.generated_def.winstructs.DWORD`
TokenVirtualizationEnabled = craft(gdef.TokenVirtualizationEnabled, gdef.DWORD) #: :class:`~windows.generated_def.winstructs.DWORD`
TokenIntegrityLevel = craft(gdef.TokenIntegrityLevel, gdef.TOKEN_MANDATORY_LABEL) #: :class:`~windows.generated_def.winstructs.TOKEN_MANDATORY_LABEL`
TokenUIAccess = craft(gdef.TokenUIAccess, gdef.DWORD) #: :class:`~windows.generated_def.winstructs.DWORD`
TokenMandatoryPolicy = craft(gdef.TokenMandatoryPolicy, gdef.TOKEN_MANDATORY_POLICY) #: :class:`~windows.generated_def.winstructs.TOKEN_MANDATORY_POLICY`
TokenLogonSid = craft(gdef.TokenLogonSid, TokenGroupsType) #: :class:`TokenGroups`
TokenIsAppContainer = craft(gdef.TokenIsAppContainer, gdef.DWORD) #: :class:`~windows.generated_def.winstructs.DWORD`
TokenCapabilities = craft(gdef.TokenCapabilities, TokenGroupsType) #: :class:`TokenGroups`
TokenAppContainerSid = craft(gdef.TokenAppContainerSid, gdef.TOKEN_APPCONTAINER_INFORMATION) #: :class:`~windows.generated_def.winstructs.TOKEN_APPCONTAINER_INFORMATION`
TokenAppContainerNumber = craft(gdef.TokenAppContainerNumber, gdef.DWORD) #: :class:`~windows.generated_def.winstructs.DWORD`
TokenUserClaimAttributes = craft(gdef.TokenUserClaimAttributes, gdef.CLAIM_SECURITY_ATTRIBUTES_INFORMATION) #: :class:`~windows.generated_def.winstructs.CLAIM_SECURITY_ATTRIBUTES_INFORMATION`
TokenDeviceClaimAttributes = craft(gdef.TokenDeviceClaimAttributes, gdef.CLAIM_SECURITY_ATTRIBUTES_INFORMATION) #: :class:`~windows.generated_def.winstructs.CLAIM_SECURITY_ATTRIBUTES_INFORMATION`
# TokenRestrictedUserClaimAttributes = craft(gdef.TokenRestrictedUserClaimAttributes, ???) # Reserved.
# TokenRestrictedDeviceClaimAttributes = craft(gdef.TokenRestrictedDeviceClaimAttributes, ???) # Reserved.
TokenDeviceGroups = craft(gdef.TokenDeviceGroups, TokenGroups)
TokenRestrictedDeviceGroups = craft(gdef.TokenRestrictedDeviceGroups, gdef.TOKEN_GROUPS)
TokenDeviceGroups = craft(gdef.TokenDeviceGroups, TokenGroupsType) #: :class:`TokenGroups`
TokenRestrictedDeviceGroups = craft(gdef.TokenRestrictedDeviceGroups, gdef.TOKEN_GROUPS) #: :class:`~windows.generated_def.winstructs.TOKEN_GROUPS`
# Reserved.
# Structure found in ntseapi.h (thx internet)
TokenSecurityAttributes = craft(gdef.TokenSecurityAttributes, TokenSecurityAttributesInformation)
TokenSecurityAttributes = craft(gdef.TokenSecurityAttributes, TokenSecurityAttributesInformation) #: :class:`TokenSecurityAttributesInformation`
# Help would be appreciated for the structures of the following query type
# TokenIsRestricted = craft(gdef.TokenIsRestricted, ???) # Reserved.
# TokenProcessTrustLevel = craft(gdef.TokenProcessTrustLevel, ???) # Reserved.
# TokenPrivateNameSpace = craft(gdef.TokenPrivateNameSpace, ???) # Reserved.
TokenProcessTrustLevel = craft(gdef.TokenProcessTrustLevel, gdef.PSID) #: :class:`~windows.generated_def.winstructs.PSID`
# TokenPrivateNameSpace = craft(gdef.TokenPrivateNameSpace, gdef.ULONG) # Reserved.
# TokenSingletonAttributes = craft(gdef.TokenSingletonAttributes, ???) # Reserved.
# TokenBnoIsolation = craft(gdef.TokenBnoIsolation, ???) # Reserved.
# TokenChildProcessFlags = craft(gdef.TokenChildProcessFlags, ???) # Reserved.
# TokenIsLessPrivilegedAppContainer = craft(gdef.TokenIsLessPrivilegedAppContainer, ???) # Reserved.
# property arround raw 'GetTokenInformation'
# High level properties
@property
def user(self):
"""The user sid of the token
:type: :class:`~windows.generated_def.winstructs.PSID`
"""
return self.TokenUser.User.Sid
groups = TokenGroups # The property not the ctypes Struct
@property
def username(self):
"""The username of the token
:type: :class:`str`
"""
return self._user_and_computer_name()[1]
@property
def computername(self):
"""The computername of the token
:type: :class:`str`
"""
return self._user_and_computer_name()[0]
def _user_and_computer_name(self):
return windows.security.lookup_sid(self.user)
groups = TokenGroups #: Alias for TokenGroups (type may change in the future for improved struct)
@property
def owner(self):
"""The owner sid of the token
:type: :class:`~windows.generated_def.winstructs.PSID`
"""
return self.TokenOwner.Owner
@property
def primary_group(self):
"""The sid of the primary group of the token
:type: :class:`~windows.generated_def.winstructs.PSID`
"""
return self.TokenPrimaryGroup.PrimaryGroup
@property
def default_dacl(self):
return self._get_token_infomations(gdef.TokenDefaultDacl, windows.security.PAcl)[0]
"""The defaul DACL of the token
:type: :class:`windows.security.Acl`
"""
return self.get_token_infomations(gdef.TokenDefaultDacl, windows.security.PAcl)[0]
# def source(self): (tok.TokenSource) ??
@property
def type(self):
"""The type (Primary / Impersonation) of the token
"""
return self.TokenType.value
@property
def impersonation_level(self):
return self.TokenImpersonationLevel.value
"""The impersonation level of a ``TokenImpersonation`` token.
statistics = TokenStatistics
restricted_sids = TokenRestrictedSids
session_id = TokenSessionId
:raises: :class:`WindowsError` if token is not a ``TokenImpersonation``
:type: :class:`int` -- Enum value from :class:`~windows.generated_def.winstructs.SECURITY_IMPERSONATION_LEVEL`
"""
try:
return self.TokenImpersonationLevel.value
except WindowsError as e:
if (e.winerror == gdef.ERROR_INVALID_PARAMETER and
self.type != gdef.TokenImpersonation):
# raise ValueError ?
e.strerror += " This Token is not an Impersonation token"
raise
statistics = TokenStatistics #: Alias for TokenStatistics (type may change in the future for improved struct)
@property
def id(self):
"""The TokenId Specifies an unique identifier that identifies this instance of the token object.
:type: :class:`int`
"""
return int(self.TokenStatistics.TokenId)
@property
def authentication_id(self):
"""The AuthenticationId Specifies an unique identifier assigned to the session this token represents.
There can be many tokens representing a single logon session.
:type: :class:`int`
"""
return int(self.TokenStatistics.AuthenticationId)
@property
def modified_id(self):
"""The ModifiedId Specifies an unique identifier that changes each time the token is modified.
:type: :class:`int`
"""
return int(self.TokenStatistics.ModifiedId)
restricted_sids = TokenRestrictedSids #: Alias for TokenRestrictedSids (type may change in the future for improved struct)
session_id = TokenSessionId #: Alias for TokenSessionId (type may change in the future for improved struct)
@property
def groups_and_privileges(self):
"""Alias for TokenGroupsAndPrivileges (type may change in the future for improved struct)"""
# Return enhanced 'TOKEN_GROUPS_AND_PRIVILEGES' ?
raise NotImplementedError("Token.groups_and_privileges")
return self.TokenGroupsAndPrivileges
sandbox_inert = TokenSandBoxInert
@property
def privileges(self):
"""Alias for ``TokenPrivileges``
# audit_policy
:type: :class:`TokenPrivileges`
"""
return self.TokenPrivileges
sandbox_inert = TokenSandBoxInert #: Alias for TokenSandBoxInert (type may change in the future for improved struct)
# def audit_policy(self):
# raise NotImplementedError("Need to find the type of TokenAuditPolicy")
@property
def origin(self):
# Make a enhanced LUID ?
"""The originating logon session of the token.
:type: :class:`int`
"""
origin_logon_session = self.TokenOrigin.OriginatingLogonSession
return gdef.ULONG64.from_buffer(origin_logon_session).value
return int(origin_logon_session) # improved LUID implem __int__ :)
@property
def elevation_type(self):
"""The elevation type of the token.
:type: :class:`int` -- Enum value from :class:`~windows.generated_def.winstructs.TOKEN_ELEVATION_TYPE`
"""
return self.TokenElevationType.value
@property
def linked_token(self):
"""The token linked to our token if present (may raise else)
:type: :class:`Token`
"""
# TODO: return None if not present ?
return Token(self.TokenLinkedToken.LinkedToken)
@property
def elevation(self):
def elevated(self):
"""``True`` if token is an elevated token"""
return bool(self.TokenElevation.TokenIsElevated)
is_elevated = elevation # Keep this old name ?
has_restriction = TokenHasRestrictions
is_elevated = elevated #: Alias for ``elevated`` deprecated and may disapear
has_restriction = TokenHasRestrictions #: Alias for TokenHasRestrictions (type may change in the future for improved struct)
@property
def access_information(self):
"""Alias for TokenAccessInformation (type may change in the future for improved struct)"""
# Return enhanced subclass ?
raise NotImplementedError("Token.access_information")
# return self.TokenAccessInformation
return self.TokenAccessInformation
virtualization_allowed = TokenVirtualizationAllowed
virtualization_enabled = TokenVirtualizationEnabled
@property
def trust_level(self):
"""The trust level of the process if present else ``None``.
:type: :class:`~windows.generated_def.winstructs.PSID`
"""
tl = self.TokenProcessTrustLevel
if not tl: # NULL:
return None
return tl
virtualization_allowed = TokenVirtualizationAllowed #: Alias for TokenVirtualizationAllowed (type may change in the future for improved struct)
virtualization_enabled = TokenVirtualizationEnabled #: Alias for TokenVirtualizationEnabled (type may change in the future for improved struct)
@property
def integrity_level(self):
# Return SID_AND_ATTRIBUTES ? Only SID ?
"""The integrity level and attributes of the token
:type: :class:`windows.generated_def.winstructs.SID_AND_ATTRIBUTES`
"""
return self.TokenIntegrityLevel.Label # SID_AND_ATTRIBUTES
ui_access = TokenUIAccess
def get_integrity(self):
"""Return the integrity level of the token
:type: :class:`int`
"""
sid = self.integrity_level.Sid
count = winproxy.GetSidSubAuthorityCount(sid)
integrity = winproxy.GetSidSubAuthority(sid, count[0] - 1)[0]
return KNOW_INTEGRITY_LEVEL[integrity]
def set_integrity(self, integrity):
"""Set the integrity level of a token
:param type: :class:`int`
"""
mandatory_label = gdef.TOKEN_MANDATORY_LABEL()
mandatory_label.Label.Attributes = 0x60
mandatory_label.Label.Sid = gdef.PSID.from_string("S-1-16-{0}".format(integrity))
return self.set_informations(gdef.TokenIntegrityLevel, mandatory_label)
_INTEGRITY_PROPERTY_DOC = """The integrity of the token as an int (extracted from integrity PSID)
:getter: :func:`get_integrity`
:setter: :func:`set_integrity`
"""
integrity = property(get_integrity, set_integrity, doc=_INTEGRITY_PROPERTY_DOC)
ui_access = TokenUIAccess #: Alias for TokenUIAccess (type may change in the future for improved struct)
VALID_TOKEN_POLICIES = gdef.FlagMapper(
gdef.TOKEN_MANDATORY_POLICY_OFF,
@@ -268,129 +487,128 @@ class Token(utils.AutoHandle):
@property
def mandatory_policy(self):
"""mandatory integrity access policy for the associated token
:type: :class:`int` -- see `[MSDN] mandatory policy <https://docs.microsoft.com/en-us/windows/desktop/api/winnt/ns-winnt-_token_mandatory_policy>`_
"""
return self.VALID_TOKEN_POLICIES[self.TokenMandatoryPolicy.Policy]
@property
def logon_sid(self):
"""The logon sid of the token. (Case of multiple logon sid not handled and will raise AssertionError)
:type: :class:`windows.generated_def.winstructs.SID_AND_ATTRIBUTES`
"""
rgroups = self.TokenLogonSid
assert rgroups.GroupCount == 1, "More than 1 TokenLogonSid"
return rgroups.Groups[0]
is_appcontainer = TokenIsAppContainer
capabilities = TokenCapabilities
is_appcontainer = TokenIsAppContainer #: Alias for TokenIsAppContainer (type may change in the future for improved struct)
capabilities = TokenCapabilities #: Alias for TokenCapabilities (type may change in the future for improved struct)
@property
def appcontainer_sid(self):
return self.TokenAppContainerSid.TokenAppContainer
"""The sid of the TokenAppContainerSid if present else ``None``
appcontainer_number = TokenAppContainerNumber
:type: :class:`~windows.generated_def.winstructs.PSID`
"""
sid = self.TokenAppContainerSid.TokenAppContainer
if not sid: # NULL
return None
return sid
# def security_attribute:
# see PTOKEN_SECURITY_ATTRIBUTES_INFORMATION
# https://github.com/wj32/Backup/blob/59aa77379f9f7ca57f27265e796dd2fe4dae9fab/include/phnt/ntseapi.h
# blablabla :)
appcontainer_number = TokenAppContainerNumber #: Alias for TokenAppContainerNumber (type may change in the future for improved struct)
@property
def security_attributes(self):
"""The security attributes of the token
:type: [:class:`TokenSecurityAttributeV1`] - A list of token security attributes
"""
return self.TokenSecurityAttributes.attributes
def duplicate(self, access_rigth=0, attributes=None, impersonation_level=gdef.SecurityImpersonation, toktype=gdef.TokenPrimary):
## Token Methods
def duplicate(self, access_rigth=gdef.MAXIMUM_ALLOWED, attributes=None, type=None, impersonation_level=None):
"""Duplicate the token into a new :class:`Token`.
:param type: The type of token: ``TokenPrimary(0x1L)`` or ``TokenImpersonation(0x2L)``
:param impersonation_level: The :class:`~windows.generated_def.winstructs.SECURITY_IMPERSONATION_LEVEL` for a ``TokenImpersonation(0x2L)``:
- If ``type`` is ``TokenPrimary(0x1L)`` this parameter is ignored if ``None`` or used as-is.
- If ``type`` is ``TokenImpersonation(0x2L)`` and this parameter is None, ``self.impersonation_level`` is used.
- If ``type`` is ``TokenImpersonation(0x2L)`` and our Token is a ``TokenPrimary(0x1L)`` this parameter MUST be provided
:returns: :class:`Token` - The duplicate token
Example:
>>> tok
<Token TokenId=0x39d6dde5 Type=TokenPrimary(0x1L)>
>>> tok.duplicate()
<Token TokenId=0x39d7b206 Type=TokenPrimary(0x1L)>
>>> tok.duplicate(type=gdef.TokenImpersonation)
...
ValueError: Duplicating a PrimaryToken as a TokenImpersonation require explicit <impersonation_level> parameter
>>> tok.duplicate(type=gdef.TokenImpersonation, impersonation_level=gdef.SecurityImpersonation)
<Token TokenId=0x39dadbf8 Type=TokenImpersonation(0x2L) ImpersonationLevel=SecurityImpersonation(0x2L)>
"""
newtoken = gdef.HANDLE()
winproxy.DuplicateTokenEx(self.handle, access_rigth, attributes, impersonation_level, toktype, newtoken)
return type(self)(newtoken.value)
if type is None:
type = self.type
if impersonation_level is None:
if self.type == gdef.TokenImpersonation:
impersonation_level = self.impersonation_level
elif type != gdef.TokenImpersonation:
impersonation_level = 0 #: ignored
else:
raise ValueError("Duplicating a PrimaryToken as a TokenImpersonation require explicit <impersonation_level> parameter")
winproxy.DuplicateTokenEx(self.handle, access_rigth, attributes, impersonation_level, type, newtoken)
return bltn_type(self)(newtoken.value)
def adjust_privileges(self, privileges):
"""Adjust the token privileges according to ``privileges``.
This API is the `complex one` to adjust multiple privileges at once.
To simply enable one privilege see :func:`enable_privilege`.
### OLD CODE
:param privileges: :class:`~windows.generated_def.winstructs.TOKEN_PRIVILEGES` (or subclass as :class:`TokenPrivileges`). To easily update your token privileges use the result of :data:`privileges`.
def get_integrity(self):
"""Return the integrity level of a token
Example:
:type: :class:`int`
"""
buffer_size = self.get_required_information_size(gdef.TokenIntegrityLevel)
buffer = ctypes.c_buffer(buffer_size)
self.get_informations(gdef.TokenIntegrityLevel, buffer)
sid = ctypes.cast(buffer, ctypes.POINTER(gdef.TOKEN_MANDATORY_LABEL))[0].Label.Sid
count = winproxy.GetSidSubAuthorityCount(sid)
integrity = winproxy.GetSidSubAuthority(sid, count[0] - 1)[0]
return know_integrity_level_mapper[integrity]
>>> tok = windows.current_process.token
>>> privs = tok.privileges
>>> privs["SeShutdownPrivilege"] = gdef.SE_PRIVILEGE_ENABLED
>>> privs["SeUndockPrivilege"] = gdef.SE_PRIVILEGE_ENABLED
>>> tok.adjust_privileges(privs)
def set_integrity(self, integrity):
"""Set the integrity level of a token
"""
buffsize = None
if isinstance(privileges, TokenPrivilegesType):
# The TokenPrivilegesType should come from a PTR via Improved buffer
try:
buffsize = privileges._b_base_.real_size
except AttributeError as e:
pass
if buffsize is None:
buffsize = ctypes.sizeof(privileges)
winproxy.AdjustTokenPrivileges(self.handle, False, privileges, buffsize, None, None)
if winproxy.GetLastError() == gdef.ERROR_NOT_ALL_ASSIGNED:
raise ValueError("Failed to adjust all privileges")
:param type: :class:`int`
"""
mandatory_label = gdef.TOKEN_MANDATORY_LABEL()
mandatory_label.Label.Attributes = 0x60
mandatory_label.Label.Sid = gdef.PSID.from_string("S-1-16-{0}".format(integrity))
self.set_informations(gdef.TokenIntegrityLevel, mandatory_label)
integrity = property(get_integrity, set_integrity)
@property
def is_elevated(self):
"""``True`` if process is Admin"""
elevation = gdef.TOKEN_ELEVATION()
self.get_informations(gdef.TokenElevation, elevation)
return bool(elevation.TokenIsElevated)
@property
def token_user(self):
buffer_size = self.get_required_information_size(gdef.TokenUser)
buffer = ctypes.c_buffer(buffer_size)
self.get_informations(gdef.TokenUser, buffer)
return ctypes.cast(buffer, ctypes.POINTER(gdef.TOKEN_USER))[0]
@property
def computername(self):
"""The computername of the token"""
return self._user_and_computer_name()[1]
@property
def username(self):
"""The username of the token"""
return self._user_and_computer_name()[0]
def _user_and_computer_name(self):
tok_usr = self.token_user
sid = tok_usr.User.Sid
usernamesize = gdef.DWORD(0x1000)
computernamesize = gdef.DWORD(0x1000)
username = ctypes.c_buffer(usernamesize.value)
computername = ctypes.c_buffer(computernamesize.value)
peUse = gdef.SID_NAME_USE()
winproxy.LookupAccountSidA(None, sid, username, usernamesize, computername, computernamesize, peUse)
return username[:usernamesize.value], computername[:computernamesize.value]
def get_informations(self, info_type, data):
cbsize = gdef.DWORD()
winproxy.GetTokenInformation(self.handle, info_type, ctypes.byref(data), ctypes.sizeof(data), ctypes.byref(cbsize))
return cbsize.value
def get_required_information_size(self, info_type):
cbsize = gdef.DWORD()
def enable_privilege(self, name):
"""Enable privilege ``name`` in the token"""
privs = self.privileges
try:
winproxy.GetTokenInformation(self.handle, info_type, None, 0, ctypes.byref(cbsize))
except WindowsError as e:
if not e.winerror == gdef.ERROR_INSUFFICIENT_BUFFER:
raise
return cbsize.value
#TODO: TEST + DOC
def set_informations(self, info_type, infos):
return winproxy.SetTokenInformation(self.handle, info_type, ctypes.byref(infos), ctypes.sizeof(infos))
# TEST
def dacl(self):
"""TEST CODE"""
buffer_size = self.get_required_information_size(TokenDefaultDacl)
buffer = ctypes.c_buffer(buffer_size)
self.get_informations(gdef.TokenDefaultDacl, buffer)
# TODO: use windows.security.Acl
return ctypes.cast(buffer, POINTER(TOKEN_DEFAULT_DACL))[0]
privs[name] = gdef.SE_PRIVILEGE_ENABLED
except KeyError as e:
raise ValueError("{0} as no privilege <{1}>".format(self, name))
return self.adjust_privileges(privs)
def __repr__(self):
tid_int = gdef.ULONG64.from_buffer(self.TokenStatistics.TokenId).value
return "<{0} TokenId={1:#x}>".format(type(self).__name__, tid_int)
flag_repr = gdef.Flag.__repr__
tid_int = int(self.TokenStatistics.TokenId)
toktype = self.type
if toktype == gdef.TokenPrimary:
return "<{0} TokenId={1:#x} Type={2}>".format(type(self).__name__, tid_int, flag_repr(toktype))
return "<{0} TokenId={1:#x} Type={2} ImpersonationLevel={3}>".format(type(self).__name__, tid_int, flag_repr(toktype), flag_repr(self.impersonation_level))