How to Shoot Yourself in the Foot with Security, Part 2: To ACL or Not to ACL
By Jesper M. Johansson
Senior Security Strategist
Security Technology Unit
See other Security Management columns.
The "verbification" of our languages is a wonderful thing, isn't it? ACL is just one of the recent additions to the powerful list of new verbs we have available to us. ACL stands for Access Control List. However, you have probably heard people use it as a verb, in the context of "you need to ACL the boot partition so Everyone can't get to it."
Just as the use of nouns as verbs drive linguists up the wall, statements like that should drive security professionals up the wall. Misuse of ACLs is another one of the very common ways to shoot yourself in the foot with security. In this article, part 2 of an n-part series on how not to do security, we will discuss some of the common problems people get into with ACLs.
Introduction to ACLs
Before we go into the various mechanics of how to shoot yourself in the foot with ACLs we need to cover some basics about ACLs. If you already know what they are and how they work, you may want to jump to Shooting Yourself In The Foot with ACLs. ACLs are used to control subjects' access to objects. The terms subject and object here deserve defining. A subject is basically a security principal in the system. It could be a user, or some other identifiable entity, such as a program. For example, as part of the service hardening work in Windows Vista, a service will now be an identifiable entity that can have permissions associated with it.
An object is any securable entity. In Windows NT-based operating systems, such as Windows 2000, Windows XP, and Windows Server 2003, essentially any object can be secured. This includes things we think about every day, such as files, registry keys, and Active Directory objects; as well as things we do not (unless we are programmers), such as named pipes, mutexes, critical sections, processes, SAM objects, and services.
There are actually several types of ACLs. The three basic types are the following:
Discretionary Access Control List (DACL) A discretionary ACL is one that is up to the system administrator to manage. The owner of the object, or the administrator thereof, can control who has what access to the object. They can even delegate who can administer the ACL.
Mandatory Access Control List (MACL) A mandatory ACL is one that is pre-defined and not under the control of the object owner. MACLs are typically associated with multi-level security (MLS) systems, such as you may see in some of the basic security models. For instance, in a MLS a user may have secret clearance. By virtue of having that level of clearance, the MACLs specify that the user has read access to any object that is classified as secret or below, and has write access to any object that is secret or above. Any object created by the user is automatically classified as secret unless the user specifies to classify it higher. The user cannot create objects classified lower than secret, nor can the user change the classification of an object. The MACL is computed, specified, and enforced, by the system outside the control of the object owner. Windows does not implement MACLs, nor do any other mainstream operating systems. Therefore we will not deal with them further here.
System Access Control List (SACL) A SACL is typically identical in structure to a DACL, except that it is not interpreted to govern access to but rather auditing of the object. Whereas empty and null DACLs are very important, empty and null SACLs simply mean that you do not want to audit something. SACLs are essentially optional, and they are sparingly used in a default installation.
An ACL is simply a list of Access Control List Entries (ACE). Each ACL contains 0 or more ACEs. If no ACEs are present in the ACL then no user has the type of access represented by the ACL.
If you want more information on what ACLs look like, how they work, and how the operating system parses them, please refer to the Windows Platform SDK for in depth technical information. The discussion of Authorization Structures is a good place to start. Protect Your Windows Network also has an in depth section on how ACLs really work. Henceforth, we will use the term ACL to refer to ACLs generically, encompassing concepts common to both DACLs and SACLs. Only when we specifically refer to one or the other type will we use the term DACL or SACL.
Shooting Yourself in the Foot with ACLs
There are many ways to use ACLs, and some lead to the expected result whereas others have dire consequences. In this article, we will look at the following:
Blanket replacement of ACLs
Replacing Everyone with Authenticated Users
Failing to understand SDDL
Everyone:Full Control DACLs
Lack of SACLs on sensitive files
Each of these can cause problems, some more serious than others. Unfortunately, many people also fail to understand that if you set incorrect ACLs there are few ways to recover. In fact, if you destroy the default DACLs on the operating system files, there is really only one guaranteed rollback tool:
There is no way to roll back ACLs in an automated way. You can certainly export ACLs, and there are tools that do that. There are even tools that will stamp those ACLs back on the objects. However, none of them know what to do with objects that did not exist when the snapshot was taken, or with objects which have deliberately had their ACL changed since the snapshot was taken. ACLs are properties of the objects, not of the file system or registry. If the object did not exist when the snap shot was taken, or if it has been deleted since, reapplying an old ACL does not work. If you take a snapshot and then immediately reapply it these tools will probably work fine. However, if you do anything to the system in between the time you take the snapshot and the time you reapply it, the consequences can be dire.
Blanket Replacement of ACLs
For many years it has been fashionable to perform blanket replacement of ACLs to "secure" the system. For instance, if you look at the ACL on the %systemdrive%\boot.ini it contains an ACE for Power Users. Many people believe that if you simply remove all the ACEs for Power Users, you have effectively contained that group. This is not true. There is a very simple fact about Power Users that you need to be aware of:
Power Users are administrators who simply have not made themselves administrators yet.
You cannot remove the ACLs on the file system, or even the registry, and prevent that. Power Users are ingrained in the operating system, and they have sufficient privileges to escalate to an administrator fairly easily. You cannot use Power Users to contain untrusted users. It is only meant to keep well meaning users from hurting themselves and the operating system accidentally. Nevertheless, many organizations have policies to attempt to limit Power Users by performing blanket DACL replacement. The same types of policies are commonly found to replace the Everyone group with Authenticated Users or Domain Users, which we cover below. Unfortunately, attempts to perform blanket DACL replacement often have disastrous effects.
To understand why, take the example of the default DACLs on the file system (Windows has no SACLs specified on the file system or registry by default). The default DACLs are shown in a file called %systemroot%\security\templates\setup security.inf. That file is not, as many people believe, the template that is applied during setup; quite the opposite in fact. The setup security.inf file is actually created during setup, as a snapshot of the settings that are applied during setup. The actual settings that are applied come from another template and settings that various installation routines perform during setup. The file that specifies the default security parameters is called %systemroot%\inf\deflt<systemtype>.inf, where <systemtype> is the type of system you have. Neither of these files is sufficient to roll back, however. For example, defltsrv.inf (for servers) does not contain the directory DACL for %systemroot%\inetsrv. That directory, used for IIS, is not installed during setup on Windows Server 2003. Consequently, if the DACL on that directory is destroyed, defltsrv.inf will not contain the information to roll it back.
Even more problematic, some directories have a DACL that is modified at run-time. Consider the recycle bin, for instance (it is located at %systemdrive%\recycler). The DACL on the directory, which is inherited from the %systemdrive% is:
(A;OICI;FA;;;BA) full control for BUILTIN\Administrators, inherited by objects and containers
(A;OICI;FA;;;SY) full control for NT AUTHORITY\SYSTEM, inherited by objects and containers
(A;;FA;;;LA) Non-inherited, full control for the local Administrator. This ACE provides access only to this folder. The reason this ACE is here is because the local Administrator was the user who created this directory.
(A;OICIIO;GA;;;CO) Full control for Creator/Owner, inherited only, inherited by both objects and containers. This ACE provides no rights to the recycler directory, but does provide them on any directories created underneath.
(A;OICI;0x1200a9;;;BU) Read and execute for BUILTIN\Users, inherited by objects and containers.
(A;CI;LC;;;BU) Create files for BUILTIN\Users, inherited by folders only
(A;CI;DC;;;BU) Create folders, for BUILTIN\Users, inherited by folders only
When a user logs on and deletes a file, a new directory for that user is created in %systemdrive%\recycler. The DACL on those directories is now set partially based on the inheritance from %systemdrive%\recycler and partially programmatically. This means an ACL on that directory may contain the following entries (the actual security identifiers used here are just examples):
These are basically full control and inherit-only DACLs granting full control on children for three users: BUILTIN\Administrators, NT AUTHORITY\System, and the user who owns this particular recycle bin. Here is the problem, these directories override the DACL specified on the parent. If an administrator decides to perform blanket replacement of DACLs to get rid of Power Users or Everyone, the typical way to do so is to define an ACL that you want on the %systemdrive% directory. A common one, which has been recommended in numerous security guides, is this one:
(A;OICI;FA;;;BA) full control for BUILTIN\Administrators, inherited by objects (files) and containers (folders)
(A;OICI;FA;;;SY) full control for NT AUTHORITY\SYSTEM, inherited by files and folders
(A;;FA;;;LA) Non-inherited, full control for the local Administrator. This ACE provides access only to this folder. The reason this ACE is here is because the local Administrator was the user who created this folder.
(A;OICIIO;GA;;;CO) Full control for Creator/Owner, inherited only, inherited by both files and folders. This ACE provides no rights to the recycler folder, but does provide them on any folders created underneath.
(A;OICI;0x1200a9;;;BU) Read and execute for BUILTIN\Users, inherited by files and folders.
The guides then specified to propagate this DACL down the entire tree. That means that the recycle bin no longer works for non-administrator users. They now only have read access to their own recycle bin! New users may not even create a recycle bin as they no longer have the right to do so. On the other hand, all the recycle bins now have the same DACL, so the Administrator's recycle bin is now readable by all users, as are all the user profiles, stored in %systemdrive%\Documents and Settings.
It is easy to see how this type of blanket replacement of DACLs not only ruins the security model on the system, it actually weakens security. It just made sensitive directories, such as all user profiles readable to all users. Rolling the system back to the defaults is virtually impossible without significant manual effort. There is no inherent knowledge of who should have what access to the directories. For example, the user's profile directory is always owned by Administrators, not the user. The name on the directory may not even correspond with the user's name if either has been modified. Hence, the only way to guarantee perfect roll-back is to reinstall the operating system. Any other method that does not involve reinstallation relies on having all ACLs explicitly specified.
Replacing Everyone with Authenticated Users
It is quite common for security "experts" to get very nervous when they see ACLs specified for the Everyone group in Windows. In Windows NT 4.0 and earlier, this was one of the most common ACEs, and it literally meant everyone. In those days it was justified to be worried about Everyone in many cases. Since Windows XP, however, these concerns are almost always unwarranted. By default the anonymous user is not included in Everyone any longer. That means that Everyone is functionally identical to Authenticated Users in Windows XP and Windows Server 2003 unless the "Everyone includes anonymous" setting has been changed from its default value. Therefore, there are few instances where replacing ACEs with Everyone is worthwhile.
One recent issue that arose was a customer that wanted to contain users from other domains in the forest by replacing Everyone with Domain Users. This is troublesome not only because of the issue with blanket ACL replacement discussed earlier, but also because it achieves very little in the way of security. The real security boundary is the forest, not the domain. Therefore, users with advanced privileges in one domain in a forest can escalate to higher privileges in other domains fairly easily. Domains within a forest were never designed to serve as a security boundary, they were merely designed to serve as convenient containers and management units.
Several times I have faced an argument that if you have to change the default value of "Everyone includes anonymous" to allow Everyone to include anonymous users then you have a legitimate reason to perform blanket replacement of Everyone with Authenticated Users. However, such reasoning is flawed. First, allowing Everyone to include anonymous opens up a very large set of holes, not all of which can be closed using ACL replacement on the file system and in the registry. Second, if you have a reason to do this kind of replacement, it is often with the intent of deliberately turning off some security. Selectively turning security back on by changing ACLs is essentially taking a position counter to that which forced you to open up the holes in the first place. Finally, if anonymous access is what you need, then grant access to the user ANONYMOUS. Doing so achieves very granularly controlled anonymous access without opening unnecessary holes.
One final thought on Everyone before moving on: Up through Windows XP the default DACL on shares was for Everyone with Full Control. This caused great consternation with many users who believe that this means anyone can do anything to all the data in that share. That is not actually true. The permissions the user has on objects in a share is the most restrictive combination of the permissions on the share and the permissions on the objects themselves. In other words, if the DACL on the share says "Everyone:Full Control" what it really means is "I don't want to manage permissions here." The permissions on the share are meaningless in that situation. Only the permissions on the file system control access. The advice, therefore, is that unless you have a reason to restrict people further when they are accessing files from the network than when they are accessing them locally there is no reason to change the default permission on a share. You may want to use share ACLs to protect against potentially incorrect file DACLs, but in that case, you probably should fix the file DACLs instead.
Failing to understand SDDL
Many an ACL has been broken because the person that created it did not understand SDDL. SDDL is a very convoluted language, and a full treatment of it is beyond the scope of this document. However, if you are going to be manually creating security templates (which use SDDL) or write programs that set security, you need to have intimate knowledge on SDDL.
There are a few resources to learn SDDL. The first is the Platform SDK. Search the SDK for "Security Descriptor Definition Language" as a starting point. Protect Your Windows Network also has in-depth treatment of SDDL.
Nowhere, however, are the slight modifications made in the Security Configuration Editor (SCE) to standard SDDL documented. SCE also puts a flag on the SDDL string to describe the disposition of existing ACLs. The flag can take a value of 0, 1, and 2, and has the following meaning:
0. ACEs defined explicitly on the target object are merged with the ones in the SDDL string to arrive at the final ACL
1. Used only during setup, same semantics as 2, but incurs extra processing to ensure the complete application of the DACL
2. ACEs defined explicitly on the target object are over written by those in the SDDL string.
If you are going to be significantly changing ACLs, you really need to learn how SDDL works. In the process you will learn an awful lot about how ACLs work, and you will greatly reduce the risk using them incorrectly.
In Windows 2000 a brand-new ACL inheritance model was introduced. The new model is several orders of magnitude more powerful than the previous one. It is also several orders of magnitude more complicated. This leads to a number of potential problems.
The first is to not recognize that if you add or remove an ACE to a directory, it will also be added to or removed from all objects and containers within that directory that inherit the ACL from the parent. This can have wide-ranging consequences.
Another common misconception is that you can remove ACEs from an inherited ACL. You can add to an inherited ACL, but not remove from it. If you need to remove, you need to copy the ACL and then remove the ACEs that offend you.
The final ill is not using inheritance when it is warranted. Some software, and some administrators, explicitly define ACLs on objects all the way down a hierarchy. Inheritance is designed to make configuring ACLs simpler and less error prone use that facility.
DACLs for Everyone that specify Full Control are almost always dangerous (see above for an example when it is not on shares). Some programs, however, will set Everyone:Full Control DACLs because "otherwise the programs does not work as a regular user." Trying to make things work as a regular users is admirable, but the proper way to do that is to fix the program so it does not need Everyone:Full Control DACLs. In some cases, this necessitates a design change. Even in those cases where the program is designed properly and there is a need for access by Everyone, it is almost never justified to allow full control. Most of the time just having read and execute access is sufficient. In some cases, you may need to grant more permissions than that, but carefully evaluate the minimum needed permissions and the minimum set of subjects that need them.
The worst offender of this principle in recent memory was a biometric authentication device that specified an Everyone:Full Control DACL on the directory where they stored the user identity information. Unfortunately, this directory also contained the binaries, including two service binaries, which were running as NT AUTHORITY\System. Any user can now go replace these with any program they want and that program will now run as NT AUTHORITY\System on the next reboot. This provides an extremely simple elevation of privilege attack against the computer.
Another case where Everyone:Full Control DACLs seem to be common is where users realized some application did not work, and they attempted to solve it by applying an Everyone:Full Control DACL. This often actually does resolve the problem; turning off security often does. The problem is that it is exactly that turning off the security. The proper way to resolve this issue is to use applications like filemon and regmon to determine what the minimum set of ACLs required are and opening up only those.
DACLs that deny access are very troublesome, particularly when they are defined for the Everyone user. In one memorable incident many years ago I had a user who put an Everyone:Deny ACE on %systemdrive%. After she clicked yes on all three warning dialogs that popped up the system logged her off and she could no longer log on.
The part she forgot was that Everyone really means everyone and deny really means deny! In the evaluation precedence order followed by the operating system, deny ACEs are supposed to show up first in the DACL (note that there is nothing specifically that enforces this; it is up to the application that sets the ACEs to ensure they are sorted correctly). Consequently, they are evaluated first. Access checking only proceeds until one of the following two conditions are satisfied:
A deny ACE listing any of the requested access methods for the subject is encountered. In this case, the access fails with an access denied error.
ACEs have been collected which contain all the requested access methods for the subject. In this case, the access succeeds.
This precedence order is important. It means that deny ACEs are very, very dangerous. They should be used extremely sparingly. In almost all cases, they are really not necessary other than as "defense in depth" against misconfiguration. While this may be a valuable purpose, it is more common that the deny ACEs cause problems than that they prevent anyone from accessing something they should not have access to. In general, deny ACEs should be avoided.
NULL DACLs are rare, but do happen. A NULL DACL is where there simply is no DACL on an object. This is to contrast with an empty DACL, which is where we have a DACL but there are no ACEs in it. In the former case of a NULL DACL, the semantics are that the user did not wish to secure this object and the effect is the same as if the DACL listed "Everyone:Full Control." In fact, most tools will actually display the DACL that way. An empty DACL, by comparison, is interpreted as the user not wishing to allow anyone access and all attempts to access the object will fail.
NULL DACLs are most common on internal operating system constructs and kernel objects. However, they can occur on anything. For instance, a recent game from Microsoft actually sets a NULL DACL on some files in the program files directory. Recovery in this case is rather simple. First you must take ownership of the object since only as the owner can you set an ACL. Then you apply an appropriate DACL to the object. You will need to be an administrator to do this.
There are not nearly as many ways to shoot yourself in the foot with SACLs as there are with DACLs. However, one stands out fresh: excessive SACLs. SACLs define what kinds of access to audit. An Everyone:Full Control ACE in a SACL means that you want to audit everything anyone does to the object the SACL applies to. Some security guides set these kinds of SACLs on the entire file system. Doing so is nothing more than an exercise in filling your hard drive. It is highly unlikely that you care when some user reads the user32.dll binary. This type of advice was often combined with advice that recommended turning on the FullPrivilegeAuditing setting (called "Audit: Audit access to global system objects" in group policy). This setting ensures that the operating system audits pretty much everything that could possibly ever happen. Turning on that setting will increase the number of audit events by about 5 orders of magnitude.
SACLs should be used sparingly to track meaningful activity that is specified in the organizational security policy, and that might represent realistic threats. Typically, read access, at least on binaries, is uninteresting. Read access on data may be interesting depending on the data, the threats involved, and the risk management philosophy of the organization. Never forget though that auditing is an after the fact activity. When the event gets logged, the event has already happened. You cannot undo the event by auditing it. You can only track that it occurred, assuming of course that the bad guy does not control the audit log, in which case you cannot even track it.
Lack of SACLs on Sensitive Files
Closely related to the statement earlier is the lack of SACLs on sensitive files. Windows ships with no file system SACLs by default. Many customers do not realize that they have no auditing on file system access until after they get attacked and are asked to prove by whom and when. This is unfortunately a bad time to have to discover you have no audit trail.
You should evaluate carefully what to do about auditing, which objects to audit, what types of events to audit, and how to manage the audit logs. This is a basic part of the risk management discipline and needs to be done in all organizations. A basic set of SACLs are available in the scwsacls.inf that ships with the Security Configuration Wizard (SCW) in Windows Server 2003 Service Pack 1. These SACLs are fairly generic but provide a reasonable starting point for defining what you need to audit. In the end, only your risk management discipline can answer that question for you though.
In this article we have dealt with another issue that often bites people. ACL problems are a top support call generator for Microsoft, and many of the problems people run into with them fall into one of the categories mentioned in this article. Hopefully this article will help you avoid these issues, and maybe even serve as fuel in your arguments against those who still believe in these bad operational practices.
If you want to learn more about ACLs, or learn more about the ACLs on a specific system, three tools are well worth mentioning. The first is subinacl. Subinacl comes with the Windows Server 2003 Resource Kit. However, there is an updated version on the Microsoft download center. Subinacl is probably the most versatile, powerful, and dangerous, ACL management tool available. It is entirely command line based, and can manage ACLs on almost any securable entity as long as you can figure out the right syntax.
The second tool is Access Enum from Sysinternals. Access Enum is fairly simple really: it will enumerate all subfolders, files, or registry keys, which have permissions different from its parent. It can be very useful as a quick check to spot obvious problems.
Finally, Security Expressions, from Altaris, is a tool they acquired from Pedestal Software. Security Expresssions has an incredibly rich set of functionality. Specifically to ACLs, it allows you to query a hierarchy for objects with a specific ACE in them. For instance, you can ask it to enumerate all registry keys that allow write for Users. Security Expressions works with the file system and the registry and is a valuable tool in a security analyst's toolkit.
As always, this column is for you. If there is something you would like to see, please send me a message by clicking Contact Us at the very bottom of the page. You may also contact me through my blog. You will find a thread there where we can carry on discussions about this very article.