Here's the code where I'me trying to impersonate a user and then create a mutex. The mutex is not getting created. I get ERROR_ACCESS_DENIED error.
void Impersonate()
{
DWORD logonType = LOGON32_LOGON_INTERACTIVE;
DWORD logonProvider = LOGON32_PROVIDER_DEFAULT;
HANDLE userToken;
HANDLE hMutex;
DWORD err;
LPSTR user = "zoom"; // the user I created myself on my machine.
// It has Administrator privileges, and my account,
// from which I start the app, is Admin too
LPSTR password = "zoom";
LPSTR domain = ".";
hMutex = NULL;
LogonUserA(user, domain, password, logonType, logonProvider,&userToken);
// just to make sure that mutexes are created fine before impersonation
hMutex = CreateMutexA( NULL, FALSE, "mutex_good" );
ImpersonateLoggedOnUser(userToken);
hMutex = CreateMutexA( NULL, FALSE, "mutex_797" ); // I can set any
// random name, no difference
if( hMutex == NULL )
{
err = GetLastError();
// here err is ERROR_ACCESS_DENIED
}
CloseHandle(userToken);
}
I've found several similar topics, but all of them were discussing creating same-name mutex from two different user contexts, i.e. a mutex "MUTEX_1" was already created before impersonation, and attempting to call CreateMutex with the same name but from an impersonated user was failing due to lack of privileges.
This is not the case here, as I am pretty sure that there is no mutex with the same name (or any mutex at all) being created before this code.
I guess I should pass something non-null into CreateMutex, but what exactly?
I'm not very good in Windows security. I understand passing NULL as a first parameter of CreateMutex means that 'default' security attributes will be used. In this case it will be security parameters associated to the thread, i.e. with impersonated user.
Am I correct with my assumptions?
first of all you need understand NT Namespaces and use WinObj tool.
this is like small file system in memory with folders and different "files" in it (here under "files" mean different object types -
Event,Mutant(mutex),Section,Device, ...). every time when you create named object - it placed to some folder in NT Namespaces. folders here (like folders in NTFS) have security descriptors. as result not everybody can create object under any folder.to paraphrase what you do on the file system language (maybe it will be more clear):
i (
John) try create file "mutex_good" under%USERPROFILE%\Documentsand this is ok. because this is my personal folder and I have write access to it.then i login(impersonate) as
zoomand try create file "mutex_797" again under%USERPROFILE%\Documents(%USERPROFILE%in both case expand to same path, sayc:\Users\Johnimpersonation not affect this)and
zoomfail to create file. why ? simply he have no rights to do this. onlyJohn,Administartors,SYSTEMhave write access toc:\Users\Johnbut notzoom.now let return to NT Namespaces. when we call
CreateMutexA( NULL, FALSE, "mutex_797" );where is"mutex_797"will be placed ?if you not
appcontainerand not run in systemsession 0- you run in some usersession <N>and your named objects will be placed in\Sessions\<N>\BaseNamedObjectsdirectory, where N=1,2..so call
CreateMutexA( NULL, FALSE, "mutex_797" );try create mutex at
\Sessions\<N>\BaseNamedObjects\mutex_797however in
\Sessions\<N>\BaseNamedObjectsexist next SymbolicLinks (this is like in NTFS file system):so say if you call
CreateMutexA( NULL, FALSE, "Global\\mutex_797" );Object Manager try place your mutex under
\BaseNamedObjects\mutex_797for more info about this read Kernel object namespaces
and of course we must understand How AccessCheck Works
for directory objects defined the next access rights:
also can more read about this at DirectoryObject DesiredAccess Flags
we need
DIRECTORY_CREATE_OBJECTaccess (Name-creation access to the directory object) for create mutex (or event or any object) in Directorynow for understand why you can create mutex in
\Sessions\<N>\BaseNamedObjectsbutzoomcan not - need look forSecurity Descriptorfor this folder. i dump it:so who have
DIRECTORY_CREATE_OBJECT(4) here ?DWM-1,SYSTEM,Administrators, current logon session users (LogonSessionId_0_294807), current user (John) - and all.zoomnot have this access.for example
Everyonehave (3) -DIRECTORY_QUERY|DIRECTORY_TRAVERSE-Name lookupandQuerybut notName creationyou can ask where in this case I can create mutex after impersonation ? need use
\BaseNamedObjects( global namespace )OR\BaseNamedObjects\Restricteddirectory - I test it security descriptor and result :for
\BaseNamedObjectsfor
\BaseNamedObjects\Restrictedso how you can view
Everyonehere have 2000F - all needed access. hopezoomis member ofEveryone? next code I sure will be workedCreateMutexA(0, 0, "Global\\mutex_797");for
\BaseNamedObjects(global namespace) exist one exception:but for Mutex or say Event - not need SeCreateGlobalPrivilege enabled
you also can say, but
zoomis Administrator account andAdministratorhave access to\Sessions\<N>\BaseNamedObjects- so why this not work ? because withLOGON32_LOGON_INTERACTIVEandUACsystem assign tozoomfiltered token.AdministratorGroup (S-1-5-32-544) exist in token but withSE_GROUP_USE_FOR_DENY_ONLYattribute only - as result it ignores access-allowed ACEs for the SID. andzoomhave anotherLogonSessionId_0_XXXSID - as result andERROR_ACCESS_DENIEDas noted @Harry Johnston - if we will use
LOGON32_LOGON_BATCHinsteadLOGON32_LOGON_INTERACTIVE- we got elevated token - hereAdministratorGroup will be withSE_GROUP_ENABLEDattribute - is enabled for access checks for access-allowed ACEsor how i offered - use
Global\prefix before name - for place object to\BaseNamedObjectswhereEveryonehave full accessthe first parameter - pointer to
SECURITY_ATTRIBUTESlet you overwrite default security descriptor for the new object. this is control who will be have access to it. but this not give you more or less access to Directory where you try place object - you must haveDIRECTORY_CREATE_OBJECTaccess granted and we can not affect this bySECURITY_ATTRIBUTES- this affect on new object but not on existing Directoryand finally some visualization of NT Namespace