Last time we looked at how the Whidbey version of CasPol uses a mutex to indicate the state of the security system. One of the more interesting fallouts from this model is that is that we can actually use this information to prevent security from being turned off in the first place.
As I mentioned in the last post, the CLR looks for a mutex named \BaseNamedObjects\CLR_CASOFF_MUTEX, and if this mutex exists, is not abandoned, and is owned by the BUILTIN\Administrators group, it considers security to be in an off state. The obvious CasPol -s off implementation given that information is to acquire the named mutex and set the ACL such that the CLR will recognize it. From there, it's pretty easy to see that in order to prevent CasPol from successfully turning off security, we need to prevent it from acquiring the mutex.
How would we go about doing that? According to the MSDN documentation, if CreateMutex is called with a non-NULL lpName parameter, it will return either a new mutex with the given name, or if the mutex already exists, it will return a handle to the existing object while setting the last error to ERROR_ALREADY_EXISTS. Basically that's saying that Windows only allows one mutex with a given name on each system.
This means that if we create the mutex before CasPol does, we'll have a handle to the same mutex that CasPol and the CLR use to determine the security state. If we're on Windows NT, we can make use of the Windows security system to prevent anyone else from having access to that object. For CasPol, not having access to the mutex means that it can't possibly set it to the state the CLR is looking for. More importantly if the CLR doesn't have access to the mutex, it can't use it to determine that security is off.
So our strategy is to simply create the mutex before anyone else on the machine, and ACL it down such that nobody is allowed access to it. We can pull this off in less than 20 lines of code:
First we setup a SECURITY_ATTRIBUTES structure that does not allow handles to inherit, and attach a DACL containing a single ACE which denies all access to the Everyone group. To create the DACL, we use the ConvertStringSecurityDescriptorToSecurityDescriptor function, which is available on Windows XP and later, so you'll need to use an XP machine to run this code, and define _WIN32_WINNT and WINVER to 0x0501 or higher before including windows.h and sddl.h
The string parameter to ConvertStringSecurityDescriptorToSecurityDescriptor looks a little daunting at first, but it's easy to break down:
After creating the security attributes, we attempt to create the mutex with them. If that fails, then it is possible the mutex already exists, perhaps because security is already off. Once we acquire the mutex, we just wait for the user to press any key to close it and exit.
When running this code, you'll notice that attempting to turn security off with CasPol will fail, and security will always be enforced by the CLR.
Now for the disclaimer. This code is really for demonstration purposes only, and is not a silver bullet against security being turned off.