NULL DACLs and Other Dangerous ACE Types

NULL DACLs and Other Dangerous ACE Types

A NULL DACL is a way of granting all access to an object to all users, including attackers. I sometimes quip that NULL DACL == No Defense. And it is absolutely true. If you don t care that anyone can do anything to your object including read from it, write to it, delete existing data, modify existing data, and deny others access to the object a NULL DACL is fine. However, I have yet to see a product for which such a requirement is of benefit, which, of course, completely rules out the use of NULL DACLs in your products!

If you see code like the following, file a bug. It should be fixed because the object is not protected.

if (SetSecurityDescriptorDacl(&sd,                                 TRUE,     // DACL Present                                             NULL,     // NULL DACL                                 FALSE)) {                     // Use security descriptor and NULL DACL.                               }

Another variation of this is to populate a SECURITY_DESCRIPTOR structure manually. The following code will also create a NULL DACL:

SECURITY_DESCRIPTOR sd = {      SECURITY_DESCRIPTOR_REVISION,                           0x0,                           SE_DACL_PRESENT,                           0x0,                           0x0,                           0x0,                           0x0};      // Dacl is 0, or NULL.

note

A debug version of your application will assert if you create a NULL DACL by using the ATL library included with Visual Studio .NET.

While working on Windows XP, I and others on the Secure Windows Initiative team and Windows Security Penetration Team spent many hours looking for NULL DACLs, filing bugs against the code owners, and getting them fixed. Then we spent time analyzing why people created objects with NULL DACLs in the first place. We found two reasons:

  • Developers were overwhelmed by the code required to create ACLs. Hopefully, you understand at least one of the three options I have covered earlier in this chapter and can create code to reflect the ACLs you need.

  • The developer thought that a NULL DACL would be good enough because his code always worked when the NULL DACL was used. By now, you know this is a bad thing because if it works so well for users, it probably works just as well for attackers!

Frankly, I think both of these reveal a touch of laziness or perhaps lack of knowledge. It s true that defining a good ACL takes a little work, but it is well worth the effort. If your application is attacked because of a weak ACL, you will have to patch your code anyway. You may as well get it right now.

note

A NULL DACL is not the same as a NULL security descriptor. If the SD is set to NULL when creating an object, the operating system will create a default SD including a default DACL, usually inherited from the object s parent.

I once wrote a simple tool in Perl to look for NULL DACLs in C and C++ source code. I used the tool to analyze some source code from a Microsoft partner and found about a dozen NULL DACLs. After filing the bugs and waiting for them to be fixed, I ran the tool again to verify that they had been fixed, and indeed, the tool a second time yielded no more NULL DACLs. Almost three months after filing the bugs, I performed a security source code audit and saw that the code for one of the NULL DACL bugs looked strange. It had changed from

SetSecurityDescriptorDacl(&sd, TRUE, NULL, // DACL FALSE);

to the following, which would not be picked up by the tool:

SetSecurityDescriptorDacl(&sd, TRUE, ::malloc(0xFFFFFFFF), // DACL FALSE);

While the code is a silly stunt, it is somewhat clever. If the memory allocation function, malloc, fails to allocate the requested memory block, it returns NULL. The developer is attempting to allocate 0xFFFFFFFF, or 4,294,967,295 bytes of data, which on most machines will fail, and hence the developer set the DACL to NULL! I looked at the bug and saw the developer claimed he had fixed the bug. Of course, I did what comes naturally and reopened the bug and didn t relax until the code was fixed properly.

NULL DACLs and Auditing

Here s another insidious aspect of NULL DACLs: if a valid user does indeed change a NULL DACL to Everyone (Deny Access), chances are good that nothing is logged in the Windows event log to indicate this malicious act because the chances are also good that you have no audit ACE (an SACL) on the object either!

important

NULL DACLs are simply dangerous. If you find a NULL DACL in your application, file a bug and get it fixed.

Dangerous ACE Types

You should be wary of three other dangerous ACE types: Everyone (WRITE_DAC), Everyone (WRITE_OWNER), and directory ACLs, which allow anyone to add new executables.

Everyone (WRITE_DAC)

WRITE_DAC is the right to modify the DACL in the object s security descriptor. If an untrusted user can change the ACL, the user can give himself whatever access to the object he wants and can deny others access to the object.

Everyone (WRITE_OWNER)

WRITE_OWNER is the right to change the owner in the object s security descriptor. By definition, the owner of an object can do anything to the object. If an untrusted user can change the object owner, all access is possible for that user as is denying others access to the object.

Everyone (FILE_ADD_FILE)

The Everyone (FILE_ADD_FILE) ACE is particularly dangerous because it allows untrusted users to add new executables to the file system. The danger is that an attacker can write a malicious executable file to a file system and wait for an administrator to run the application. Then the malevolent application, a Trojan, performs nefarious acts. In short, never allow untrusted users to write files to shared application directories.

Everyone (DELETE)

The Everyone (DELETE) ACE allows anyone to delete the object, and you should never allow untrusted users to delete objects created by your application.

Everyone (FILE_DELETE_CHILD)

The Everyone (FILE_DELETE_CHILD) ACE, known as Delete Subfolders And Files in the user interface, is set on container objects, such as directories. It allows a user to delete a child object, such as a file, even if the user does not have access to the child object. If the user has FILE_DELETE_CHILD permission to the parent, she can delete the child object regardless of the permissions on the child.

Everyone (GENERIC_ALL)

GENERIC_ALL, also referred to as Full Control, is as dangerous as a NULL DACL. Don t do it.

What If I Can t Change the NULL DACL?

I can think of no reason to create an object with a NULL DACL, other than the case in which it simply doesn t matter if the object is compromised. I saw an example of this once where a dialog box would pop up to tell the user a joke. It used a mutex, with a NULL DACL to protect it, to make sure that multiple versions of the application did not put multiple instances of the dialog box on the screen at once. If an attacker placed a deny ACE on the object, the user would not see any jokes not a major problem!

At an absolute minimum, you should create an ACL that does not allow all users to

  • Write a new DACL to the object [Everyone (WRITE_DAC)]

  • Write a new owner to the object [Everyone (WRITE_OWNER)]

  • Delete the object [Everyone (DELETE)]

The access mask will vary from object to object. For example, for a registry key, the mask will be the following:

DWORD dwFlags = KEY_ALL_ACCESS & ~WRITE_DAC  & ~WRITE_OWNER & ~DELETE;

For a file or directory, it will be like this:

DWORD dwFlags = FILE_ALL_ACCESS & ~WRITE_DAC & ~WRITE_OWNER & ~DELETE & ~FILE_DELETE_CHILD 



Writing Secure Code
Writing Secure Code, Second Edition
ISBN: 0735617228
EAN: 2147483647
Year: 2005
Pages: 153

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net