To understand when privileges may be unintentionally
removed, you must understand the format of the
NewState parameter and the operation of
AdjustTokenPrivileges in response to
DisableAllPrivileges and
NewState.
Because the remainder of this article discusses
AdjustTokenPrivileges and the format of its parameters in detail, the declarations and
definitions are provided here for your reference:
BOOL AdjustTokenPrivileges(
HANDLE TokenHandle,
BOOL DisableAllPrivileges,
PTOKEN_PRIVILEGES NewState,
DWORD BufferLength,
PTOKEN_PRIVILEGES PreviousState,
PDWORD ReturnLength
);
typedef struct _TOKEN_PRIVILEGES {
DWORD PrivilegeCount;
LUID_AND_ATTRIBUTES Privileges[ANYSIZE_ARRAY];
} TOKEN_PRIVILEGES, *PTOKEN_PRIVILEGES;
typedef struct _LUID_AND_ATTRIBUTES {
LUID Luid;
DWORD Attributes;
} LUID_AND_ATTRIBUTES, *PLUID_AND_ATTRIBUTES;
The
NewState parameter points to a caller-supplied buffer that holds a
TOKEN_PRIVILEGES structure. This structure contains a count and an array of
LUID_AND_ATTRIBUTES structures, each of which specifies a privilege and its
attributes. The Attributes field is a bit mask of flags that can be combined
(these flags are defined in the Winnt.h file):
SE_PRIVILEGE_ENABLED
SE_PRIVILEGE_ENABLED_BY_DEFAULT
SE_PRIVILEGE_USED_FOR_ACCESS
If the
DisableAllPrivileges parameter is FALSE,
AdjustTokenPrivileges uses the array of LUID_AND_ATTRIBUTES pointed to by
NewState to modify the state of each corresponding privilege in the access
token. The state is adjusted depending on the value specified in the
Attributes field. For example, if the SE_PRIVILEGE_ENABLED attribute is set
for a privilege,
AdjustTokenPrivileges enables that privilege in the access token. Otherwise, it
disables the privilege.
New Windows Server 2003 Feature
Windows Server 2003 provides a new way for processes to remove
privileges from an access token permanently, as though they had never been
granted. This feature allows a process at startup, or any other time, to remove
a privilege from an access token that it opened. This capability was added so
that processes can comply with the principle of least privilege.
For
example, a process that impersonates users should voluntarily remove any
privileges that it does not need or that impersonated users should not be able
to acquire under any circumstances. This was implemented by adding a new
attribute to the Attributes field:
#define SE_PRIVILEGE_REMOVED (0X00000004L)
If
SE_PRIVILEGE_REMOVED is set in the attribute for a privilege,
AdjustTokenPrivileges will permanently remove the corresponding privilege from the
privileges in the access token. Additionally,
SE_PRIVILEGE_REMOVED supercedes
SE_PRIVILEGE_ENABLED; if both are present in the
Attributes field for a privilege, the privilege will be removed from the
token.
After a privilege is removed from the access token, attempts
to re-enable it result in the warning 1300 STATUS_NOT_ALL_ASSIGNED, as though
the privilege had never existed. Privilege checks for removed privileges result
in the error code 1314 STATUS_PRIVILEGE_NOT_HELD, similar to disabled or
missing privileges.
Therefore, if a process passes an uninitialized
buffer for the
NewState parameter, and if the memory has the bit set at a location that
corresponds to the SE_PRIVILEGE_REMOVED bit in the Attributes field of any
LUID_AND_ATTRIBUTES structure, the corresponding privilege will be removed.