Last month, I began a two-part series on Windows NT security by discussing NT's C2 security rating. I discussed the security subsystem's use of security identifiers (SIDs) to identify users, groups, and computers, and I stepped through local and remote logon sequences. I concluded by introducing access tokens. This month, I'll explain tokens in more detail. I'll discuss how impersonation, or the adoption of someone else's token, is a useful and common NT technique. I'll look at security descriptors and access validation, and I'll explain privileges. Then, I'll briefly consider policies and conclude with a preview of NT 5.0's security enhancements.
The Security Reference Monitor uses tokens (or access tokens) to identify the security context of a process or thread. A security context consists of information that describes the privileges, accounts, and groups associated with the process or thread. Last month, I described the logon processhow NT creates an initial token to represent the user and attaches the token to the user's logon shell. All programs the user executes inherit a copy of the initial token. Tokens vary in size because different user accounts have different sets of privileges and associated group accounts. However, all tokens contain the same basic set of information, as Figure 1, page 60, shows.
NT's security mechanisms use two token components to determine what a token's thread or process can do. One component comprises the token's user account SID and group account SID fields. The Security Reference Monitor uses SIDs to determine whether a process or thread can obtain requested access to a securable object, such as an NTFS file.
The group account SIDs in a token signify which groups a user's account is a member of. A server application can disable specific groups to restrict a token's credentials when the server application is performing actions a client requests. Disabling a group produces the same effect as if the group were not present in the SID.
The second component in a token that determines what the token's thread or process can do is the privilege array. A token's privilege array is a list of rights associated with the token. An example privilege is the right for the process or thread associated with the token to shut down the computer. There are about two dozen token privileges.
A token's Default Primary Group field and Default Discretionary Access Control List (DACL) field are security attributes NT applies to objects that a process or thread creates when it uses the token. By including security information in tokens, NT makes it convenient for a process or thread to create objects with standard security attributes, because the process or thread doesn't need to request discrete security information for every object it creates.
Each token's type distinguishes a primary token (a token that identifies the security context of a process) from an impersonation token (a token that threads use to temporarily adopt a different security context, usually of another user). Impersonation tokens carry an impersonation level that signifies what type of impersonation is active in the token. I'll describe impersonation in more detail shortly.
The remainder of the fields in a token serve informational purposes. The Token Source field contains a short textual description of the entity that created the token. Programs that want to know where a token originated use the Token Source to distinguish among sources such as the NT Session Manager, a network file server, or the remote procedure call (RPC) server. The token identifier is a locally unique identifier (LUID) that the Security Reference Monitor assigns to the token when it creates the token. NT's Executive maintains the Executive LUID, a counter it uses to assign a unique numeric identifier to each token.
The token Authentication ID is another kind of LUID. A token's creator assigns the token's Authentication ID. The Local Security Authority Sub System (LSASS) is typically the only token-creator on a system, and LSASS obtains the LUID to assign from the Executive LUID. LSASS then copies the Authentication ID for all tokens descended from an initial logon token. A program can obtain a token's Authentication ID to see whether the token belongs to the same logon session as other tokens the program has examined.
The Executive LUID refreshes the Modification ID every time a token's characteristics are modified. An application can test the Modification ID to discover changes in a security context since the context's last use.
Tokens contain an Expiration Time field that has been present but unused in NT since NT 3.1. Microsoft presumably has plans to allow for tokens that are valid for a period of time before expiring. Consider a user that the systems administrator sets an account expiration time for. Currently, if the user logs on and remains logged on past the account expiration, the system will let the user continue to access resources. The only way to prevent the user from accessing resources is to forcibly log the user off the machine. If NT supported token expiration, the system could prevent the user from opening resources past the token Expiration Time. NT 5.0 doesn't appear to implement token expiration functionality.
Impersonation is a powerful feature NT uses frequently in its security model. NT also implements impersonation in its client/server programming model. In NT, a server exports resources such as files, printers, or databases. A client wanting to access a resource sends a request to the server. When the server receives the request, it must ensure that the client has permission to perform the desired operations on the resource. For example, if a user on a remote machine tries to delete a file on an NTFS share, the server exporting the share must determine whether the user is allowed to delete the file. The obvious process to determine whether a user has permission is for the server to query the user's account and group SIDs and scan the security attributes on the file. This process is tedious to program, prone to errors, and does not change as NT's model might change. Thus, NT uses impersonation to simplify the server's job.
Impersonation lets a server notify the Security Reference Monitor that the server is temporarily adopting the security profile of a client making a resource request. The server can then access resources on behalf of the client, and the Security Reference Monitor carries out the access validations. Usually, a server has access to more resources than a client does and loses some of its security credentials during impersonation. However, the reverse can be true: The server can gain security credentials during impersonation.
A server impersonates a client only within the thread that makes the impersonation request (for more information about threads and processes, see "Inside the Windows NT Scheduler, Part 1," July 1997). Thread-control data structures contain an entry for a possible impersonation token. However, a thread's primary token, which represents the thread's real security credentials, is always accessible in the process' control structure.
NT makes impersonation available in several forms. If a server communicates with a client through a named pipe, the server can tell the Security Reference Monitor that it wants to impersonate the user on the other end of the pipe. If the server is communicating with the client through Dynamic Data Exchange (DDE) or RPC, it can make a similar impersonation request. After the server thread finishes its task, it reverts to its primary security profile. These forms of impersonation are convenient for carrying out specific actions at the request of a client. The disadvantage to these forms of impersonation is that they cannot execute an entire program in the context of a client. In addition, an impersonation token cannot access files or printers on network shares unless the file or printer share supports null sessions.
If an entire application must execute in a client's security context or must access network resources, the client must be logged on to the system. An NT function, LogonUser, enables this action. LogonUser takes an account name, password, and domain or computer name as input and returns a primary token. A server thread can adopt the token as an impersonation token, or the server can start a program that has the client's credentials as its primary token. From a security standpoint, the process that LogonUser creates to run the program looks exactly like a program a user starts by logging on to the machine interactively.
NT impersonates a client's security context in a second way, which is similar to LogonUser: by taking a client's access token, duplicating it, and using it as the primary token that is passed to the CreateProcessAsUser command. The disadvantage to using the LogonUser and CreateProcessAsUser approaches is that a server must obtain the user's account name and password. If the server transmits this information across the network, the server must encrypt it securely so that a malicious user snooping network traffic can't capture it.
To prevent misuse of impersonation, NT does not let servers perform impersonation without a client's consent. The client of a named pipe, DDE, or RPC can specify the level of impersonation it allows a server. Existing impersonation levels are Anonymous, Identification, Impersonation, and Delegation. Each level lets a server perform different types of operations in the client's name. Anonymous impersonation is the most restrictive level--the server cannot imperson-
ate or identify the client. Identification impersonation lets the server obtain the identity (i.e., the SIDs) of the client and the client's privileges, but the server cannot impersonate the client. The Impersonation level lets the server identify and impersonate the client. Finally, Delegation impersonation, the most permissive level of impersonation, lets the server impersonate the client on local and remote systems. NT doesn't fully support Delegation impersonation in versions before NT 5.0. If the client does not set an impersonation level, NT chooses the Impersonation level by default.
Tokens, which identify a user's credentials, are only half of the object security equation. The other half of the equation is the information associated with an object, which specifies who can perform what actions on the object. The data structure for this information is called a security descriptor, which Figure 2 shows. The descriptor has a header that contains the descriptor's revision number, and control flags that specify attributes of the descriptor, such as what memory layout the descriptor uses. The security descriptor contains the SID of the object's owner, which can be for a local or domain user or group account. Following the object owner's SID is the SID of the group that is the main, or primary, group of the object. A security descriptor can have two attached optional lists: a DACL and a System Access Control List (SACL).
The security descriptor's optional DACL is a list of zero or more access control entries (ACEs). A DACL uses its ACEs to describe the actions a particular user or group can perform on the object. An ACE, as Figure 3 shows, has a header that specifies whether the ACE allows or denies accesses, a SID that identifies a user or a group, and a mask that lists the ACE's accesses.
When a user opens an object, the user specifies what actions to perform on the object (e.g., delete, read, or write). If the object is a secured object (i.e., a security descriptor is associated with it), it calls the Security Reference Monitor to determine whether the open is allowed.
Two special cases relate to access. In the first case, if the security descriptor doesn't have a DACL, the Security Reference Monitor allows any open. In the second case, if the descriptor has a DACL but the DACL has no ACEs, the Security Reference Monitor doesn't allow any access to the object.
In the case of a DACL with ACEs, the Security Reference Monitor scans the ACEs looking for one with a SID that matches any of the enabled SIDs in the user's access token (regardless of whether it's a primary or an impersonation token). If the Security Reference Monitor finds such a SID, and the SID's ACE is a deny ACE, the open will fail if the user is requesting any of the accesses listed in the ACE. If the ACE is an allow ACE, the Security Reference Monitor matches the accesses in the ACE to the accesses the user is requesting. If an explicit allow ACE does not match at least one of the user's requested accesses, the Security Reference Monitor continues scanning the ACEs. If allow ACEs match all the user's accesses, the open succeeds. If the Security Reference Monitor processes all the ACEs without granting all of the access types the user requested, it denies the user access to the object.
The process I just explained is illustrated in Figure 4, page 62. User Mark attempts to open an object and requests permission to write to the object. When the Security Reference Monitor looks through the ACEs in the object's DACL, it comes across an ACE that denies members of the Writers group (of which Mark is a member) write access. Thus, even though a subsequent ACE allows Mark write access to the object, the Security Reference Monitor denies Mark access, and the open fails.
A special case is that a user who owns an object (i.e., the user SID matches the owner SID in the security descriptor) or belongs to the group that owns an object can always open the object to modify its security descriptor. Thus, an object's owner can always access an object to modify the security descriptor, even if the descriptor denies the owner all access.
A SACL is constructed similarly to a DACL, except that instead of identifying allowed and denied accesses, the SACL specifies which actions particular users or groups perform that cause NT to write audit events to the NT Security Log. The header of a SACL's ACE shows whether the ACE is of the success or failure type. The header's mask lists accesses that generate events when the user or group identified with the SID performs the access. NT uses SACLS only if an administrator has enabled auditing. Administrators usually disable auditing because SACL processing and security event record logging can introduce significant system overhead.
With auditing enabled, the Security Reference Monitor scans a SACL after a user opens an object associated with the SACL. The Security Reference Monitor looks for a match between the SIDs of the user's enabled groups and a SID in one of the SACL's ACEs combined with the user's SID. If the SIDs match, the Security Reference Monitor checks the ACE type to see whether it matches the result of the open (e.g., the ACE is a succeed ACE, and the open succeeded). If there is a match, the Security Reference Monitor makes a final check to see whether the access requested in the open matches any accesses in the ACE's mask (e.g., the user requested read access, and the read bit is set in the mask). A match at this point results in NT logging the event to the Security Log. Thus, SACLs monitor and record actions users perform on critical resources.
NT uses security descriptors to secure objects for several standard NT components, such as NTFS, the Registry, and the named pipe file system. However, applications written for NT can secure their private objects with security descriptors as well. An application is responsible for maintaining object-to-security-descriptor relationships and calling the Security Reference Monitor to perform access validation.
A privilege is the right a user has to perform a system-related action, such as load a device driver, shut down the computer, or open files for backup purposes. Built-in accounts and groups have default sets of privileges. For example, accounts that belong to the Backup Operators group have the Backup privilege for backing up files. Administrators can use User Manager to add or remove specific privileges from user or group accounts. Table 1, page 64, lists the privileges NT 5.0 beta 1 defines.
Each privilege contains an LUID that identifies the privilege. Microsoft documentation states that the LUID for a given privilege can be different across different computers or from boot to boot. However, privilege LUIDs are hard-coded into NT so that each LUID is guaranteed to be identical on all systems running the same version of NT. In future releases of NT, applications will be able to define additional privileges.
By default, NT disables all the privileges (except the CHANGE_NOTIFY privilege, which NT enables on all accounts) on privilege arrays associated with tokens. Disabling these privileges prevents an application from performing an operation accidentally. For instance, a program must enable the SHUTDOWN privilege before it can shut down the system.
I mentioned last month that I would go inside the SECURITY Registry key to show you what's hiding there. Screen 1 shows that under the Policy subkey you'll find subkeys for each local user and group account. The account keys, two of which are open in the figure, include the account's SID, the default security descriptor, and the list of the account's privileges. Other data in the SECURITY key includes various policy information and domain account definitions if the machine is a domain controller. The SECURITY key's layout is undocumented and subject to change at any time.
Policies, a feature new to NT 4.0, aren't really a part of NT's security model. Individual applications and components define policies. Policies are similar to privileges in that they are rights granted to user accounts. For example, NT Explorer has a set of policies that administrators can control to allow or deny users the ability to move icons around their desktops, set their desktop backgrounds, or have a Run entry on their Start menus.
The System Policy Editor (SPE) is a tool administrators use to create policy profiles and apply them to specific machines or across a domain. NT stores policy values as Registry keys. For example, many of Explorer's policies are in the HKEY_CURRENT_USER\Software\
Policies key. When NT Explorer starts, it reads the values of its policies and allows only specified rights.
NT 5.0 Security
There are three enhancements to NT's security model in NT 5.0. The first enhancement is the ability to control access to securable objects that operating systems (OSs) other than NT create. Objects from OSs other than NT have definitions for access rights. For instance, read access for a directory in a UNIX file system doesn't map neatly to the same access on NT. NT 5.0 introduces the idea of provider-independent access rights. When an application identifies that it's dealing with foreign objects, it can implement provider-independent access rights and use new NT APIs to map the foreign rights to corresponding NT rights. Provider-independent access rights remove the burden of translating from applications.
The second NT 5.0 security enhancement extends ACLs to allow per-property granularity in an ACL. This en- hancement lets a single security descriptor have a DACL or SACL that refers to different properties of an object. For instance, one ACE of a word processor document file's DACL could allow changes to the text, and another ACE could deny the ability to change the document's author. NT 5.0 will also let you specify which ACEs of a parent object's security descriptor will be inherited by the object's children. NT 5.0 considers files to be children of the directory in which they are created, for instance.
The third NT 5.0 security enhancement is an API that creates a new token from an existing token but with reduced privileges or groups. For example, suppose a server wants to impersonate a client by starting a program on the client's behalf, but the server wants to make sure the program cannot shut down the machine, even though the client's security profile possesses the shutdown privilege. The server creates a token identical to the client's token except without the shutdown privilege. If a group is disabled in a restricted token, NT considers the group to be absent for the purpose of granting access but present when NT considers denying access. Thus, removing a group from a token doesn't allow access to objects that aren't otherwise accessible.
I've covered a lot of ground very quickly. Many NT security subtleties exist that I don't have the space to explain, but you have a solid foundation of how the NT security model works. If you want more detailed information, refer to the Microsoft Windows NT Workstation 4.0 Resource Kit. If you're interested in the intricacies of the security model, read the Microsoft Developer's Network documentation on NT security APIs.