Protect Your Windows Network: From Perimeter to Data
For most of the history of computing, ACLs have been the principal means of verifying and enforcing authorization to resources and data. After you have identified and authenticated yourself, some mechanism (tokens, tickets, or similar) authorizes you against an ACL and either permits or denies access. And for the most part, ACLs have worked wellat least until the advent of portable computing.
Types of Access Control Lists
There are three types of ACLs:
-
Mandatory ACLs (MACLs)
-
Discretionary ACLs (DACLs)
-
System ACLs (SACLs)
An MACL is a system-enforced ACL that even the administrator cannot modify. It is not used in most general-purpose operating systems. Rather, it is a core component of a multilevel security (MLS) operating system. MLS systems are not in common use today, although there have been many variants produced in the past. They might use an MACL, for instance, to enforce data classifications, such as Top Secret, Confidential, and so on. The administrator cannot modify this ACL. As soon as something is classified , the system automatically enforces access from users based on their classification rating and the operation they are performing. Since Windows does not support this type of ACL, we do not consider it in the rest of this chapter. If you want to learn more about them, pick up just about any textbook on security or take a Certified Information Systems Security Professional (CISSP) review seminar. In spite of the fact that no off-the-shelf systems today provide this functionality, both devote significant amount of time to the topic.
A DACL is what we typically mean when we refer to an ACL. It is an ACL that is at the discretion of the data owner, the administrator, or both. A DACL is composed of access control list entries (ACEs). Each ACE defines some permission that is allowed or not allowed to some user or group . For instance, some object may have an ACE that defines that administrators have full control and another that defines that Everyone has read access.
An SACL is identical in structure to a DACL, but it defines not what access is allowed but what access is audited. If the ACEs in an SACL defined Administrators:Full Control and Everyone:Read, as we showed earlier, it would instead mean that any access by administrators is audited but that only read access is audited for Everyone.
Because DACLs are identical in structure to SACLs, we use the term ACL collectively to refer to both of them. If we specify either DACL or SACL, we refer only to that specific form of ACL.
Security Descriptors and Access Control List Entries
Permissions defined on objects are granted to security principals; they define who can do what to those objects. Objects always have an owner, and the owner can always alter an object's permissions. Remember that permissions are hierarchical throughout much of Windowsin the file system, in the Registry, in the directoryso keep this in mind as you develop your ACL'ing scheme. There are times when rights will override permissionsthe classic example is file backups . Even if the owner of a file sets a permission that denies Everyone access, those who have the right to back up files will still be able to read the file.
The implementation of the permission is in the form of a security descriptor (SD). When a program tries to access a securable object on behalf of some user, the program presents an access token which contains information about the user, membership in groups, privileges, and so on. The program also presents an access mask containing the desired access. The OS compares the information in the security descriptor with the information in the access token and the requested access methods. As long as the user, or some group or set of groups the user is a member of, has all the requested access methods listed in an allow ACE in the DACL, the access is permitted. If any single requested access method listed in a deny ACE is encountered before collecting all the access methods from allow ACEs, the entire access is disallowed .
The SD on an object contains both the DACL and the SACL (if one is defined). All objects have an SD, but they may have an empty, or null, DACL or SACL field in them. If an SD has a null SACL, it simply means that there will not be any auditing done on that object. However, a null DACL is much more problematic . It means that there are no restrictions on access to that object. In other words, a null DACL means that all users, including anonymous users, get full control over the object. Null DACLs are rare on the file system and Registry, but there have been multiple security bulletins issued to correct null DACLs on other objects, such as services and various other system objects.
SDs are typically represented in string format in the Security Descriptor Definition Language (SDDL). Since this is the way they are represented in the security templates we use to harden systems, it is worth reviewing the format here.
An SD contains information on the owner of the object, the primary group (not used in Windows but included for compatibility with other operating systems), the DACL, and the SACL. The format is as follows :
O:owner_sid G:group_sid D:dacl_flags(string_ace1)(string_ace2)... (string_acen) S:sacl_flags(string_ace1)(string_ace2)... (string_acen)
The security identifier (SID) was explained in Chapter 12, "Server and Client Hardening," so we do not repeat that description here.
The line that starts with D: represents the DACL, and the line that starts with S: represents the SACL. They are formatted identically, containing a set of flags and zero or more ACEs. The flags define the inheritance behavior of the ACL. There are three possible flags. (These show the DACL names for the flags. The SACL names are identical, except they have SACL instead of DACL.)
-
SE_DACL_PROTECTED The ACL is protected and cannot be modified by inherited ACEs from parent objects. In SDDL, this flag is represented by the letter P .
-
SE_DACL_AUTO_INHERITED The ACL is inherited by child objects that have been configured to inherit their ACL from parent objects. This flag would be set by the system on both of the child objects, indicating that the ACL is inherited, and on parent objects, indicating that the ACL should be inherited by child objects. In SDDL, this flag is represented by the letters AI .
-
SE_DACL_AUTO_INHERIT_REQ The ACL is automatically propagated to child objects and the SE_DACL_AUTO_INHERITED flag is set on the ACL of those child objects. This flag, set by the programmer and represented in SDDL by the letters AR , is used to ensure that all child objects get their ACLs propagated from their parent. It should be used with great caution because it could potentially overwrite a carefully crafted set of ACLs on child objects. For instance, one of the authors once was managing a large lab with student shares. The student shares had very finely crafted ACLs allowing only each student modify access. When the inheritance of ACLs was first rolled out in Service Pack 4 for Windows NT 4.0, he tried to use it to control the ACLs on that hierarchy. Unfortunately, he set the SE_DACL_AUTO_INHERITED_REQ flag on the DACL for the parent directory with the result that all the student directories were now readable by all the other students and not modifiable by anyone .
A string ACE is a string representation of the ACE. The string representation has the following fields, separated by semicolons:
-
ace_type A one- or two-letter code defining the type of ACE this is. The values possible are as follows:
-
A Access allowed ACE, used to apply an ACE to a container like an allowed ACE.
-
D Access denied ACE. This is simply the corollary to the access-specific objects, for instance. Typically, this ACE type is used with an object GUID, defining the object that the ACE applies to.
-
OA Object access allowed. Object ACEs are used in Active Directory to apply ACLs to a domain or OU, but so that they only apply to specific objects, for instance. Typically, this ACE type is used with an object GUID, defining the object that the ACE applies to.
-
OD Object access denied. The corollary to the object allowed ACE.
-
AU Audit ACE. This type denotes a standard audit ACE and is used where you would find the A flag.
-
AL Alarm ACE. Alarm ACEs are not used in Windows today. They are included for future use, for instance, to throw an administrative alert when some object is touched.
-
OU Object audit ACE. The audit ACE on an object
-
OL Object alarm ACE. Alarm ACE on some object.
-
-
ace_flags A two-letter code denoting how the ACE should be processed , as follows:
-
CI Container inherit flag. Child objects that are containers, such as directories and Registry keys, inherit the ACE as an effective ACE. This inherited ACE is inheritable by children of the container if the NP flag is not set.
-
OI Object inherit flag. Noncontainer child objects, such as files, Registry values, etc. inherit this ACE as an effective ACE.
For container child objects the ACE is inherited as an inherit-only ACE unless the NP flag is set, in which case the ACE is not inherited at all.
-
NP No Propagate flag. The ACE is not inherited by any further child objects. If this flag is used together with the CI or OI flags, the ACE is inherited by the first generation of children, but the CI and OI flags are then cleared to prevent it from being inherited further. This flag is represented by the "Apply these permissions to objects and/or containers within this container only" check box in the GUI ACL editor. This is shown in Figure 17-1.
Figure 17-1. The NP flag as it shows up in the GUI.
-
IO Inherit only. This flag indicates that the ACE does not control access to the object it is applied to but rather is only used for inheritance. This flag is for example used in the default ACL on the C: drive in Windows XP. As shown in Figure 17-2, it is used on the Creator Owner ACE as well as one of the Built-in Users ACEs.
Figure 17-2. The default DACL on the C: drive in Windows XP.
-
ID Inherited ACE. This flag is set when an ACE is inherited from another object. It is typically not used in security templates. Ordinarily, you will only see this if you write programs that parse security descriptors on existing objects.
-
SA Successful audit ACE. Used in SACLs to generate audit messages for successful access attempts.
-
FA Failed audit ACE. Used in SACLs to generate audit messages for failed access attempts.
-
-
Rights This is the string that specifies the rights the subject (the group or user that the ACE applies to) has to the object under control. The rights expression can take two forms. One is the use of a two-letter code indicating one of the generic, standard, or object-specific rights. The other is a hexadecimal string representing a bitmask of the access rights. For instance, the generic access rights are the following:
-
GA Generic all. Indicates full control to the subject
-
GX Generic execute
-
GR Generic read
-
GW Generic write
The generic access rights are mapped to a combination of standard and object specific access rights, as appropriate for the object. The standard access rights are a bit more granular than the generic ones and provide additional control over the actual settings. They include the following:
-
RC Read control. Denotes the ability to read the SD (excluding the SACL) for the object
-
SD Standard delete. The ability to delete the object
-
WD Write DAC(L). Defines the ability to modify the DACL on the object
-
WO Write owner. The ability to change the owner of the object
Finally, there are object-specific rights that define the meaning of particular rights for an object. For instance, for a file or a directory, they are as follows:
-
FA File all. Full control on a file or directory. Specifying GA and FA in an SD has the same effect.
-
FR File read. Read access to the file or directory. Identical effect to GR.
-
FX File execute. The right to execute the file or traverse into the directory. The effect is identical to GX.
-
FW File write. The right to write data to the file or create new files in the director. The effect is identical to GW.
-
The generic and standard rights on a file or directory define a set of file and directory-specific rights. Table 17-1 shows the actual meaning of these rights.
Table 17-1. The Actual Meaning of the Generic Rights on a File
Generic Right | File-Specific Rights |
---|---|
Generic execute | The ability to read the attributes of the file. The ability to read the SD of the file. This is defined as the STANDARD_RIGHTS_EXECUTE and is what gives the subject the ability to execute the file. The ability to use the file handle in a wait object. This right, known as SYNCHRONIZE, is typically used in multithreaded programming to be alerted to when a file changes. It is not particularly important for administrators. |
Generic read | The ability to read the attributes of the file. The ability to read the data in the file. Note that if you have only execute permission on a file but not read you cannot actually read the data in the file. The right to read the extended attributes for the file. The ability to read the SD of a file. This is defined as STANDARD_RIGHTS_READ and is identical currently to STANDARD_RIGHTS_EXECUTE because they are both defined as READ_CONTROL. The ability to use the file handle in a wait object. This right, known as SYNCHRONIZE, is typically used in multithreaded programming to be alerted to when a file changes. It is not particularly important for administrators. |
Generic write | The right to append data to an existing file, or to add subdirectories to a directory. The right to change the attributes of a file. The right to add data to a file or add files to a directory. The ability to modify the extended attributes of a file. The ability to read the SD of a file. This is defined as STANDARD_RIGHTS_WRITE and is identical currently to STANDARD_RIGHTS_EXECUTE since they are both defined as READ_CONTROL. The ability to use the file handle in a wait object. This right, known as SYNCHRONIZE, is typically used in multithreaded programming to be alerted to when a file changes. It is not particularly important for administrators. |
Although Table 17-1 only shows the meaning of the generic rights on a file, the same exercise can be undertaken for any securable object. The exact meaning is defined in the Windows Platform Software Developers Kit (SDK). If you want to learn more, start with the definition of an SDDL string at http://msdn.microsoft.com/library/en-us/security/security/security_descriptor_string_format.asp.
-
object_guid Used to represent some object in AD. This field is not typically used on other containers.
-
inherit_object_guid Used to represent the inherited object type in an inherited ACE structure for a particular object. Again, this field is not typically used outside of AD.
-
account_sid The SID of the account that this ACE applies to. This can be either a SID like the ones we saw in Chapter 12, or a SID string that defines a well-known SID. For instance, the SID string BA denotes Built-in Administrators. For more information, refer to the platform SDK: http://msdn.microsoft.com/library/en-us/secauthz/security/sid_strings.asp.
Now that you understand the structure of an SDDL string, we can work through an example to drive home how these are used. Consider the default ACL on the C: drive in Windows XP and Server 2003. It is shown in Figure 17-2.
The SDDL representation of this DACL is as follows:
[View full width]
[View full width]
D:(A;OICI;FA;;;BA)(A;OICI;FA;;;SY)(A;OICIIO;GA;;;CO)(A;OICI;0x1200a9;;;BU)(A;CI;LC;;;BU)
There are seven separate ACEs in this DACL. The first is (A;OICI;FA;;;BA). The ACE type A denotes that this is an access allowed ACE. The OI and CI ACE flags indicate that it should be inherited by both directories and files. The right FA indicates that the ACE gives the subject full control. The object GUIDs are empty, because this is a file. Finally, we see that the SID is the SID string for built-in administrators (i.e., the local Administrators group). The GUI shows this ACE as the first line.
The next ACE, (A;OICI;FA;;;SY), is identical to the first, except that the SID string specifies SA, for Local System, i.e. the operating system itself.
The third ACE, (A;OICIIO;GA;;;CO), is very much like the first two, with a few distinct differences. First, the flag IO is also specified, indicating that ACE is only used for inheritance. This ACE, specified for the user CO, or Creator/Owner, is what gives users access to directories they create underneath the C: drive. The right they get is GA (in other words, generic all, or full control).
The next three ACEs apply to BU, or the built-in Users group. The first one, (A;OICI;0x1200a9;;;BU), specifies access on C: as well as is inherited by subdirectories and files. The right is specified by a hexadecimal bitmask, in this case 0x1200a9. This indicates the bits that are used in the access mask. An access mask is a 32-bit construct that is shown in Table 17-2.
Table 17-2. The Access Mask in Windows Specifies Granular Object Rights
3 | 3 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | ||||||||||
1 |
| 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 |
| 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 |
| 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 |
|
GR | GW | GE | GA | Reserved | MA | AS | Standard access rights | Object-specific access rights |
Using Table 17-2, it is simple to interpret the bitmask. 0x1200a9 is specified in binary as follows:
100100000000010101001
In Table 17-3, we have pasted in this bitmask as the second row and added a row below showing how each of these bits is interpreted for files.
Table 17-3. Evaluating an Access Mask
[View Full Width]
As we can see from Table 17-3, the rights granted to users by specifying 0x1200a9 are as follows:
-
SYNCHRONIZE
-
READ_CONTROL
-
FILE_READ_ATTRIBUTES
-
FILE_EXECUTE
-
FILE_READ_EA
-
FILE_READ_DATA
The file-specific access right FR includes READ_CONTROL, SYNCHRONIZE, FILE_READ_DATA, FILE_READ_ATTRIBUTES, and FILE_READ_EA. The file-specific right FX includes READ_CONTROL, FILE_READ_ATTRIBUTES, FILE_EXECUTE, and SYNCHRONIZE. In other words, 0x1200a9 is equivalent to granting both FR, read, and FX, execute to Users. If you go back to Figure 17-2, you will find that there is an ACE shown in there for Read and Execute on this folder, subfolders , and files. That is the ACE we just found.
The next ACE, (A;CI;LC;;;BU), is also for Users. It specifies the right LC. LC is actually a directory service-specific access right. It is not normally used on files. On an Active Directory object, it specifies the right to list child objects. It corresponds to 0x4 in hex, in other words, bit 3 in the access mask. Bit 3 is FILE_APPEND_DATA. In other words, even though LC is not a valid object-specific access right on a file or directory object, it just represents a bitmask that can be interpreted on a file or directory object. The result is the ACE that gives Users the right to create folders in the C: directory. It is inherited by subdirectories, as we see by the CI flag.
The following ACE, (A;CIIO;DC;;;BU) is also defined for Users. This one is also inherited by containers, but in this case it specifies the IO, or inherit only, flag. That means it does not define any ACE on the C: directory itself. The right, DC in this case, is another directory service-specific right that would govern whether the subject can delete child objects were it applied to an AD object. It evaluates to 0x2, or bit 1 in the access mask. Applied to a directory, bit 1 means FILE_ADD_FILE, or the ability to create files. This is the ACE we see in Figure 17-2 that allows users to create files and write data in subfolders.
The final ACE on the C: directory, (A;;0x1200a9;;;WD), applies to the SID string WD, or World (in other words, Everyone). No inheritance bits are specified, and hence this ACE is not inherited. The right is 0x1200a9, which we now know means read and execute. In other words, this ACE gives Everyone the right to read and execute everything in the C: directory.
The " Troublesome " Everyone Group
We hear far too often from various people who think they understand security that the Everyone group is extremely troublesome and needs to be removed at all cost. Typically, that means they replace it with the Authenticated Users group instead. This is completely counterproductive. The reason is that Everyone is identical to Authenticated Users in Windows XP and Server 2003. Unless the security policy has been changed from the default, the Everyone group no longer includes the anonymous user, which was the only difference between Everyone and Authenticated Users in Windows 2000. Thus, performing wholesale ACL replacements to replace Everyone with Authenticated Users does absolutely nothing to secure the system. And, if you have actually set the switch to include anonymous in Everyone, chances are it was done for a reason. In this case, replacing Everyone with Authenticated Users breaks that change, calling into question why it was done in the first place. To make things worse , these types of changes are typically made by people who do not fully understand SDDL strings and treat them very casually. The last time we dealt with a network where the administrators had attempted to replace Everyone with Authenticated Users, we found that the Administrator's profile was now world readable and that the recycle bin no longer worked. This happened because they had propagated the new ACL down the tree, blowing away the built-in ACLs on those directories. Because there were user directories already defined on the system it was impossible to automatically return the ACLs to the defaults. The net result was that they needed to rebuild several thousand machines that had these new ACLs defined. |
Using the same method, you can analyze any SDDL string. For example, as an exercise we leave you to analyze the SDDL representation of the ACL on the %systemroot% directory, which is
D:P(A;CIOI;GRGX;;;BU)(A;CIOI;GRGWGXSD;;;PU)(A;CIOI;GA;;;BA)(A;CIOI;GA;;;SY)(A;CIOI;GA;;;CO)
You do not need to understand SDDL strings to set ACLs on files and directories that you create yourself, but an intricate knowledge of them will help impress people at cocktail parties. In addition, you absolutely must understand them forward and backward if you are going to modify the built-in ACLs. You must also understand the concept of Creator Owner. There are, as you have seen, a lot of ACEs for Creator Owner. When a user creates a directory, or the system creates a directory on behalf of the user, that ACE is replaced with one containing the user's SID on the new directory. This happens, for instance, on all the subdirectories under Documents and Settings. Now, if you go through and propagate an ACL through that hierarchy, you would reset not only the Creator Owner ACL on the Documents and Settings directory, you would also reset the ACL on the subdirectories owned by particular users. To restore those, you would have to manually re-create all the ACLs on those directories. It was by propagating ACLs through the Documents and Settings directory that the administrators mentioned in the sidebar "The 'Troublesome' Everyone Group" managed to make the Administrator's profile world readable. We ask you to make life easier on yourself by leaving system-defined ACLs alone and focusing on setting appropriate ACLs on objects you create yourself. The system-defined ACLs are perfectly adequate in Windows XP and higher. In Windows 2000, you need to set one ACL, on the root of the C: drive. However, do not do this yourself. Use the Windows 2000 Hardening Guide to do it for you. It took us the better part of a day to ensure we got exactly the right effect on the ACL in that guide. The guide is available at http://go.microsoft.com/fwlink/?LinkId=28591.
WARNING: Do not try to modify the default ACLs on files installed by the operating system. There is nothing wrong with them in Windows XP and higher, and the risk is much greater that you will put the system into an unrecoverable state than the chance that you will actually provide any additional security.
Typically, we see administrators trying to change these ACLs to remove the Everyone group, or to destroy the Power Users group. Neither of these is a worthwhile thing to do. As described in the sidebar "The 'Troublesome' Everyone Group," there is nothing wrong with the Everyone group any longer. The Power Users group should not be used at all. Power Users are basically administrators who have not made themselves administrators yet. It provides no meaningful separation from administrators other than to make it take one additional API call to shoot yourself in the foot . Instead of trying to destroy that group, use security policy to make it a restricted group and ensure there is nobody in it. That way it does not matter what permissions and rights it has.