Access Control

Understanding Windows File And Registry Permissions

John R. Michener

This article discusses:

  • Access control lists
  • User rights
  • File system permissions
  • Registry and its permissions
This article uses the following technologies:
Windows Server 2008

Contents

Object Security Descriptors
Understanding Security Descriptor string_aces
Standard and Specific Rights
Integrity Labels and Their Usage
Object_guid and inherit_object_guid
Interpreting Security Descriptor string_aces
Windows Resource Protection
Setting Safe File System Permissions
Managing the Registry and Its Permissions
Wrap-Up

Whenever something happens in a system, a principal (which could be a process or thread acting on behalf of a user or service) acts upon objects. Files, directories, and registry keys are examples of commonly known objects. The basic security mechanism of Windows involves having a trusted system component check permissions and rights (AccessCheck) before an operation is allowed to proceed. Thus, you manage system behavior by setting permissions and rights. Since you cannot appropriately set permissions without understanding what is being done under the surface, I'll start by describing security settings on objects and how they are processed, and I'll follow that with how to set values for them.

Before I delve into the technical details, I want to take a look at the permissions at the root of the system drive in Windows Server 2008 using the Windows access control list (ACL) GUI. If I open Windows Explorer, select the security tab, right-click on Local Disc (C:), and select Properties, I see that administrators have full control. If I click on SYSTEM under Group or user names, I see that SYSTEM also has full control. When I click on Users under Group or user names, I see that the permission situation is not as simple: the users group on the system in Figure 1 has Read and Execute, List, Read, and so on. Clicking the Advanced button gives a more detailed view of the permissions associated with the users group (see Figure 2).

fig01.gif

Figure 1 User Rights of Local Disk C

fig02.gif

Figure 2 Advanced View of User Rights over Drive C (Click the image for a larger view)

Here, members of the users group are allowed to create folders and append data to files in the root of the system drive. If you click the Edit button, you'll see another "special" grant to subfolders, shown in Figure 3. This operation requires administrator privileges.

fig03.gif

Figure 3 Edit View of User Special Rights

Thus you see that normal users are allowed, by default, to create subfolders and add content to these folders from the root of the system drive in Windows Server 2008. This functionality was provided to members of the users group on Windows Server 2008 because some third-party software assumes that these permissions are present, and Microsoft did not want to break app compatibility.

Now let's move to a technical discussion of these issues and how they work below the GUI interface presented to the user. All named objects in Windows have security descriptors, which provide information about their owner as well as list which users and subjects have specified permissions. They also can specify which object accesses must be logged to the system event log.

The information about what a subject (user, process, and so on) is allowed to do to an object or resource is specified in a data structure known as an ACL. ACLs enumerate who (which principal) has what kind of access to specific objects. A discretionary ACL (DACL) is a type of ACL where the owners of objects are allowed to change them. Whenever an object is accessed, the security descriptor is compared to the principal's permissions to verify that the requested access is allowed.

Note that Windows also supports system ACLs (SACLs) for objects and has used SACL settings to establish which events are logged to the audit log for many releases. With Windows Server 2008 and Windows Vista, SACL has been extended to carry integrity-level information.

This integrity label is used to establish the "low" label that marks the Internet Explorer process used in LowRights Internet Explorer. "System" and "high" labels are used to protect critical system resources. The Windows message pump filters messages based upon the integrity level of the message. For example, medium-level processes do not receive messages sent from low-level processes, and high-level processes do not receive messages from low- or medium-level processes.

At this point, the integrity-level protection is a speed bump, not a true security barrier about which you can make security guarantees. The height of this bump will increase significantly in later releases when it is likely to become a real security barrier.

As with other modern OSs, Windows relies on DACLs for general access-control decisions. Here I will focus primarily on ­DACLs. For the system to determine whether a principal is allowed to perform an operation upon an object, several things are checked: the principal's privileges, the principal's token, and the object's security descriptor. The binary security descriptor on an object is passed to the AccessCheck routine with the principal's token. A requested access mask bit vector is prepared, representing the access rights that must be granted for the access check to succeed. It is passed with the principal's security descriptor to the AccessCheck routine, which examines the user's security token and considers the principal's privileges (typically based on roles or membership, such as administrator) in combination with the requested access and the DACL on the object.

If the requested access is satisfied by the principal's privileges, access is granted. Otherwise, the DACL access control entries (ACEs) are examined in order. As soon as the security system is able to show that all requested access components are allowed or that any of them is denied, it returns a success in the former case and a failure in the latter.

Thus, the DACL's list of ACEs should be appropriately ordered. The standard (canonical) ordering is to first place explicit denies, then explicit allows, general (group) denies, and group allows. If the canonical ordering isn't used, unanticipated allows or denies may occur.

Object Security Descriptors

While the security descriptor is a binary data structure, it relies on the security descriptor string format to provide a somewhat human-readable text format. A string format security descriptor is represented as a null-terminated string with tokens to indicate each of the four main components: owner (O:), primary group (G:), DACL (D:), and SACL (S:), as Figure 4 illustrates.

Figure 4 Security Descriptors

fig04a.gif

Security Identifiers (SIDs) are structured to provide parsing information and include 96 bits of random information (and may include 32 bits of sequence count) to serve as a unique identifier for owners. The string_aces (ACEs expressed in string format) are the structures that explicitly grant or deny permissions in the DACL and set policy in the SACL. Each string_ace is enclosed in parentheses and has the following structure:

(ace_type;ace_flags;rights;object_guid;inherit_ object_guid;account_sid)

Only those grants that are necessary for proper access to the object in question must be present. Frequently the owner_sid and group_sid are omitted from the security descriptor. If not explicitly specified at creation time, the owner field of the security descriptor is set to the SID of the principal invoking the object creation. The group field is set to the primary group of the principal's security token. If it is not necessary to audit an object or to set an integrity label, the SACL will not be present.

Within the string_aces, only those fields that are necessary are included (the minimal set is ace_type, rights, and the subject, typically the account_sid). Typically, the object_guid and inherit_object_guid are not present. The system parses ACEs in order, from first to last, until access is either granted or denied. Thus, ordering of ACEs is important. "Deny permissions" should be placed before "allow permissions."

An ACL with no ACEs in it is an empty DACL. Since an ACE grants a specified subject access to an object, no one can access an object with an empty DACL. An object without a DACL is said to have a NULL DACL. Objects with NULL DACLs have not been secured and everybody has full control over them. For that reason, do not set either empty or NULL DACLs.

It is worthwhile now to look at what a realistic security descriptor looks like. Here's a security descriptor for the root of the Windows Server 2008 system drive (note that cacls is a legacy command-line routine for investigating and setting ACLs and is being replaced by icacls. Unfortunately, icacls does not support a command-line switch to output the results in standard Security Descriptor Definition Language, or SDDL, a switch that cacls has—the /S flag):

C:\>cacls c:/ /s c:\"D:PAI(A;OICI;FA;;;SY)(A;OICI;FA;;;BA)(A;OICI;0x1200a9;;;BU)(A;CI;LC;;;BU)(A;CIIO;DC;;;BU)(A;OICIIO;GA;;;CO)"

Based upon what we know about security descriptors, you can see from the leading "D:" that no ownership or group membership is claimed and that the descriptor is a DACL. The DACL is protected: the "P" and the Windows NT 5.0 inherit flag is set. Then we have a number of ace_strings that have to be deciphered.

Understanding Security Descriptor string_aces

Recall the string_aces format I showed you previously. The allowed ace_types are defined in Figure 5, and the allowed ace_flags are defined in Figure 6. The ace_flags for inheritance are the ruling factors for the inheritance of ACEs.

Figure 5 Allowed ace_types

fig05.gif

Figure 6 Allowed ace_flags

fig06.gif

ACE rights are indicated by a string that denotes the access rights controlled by ACE. This string can be a hexadecimal string representation of the access rights, such as "0x7800003F", or it can be a concatenation of the Rights strings, such as "CCLCSWLOCRRC", which I will interpret later. The hex representation and associated bit values are shown in Figure 7.

Figure 7 ACL Access Mask

fig07.gif

The system uses a single bitmap representation of ACE rights for all objects. Not all bits are meaningful for various objects. Only rights that are appropriate for an object are applied. Standard rights are those rights that are common to all securable objects. Generic rights are convenient shorthand for specifying rights of similar intent for various objects. The specification of generic rights is mapped into the appropriate set of specific rights. Integrity labels are also encoded using the ACE rights field when specifying the SACL. The available rights for various objects are listed in Figure 8.

Figure 8 Generic Rights

fig08.gif

There are a number of largely equivalent rights mappings that are used rather indiscriminately. Full Control (FC) is equivalent to Generic_All (GA). For the file system, File All (FA) is the appropriate full control declaration. Key All (KA) is the appropriate full control declaration for the registry. Generic declarations are frequently used in place of the more appropriate declarations but are mapped to the appropriate file system or registry key declarations, as appropriate. SDDL expressions frequently mix these terms, thus you need to be aware of the equivalences.

Standard and Specific Rights

Many objects can be assigned rights. In addition to files and directories, we have registry keys, processes, desktops, and so forth. For the full list, see Figures A through J. Since we will be discussing permissions on the file system and registry, the specific rights for these objects are provided in Figures 9 and 10.

Figure 9 Specific File Rights

fig09.gif

Figure 10 Specific Registry Rights

fig10.gif

Integrity Labels and Their Usage

As was already stated, the integrity labels, if present, are stored in the object's SACL. Objects implicitly have medium integrity, so if there is no integrity label, the object has medium integrity. Similarly, if there is no integrity label on a security token, it also has medium integrity. The low-integrity label is used to label Low Rights processes, such as LowRights Internet Explorer and related untrusted objects. The "high" and "system" levels are used to help isolate those objects from medium and low processes and objects. The integrity labels are shown in Figure 11.

Figure 11 Integrity Labels

fig11.gif

Object_guid and inherit_object_guid

Object_guid and inherit_object_guid are used in specifying the security of objects in Active Directory. They are not used when securing the file system or registry. "OA" and "OD" in the ace_type field of an ACE string correspond to an object-allow and object-deny ACE, respectively. In this case, the object_guid holds the guid of the object being permissioned and the inherit_object_guid holds the guid of the object from which it inherits permissions.

The account_sid field in the ACE structure denotes the security principal that is being granted or denied the access rights specified in the ACE. The account_sid field may hold a SID, which is a long structured identifier that is essentially meaningless to a person, or a shorthand "SID string" notation for a common account. The SID string notation for common accounts is used wherever possible to make the system more readable. A table of common or well-known accounts and their SID strings is shown in Figure J below.

The OW declaration of Owner Rights is new with Windows Server 2008 and Windows Vista. Previously, the Creator/Owner (CO) of an object had the standard rights of read control (RC) and Write_DAC (WD) over that object, enabling the owner to set the security on the object. This creates a problem if a user is a member of a group and creates a large number of objects. If that user leaves the group, he would still have control over those objects because he is the owner of these objects, which granted them RC plus Write_DAC permissions. The presence of the OW owner ACE restriction blocks the implicit grant of RC/WD to the owner unless these grants are explicitly made to the owner ACE of any other relevant ACE in the ACL. This allows mitigation of this security issue.

Interpreting Security Descriptor string_aces

The output from cacls for the root of the system drive was:

"D:PAI(A;OICI;FA;;;SY)(A;OICI;FA;;;BA)(A;OICI;0x1200a9;;;BU)(A;CI;LC;;;BU)(A;CIIO;DC;;;BU) (A;OICIIO;GA;;;CO)"

Parsing this for readability, you get:

"D:PAI (A;OICI;FA;;;SY) (A;OICI;FA;;;BA) (A;OICI;0x1200a9;;;BU)(A;CI;LC;;;BU)(A;CIIO;DC;;;BU) (A;OICIIO;GA;;;CO)"

This is a protected DACL with the auto-inherit flag for a modern file systems set. The protected flag means that inheritable parent grants won't be inherited; the DACL is protected from inheritance from the object's parent. In this case there is no parent, as it is the root.

The built-in administrator and system are granted inheritable File All over both files (due to the object inherit) and directories (due to the container inherit, or CI). This means that this DACL grants File All recursively on all files and directories below the root—except where inheritance is stopped by a protected DACL when the grant in the protected DACL must be examined. CO is granted Generic_All, which maps to File All, over both files and directories below the root directory (due to the inherit-only flag).

The grant to the built-in user is far more interesting. The first string_ace applies to both files and directories in the root and below and allows List, Read, ReadEA, Traverse, Execute, ReadAttr, Read­Control, and Sync. The second string_ace allows AddSubDir in the root and below (due to the IO—inherit-only flag), while the third string_ace allows AddFile in the directories below the root. This is the same as you saw when you explored these permissions with the ACL graphical interface of Windows Explorer.

Windows Resource Protection

Starting with Windows Server 2008 and Windows Vista, components declare their needed security settings in their manifests, which are signed by a Microsoft code signing root. The manifest specifies the ACLs and other permissions associated with the file. Thus, when a component is installed, it carries with it the appropriate security settings. In addition, OS files are protected from inadvertent damage by the system administrator using Windows Resource Protection (WRP). WRP relies upon a new system-level entity, Trusted Installer, to own and manage system files and folders.

A good facility to allow normal users to perform installations of authorized components was added in Windows Vista. Thus the Power User role is no longer required, and instances of ACEs that contain the Power User SID were removed. The Power User group still exists, but the component manifests have been scanned, and all detected instances of grants to PU have been deleted.

Let's look at a system directory to see the new permissions. This is also another good exercise in SDDL reading:

C:\>cacls c:\windows /s C:\Windows "D:PAI(A;;FA;;;S-1-5-80-956008885-3418522649-18310 38044-1853292631-2271478464)(A;CIIO;GA;;;S-1-5-80-956008885-3 418522649-1831038044-1853292631-2271478464)(A;;0x1301bf;;;SY} (A;OICIIO;GA;;;SY)(A;;0x1301bf;;;BA)(A;OICIIO;GA;;;BA)(A;;0x1200a9;;;BU) (A;OICIIO;GXGR;;;BU)(A;OICIIO;GA;;;CO)"

Trusted Installer's SID is S-1-5-80-956008885-3418522649-1831038044-1853292631-2271478464. Using TI as shorthand, we find the following:

C:\Windows "D:PAI (A;;FA;;;TI)(A;CIIO;GA;;;TI) (A;;0x1301bf;;;SY)(A;OICIIO;GA;;;SY) (A;;0x1301bf;;;BA)(A;OICIIO;GA;;;BA) (A;;0x1200a9;;;BU)(A;OICIIO;GXGR;;;BU) (A;OICIIO;GA;;;CO)"

Interpreting this, you see it is a protected ACE that is being applied to C:\Windows using the Windows NT 5.0 inheritance model.

Trusted Installer is granted full control over C:\Windows and is granted Generic_All over all child containers under C:\Windows (since it is CI, inherit only).

System and admin are granted Read, Write, Append, ReadEA, WriteEA, Execute, ReadAttr, WriteAttr, Del, RCtl, and Sync, = SDGRGWGX on C:\Windows. This is Generic_All minus Write_Owner and Write_DAC; Admin and System are granted everything but the ability to change the owner or the ACL. "BA" and "SY" have Generic_All over child file and directory objects.

Since the admin has the take ownership privilege, he can still assert WriteOwnership and take control anyway. Administrator and system are a security equivalent. But with this privilege, a determined administrator can circumvent the WRP ACL controls.

CO also has Generic_All over child file and directory objects. Built-in user has Read, ReadEA, Execute, ReadAttr, RCtl, and Sync, = GRGX over C:\Windows and GRGX over subdirectories and their files below C:\Windows.

All system files and folders have protected ACLs that grant Trusted Installer full control. The control of files by Trusted Installer is not expressed in the declaration on the system root directory but in the separate declarations of the Windows components.

Setting Safe File System Permissions

Now that you have some idea of how file system ACLs work and how to read them, let's look at setting them. If you are installing an application, you should install this to the default Program Files location. The default ACLs for this location give full control to Administrator and Local System, which is appropriate.

If you install an application to some other location or grant the user the ability to choose his preferred location for an application, you have a problem: the default ACLs for other drives and for non-system and non-application areas of the system drive are not secure enough. In such cases, you must explicitly ACL your folders with the appropriate protected DACLs. The simplest and safest choice for installing an application is to duplicate the security settings on the Program Files folder. If you choose not to do this, set the DACL so that non-administrators cannot change DACLs or ownership of executables and cannot write, append, or delete files in directories containing executables.

The basic rule if you are setting DACLs is that you do not want administrators or other users executing code that was written by a user. This is particularly a problem if the folder in question would be presumed to be trusted, typically by being in a trusted area (Windows, Program Files, and so forth). Doing so allows Elevation of Privilege (EoP) to administrator and increases the risk of cross-user attacks. Thus, if a user can write files to such a folder, other users and administrators should not be able to execute them.

At first glance, it would appear that you should not let users write to folders in Windows, System, Program Files, and so on, at any time. It turns out there are valid reasons for doing so. The most common is to record error log data. If the executable is running under the user's credentials and has to log an error, it needs write/append access to the error log/logging folder. (If you logged errors to per-user locations on a multi-user system, you would have the logging data spread over the system instead of being associated with the executable. Applications and services typically write to a shared folder or registry key.) You'll find the same issues in the registry, where error information is frequently stored in specified machine registry keys by a process running with user permissions.

Do not mix user writeable files with executable files. Use separate directories for files that must be trusted (such as executables) and files that must not be trusted (anything potentially written by an untrusted user). ACL the directories appropriately—administrator control over the executables and user read/execute, but not write. The same guidance applies to registry keys and subkeys.

Client and server differ here: server administrators are assumed to be far more knowledgeable than users running as administrator. Server administrators know that they must not execute code from untrusted areas of the system. By establishing a naming convention to isolate data files from executables in the system, you provide the administrator guidance concerning the trustworthiness of the executable—logging subdirectories are not trustworthy, thus users must not have the ability to create or modify these subdirectories, as this would enable them to spoof safe naming rules.

In the client environment, it is far easier to fool the administrative user into executing code. With such naive administrators, directories that have user write must not allow administrator execute privileges in order to prevent a user from installing an executable and then fooling an administrative user into running it and compromising the system. For example, if your application or service needs to store log information that will be written to under user privileges, you should create a logging subdirectory to hold this data. This subdirectory should not allow admin execute. One way to do this is to add a leading explicit deny for file execute to everybody, such as D;OI;WP;;;WD. This prevents cross-user attacks in directories that allow file write or modify to users.

There are many cases where it is expected that users will share data (though we do not want users sharing and executing code from a shared area). For example, a home user (or his photo-viewing application) is likely to create a folder such as C:\Photos. The user expects to be able to allow multiple users to write to this folder and have multiple users edit the various photos in this folder. The default ACLs on the root of the system drive on Windows Vista support this. The other common sharing situation is a folder in which users place data for other users to read. Only the creator of the data is allowed to delete or modify the data, but other users may copy it and then edit the copy. This is a shared read scenario, and it is the default for the system drive on Windows Server 2008.

Consider the case where you choose to lock down the system drive and, specifically, ACL folders for sharing. You have to choose the ACLs that are appropriate for these two rather common scenarios. We want administrators to be able to manage the objects and we want to prevent security issues associated with execution of code in these folders (note that the ACEs here prevent even the owner from executing code from these folders).

Here's a Shared Read ACE:

D:P(D;OI;WP;;;WD)(A;OICI;FA;;;BA)(A;OICI;FA;;;SY)(A;OICI;FA;;;CO)(A;CI;0x1200af;;;AU)(A;OI;GR;;;AU)

And here is a Collaborative ACE:

D:P(D;OI;WP;;;WD)(A;OICI;FA;;;BA)(A;OICI;FA;;;SY)(A;OICI;FA;;;CO)(A;OICI;SDGRGW;;;AU)

Note that both ACLs start with a deny execute ACE for everybody, object inherit (to apply it to files), to prevent user system and cross-user attacks. Then administrator, system (system does not really need it), and CO are given full control = File All.

For the Shared Read scenario, an authenticated user is granted List, AddFile, AddSubDir, ReadEA, Traverse, ReadAttr, RCtl, and Sync due to the restriction of this grant to CI, and thus to directories, and is separately granted Generic Read to all files. For the Collaborative scenario, an authenticated user is granted Delete, Generic Read, and Generic Write on files and directories.

Managing the Registry and Its Permissions

Windows stores much of its state information in the Windows Registry. Registry data stores are known as Hives, where data is stored in keys and subkeys, which are both viewed as containers (subkeys are not viewed as objects).

User-specific data is stored in the appropriate user section of Hive Key Users (HKEY_USERS). As one would expect, much of this data is writeable by the user. In any session, HKey_Current_User (HKCU) points to the appropriate section of HKEY_USERS.

System and machine information is stored in the HKEY_LOCAL_MACHINE (HKLM) hive. Included in HKLM is information for all the various system services, most of which now run with limited permissions under either the various Local Service or Network Service groups. Services and applications can store state information in their registry keys. This information should be stored in subkeys, either in the service key or in a key under the service key. The service key must not be ACL'd to enable the service to have SetKey over its own service key (or the WDac or WOwn, which would enable such an attack), as this allows the service to point to a different executable. Such an error introduces a potential EoP against the service host, as the Service Control Manager will load the executable that is pointed to when the system loads.

The general guidance for DACLs for HKLM is that they must not enable users to write or modify this data or the associated ACLs and ownership. As with the guidance on setting file system DACLs in system areas, exceptions occur for error logging where an app or a service running under a user or limited context needs to record error information. The guidance for such situations is similar to equivalent issues in the file system—create separate keys for such information and ACL them appropriately. Thus the sensitive information can be ACL'd to trusted subjects (administrator, system, and so on) and the logging data can be writeable, as needed.

The situation you are trying to avoid is a user modifying trusted parameters (such as turning the antivirus or anti-malware service off) or tampering with a tool that users or administrators use. Let's assume that when Notepad is invoked it loads C:\windows\notepad.exe. The default ACL over C:\windows does not allow an attacker to modify the executable. If the attacker can rewrite the link from the Notepad icon to its executable, the attacker can cause a different file, say C:\tools\load_rootkit.exe, to load. This could load a rootkit and then load Notepad so that the user would not be aware of the compromise.

If the attacker can drive the link through the registry, the protective ACLs on the file system are immaterial. You are concerned with attacks from limited system services against other system services as well. In Windows Vista and Windows Server 2008, services are separated into groups by the privileges they need. The defense-in-depth protections offered by this service isolation require configuration of the service permissions so that services cannot tamper with one another, particularly across service groups.

Just as we are concerned with preventing users from adding or linking to malicious executables, we must also prevent services from having the ability to change their permissions and capabilities. The ChangeConf privilege on services must be restricted to administrator, system, or Trusted Installer since this privilege allows the possessor to change the permissions on the service.

Wrap-Up

Windows provides a very rich set of permission controls that can be used to permit operations, block operations, and provide defense-in-depth against new threats. Unavoidably associated with this rich ability to control access is the issue of complexity.

Following a few general guidelines will help you avoid problems. For instance, the system defaults are reasonable compromises. You should use them. If you are installing an application outside of program files, use the program files ACLs. In some cases you may want to tighten defaults a little bit, such as the default grants to users on drives; but remember that if you indeed do this, you must be prepared to look for and deal with potential application compatibility issues.

The most important guideline is that administrators or system accounts must not execute code or follow pointers to code that a user can write or modify. Almost as important is that users not execute code or follow pointers to code that another user can write or modify. These guidelines drive all of the security issues discussed here. If any changes you make follow these guidelines, you have avoided the most serious security issues.

For more information about access control components, see "Access Control Components" on MSDN. Information about the ace_string access mask components can be found in the MSDN "ACCESS_MASK" article, which includes pointers to specific rights for files, directories, registry keys, and shared sections. Additional information about restricted SIDs can be found in the MSDN "Restricted Tokens" article.

The Full List of Rights

Figure A Standard Rights

figa.gif

Figure B Specific Rights for Files and Directories

figb.gif

Figure C Specific Rights for File Map and Registry

figc.gif

Figure D Specific Rights for Service Control Manager and Services

figd.gif

Figure E Specific Rights for Processes and Threads

fige.gif

Figure F Specific Rights for WindowStations and Desktops

figf.gif

Figure G Specific Rights for Symbolic Links and Events

figg.gif

Figure H Specific Rights for Semaphores and Mutexes

figh.gif

Figure I Specific Rights for Pipes and Tokens

figi.gif

Figure J Common or Well-Known Accounts and Their SID Strings

figj.gif

John R. Michener is senior security program manager for Microsoft. He joined Windows Security at Microsoft almost 5 years ago. John has more than 20 years of experience in system security and has done three security startups. He is the cryptography and permissions expert for the Windows Software Assurance team. You can reach him at jmichene@microsoft.com.