What’s the point of giving my unnamed object proper security attributes since unnamed objects aren’t accessible outside the process anyway (or are they?)

Recall that the NULL DACL grants total access to everybody. Both parts of this sentence are important to note.

  • Everybody: This means everybody. No authentication required. It includes Guest. It includes Anonymous. It includes port scanners. It includes that creepy guy who hangs around the convenience store late at night.
  • Total access: This is more than just read and write access. It includes taking ownership. It includes deleting the object. It includes changing the object's security to lock you out of your own object.

Suppose you're a bit lazy and you decide, "Eh, I know that a NULL DACL grants total access to everybody but since I'm creating an unnamed object, nobody can access the object anyway, so it really doesn't matter what security attributes I put on it, right?"

Um, no. Unnamed objects can be accessed. It's just that they can't be accessed by name.

Other ways of getting a handle to an unnamed object are to duplicate the handle (and the Duplicate­Handle function will gladly duplicate handles across processes) or to inherit it.

Therefore, if you create an object with a NULL DACL, you are exposing it to everybody who has PROCESS_DUP_HANDLE permission. Which is a lot of people. And one of them may in turn be rather sloppy with their security and let the handle escape further.

Just do the right thing. Give the object the correct security attributes. (If you don't intend to use the object outside your process, then the default security attributes are probably just fine.)

Besides, it's easier to create an object with default security than it is to create an object with custom security, so just do the default thing and save yourself a bunch of typing.

Comments (10)
  1. anonymouscommenter says:

    I'm extremely puzzled. In the normal case of all code in process runs as one Windows user and all processes spawned are of the same user, is passing NULL pointer to things that want an ACL dangerous (this is what the .NET wrappers do with no way to change it except for named pipes)?

    I don't care about UAC bypass but I care about other kinds of privilege elevation. It is my understanding that spawning a process owned by one user on another user's session is safe starting w/ Vista.

  2. anonymouscommenter says:


    Most Win32 API sets a default security descriptor if pSecurityDescriptor is NULL.

  3. anonymouscommenter says:

    Thanks for this post Raymond. This made me realize that I was confusing two things:

    setting a NULL DACL vs passing NULL SECURITY_ATTRIBUTES/SECURITY_DESCRIPTOR to Win32 functions such as CreateMutex.

    In other words, in the context of CreateMutex:

    lpMutexAttributes == NULL ; fine

    lpMutexAttributes->lpSecurityDescriptor == NULL ; fine

    lpMutexAttributes->lpSecurityDescriptor->lpDACL == NULL ; bad!

  4. Peter says:

    I never thought of messing with a process by duplicating its handles before.  Is there any way to open a handle to object such that *only* the creating process can access it?

  5. anonymouscommenter says:

    I thought duplicating a handle circumvents the security checks, and I could duplicate a handle to any process I want without worrying about security and DACL of the handle.

    I even found this article ( msdn.microsoft.com/…/bb985041.aspx ) which in its "Third rule", explains exactly this behavior. So I don't see how specifying a NULL DACL can lower the security with regards to DuplicateHandle: Anyone with PROCESS_DUP_HANDLE can duplicate and steal all your handles, no matter its DACL.

    Am I missing something?

  6. @sense: Reread the article.  Right after he states the third rule, he says this: "the system will perform an access check against the object's security descriptor only if one or more new permissions (not already granted in the original session) are being requested."  Remember that in the context of these rules, a session belongs to a process, so if you duplicate a handle, the OS will perform the access check as Raymond describes.  You only get a free pass if it's the handle passed back after creation or if you inherit it.

  7. alegr1 says:

    If you have PROCESS_DUP_HANDLE permission, you're already on the other side of the airtight hatchway.

    Also, DuplicateHandle doesn't check if the requestor has the privileges to the object. Any ACL on the object is not checked.

  8. sense says:

    @MNGoldenEagle: If you reread the sentence you quoted, it says that only new permissions are checked, not the original ones. That's because DuplicateHandle under rare occasions can raise permissions on a handle. This has nothing to do with cross-process duplication. (Refer to DuplicateHandle on MSDN)

    And "inheritance" is another caveat here that I don't get. If you get a handle by inheritance the DACL definitely does not matter. So I'm in the dark about the situation Raymond is talking about.

    Even *after* inheriting (or duplicating for that matter) a handle, is there a situation that the DACL matters? I mean even if a *careless* process gets the handle by duplication/inheritance, then what are the ways it can be leaked, that a proper DACL would prevent? (i.e. Other than OpenXXX functions, where is the DACL checked for an unnamed object?)

  9. anonymouscommenter says:

    Even if the DACL mattered when you duplicate a handle, you can still duplicate the current process handle if you have PROCESS_DUP_HANDLE access. With that you have a handle with complete access to the process which you can use to execute arbitrary code in the context of that process, rendering any questions about access to handles moot.

  10. anonymouscommenter says:

    Right…  Raymond is saying "if you create an object with a NULL DACL, you are exposing it to everybody who has PROCESS_DUP_HANDLE permission".  Others are saying that once you duplicate a handle, its DACL does not matter.  (I am reading "if you create…" to mean "if, and only if, you create…".)

    Can anyone clarify this?

Comments are closed.

Skip to main content