CreateMutex fails after impersonation

余生颓废 提交于 2021-02-19 02:49:08

问题


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?


回答1:


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%\Documents and this is ok. because this is my personal folder and I have write access to it.

then i login(impersonate) as zoom and try create file "mutex_797" again under %USERPROFILE%\Documents (%USERPROFILE% in both case expand to same path, say c:\Users\John impersonation not affect this)

and zoom fail to create file. why ? simply he have no rights to do this. only John, Administartors, SYSTEM have write access to c:\Users\John but not zoom.

now let return to NT Namespaces. when we call CreateMutexA( NULL, FALSE, "mutex_797" ); where is "mutex_797" will be placed ?

if you not appcontainer and not run in system session 0 - you run in some user session <N> and your named objects will be placed in \Sessions\<N>\BaseNamedObjects directory, where N=1,2..

so call CreateMutexA( NULL, FALSE, "mutex_797" );

try create mutex at \Sessions\<N>\BaseNamedObjects\mutex_797

however in \Sessions\<N>\BaseNamedObjects exist next SymbolicLinks (this is like in NTFS file system):

Global -> \BaseNamedObjects
Local  -> \Sessions\<N>\BaseNamedObjects
Session -> \Sessions\BNOLINKS

so say if you call CreateMutexA( NULL, FALSE, "Global\\mutex_797" );

Object Manager try place your mutex under \BaseNamedObjects\mutex_797

for 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:

//
// Object Manager Directory Specific Access Rights.
//

#define DIRECTORY_QUERY                 (0x0001)
#define DIRECTORY_TRAVERSE              (0x0002)
#define DIRECTORY_CREATE_OBJECT         (0x0004)
#define DIRECTORY_CREATE_SUBDIRECTORY   (0x0008)

also can more read about this at DirectoryObject DesiredAccess Flags

we need DIRECTORY_CREATE_OBJECT access (Name-creation access to the directory object) for create mutex (or event or any object) in Directory

now for understand why you can create mutex in \Sessions\<N>\BaseNamedObjects but zoom can not - need look for Security Descriptor for this folder. i dump it:

T FL AcessMsK Sid
0 00 000F000F S-1-5-90-0-1 DWM-1
0 00 000F000F S-1-5-18 SYSTEM
0 0B 10000000 S-1-5-18 SYSTEM
0 0B 10000000 S-1-3-0 CREATOR OWNER
0 00 000F000F S-1-5-21-4026734978-3280735129-2412320105-1001 John
0 0B 10000000 S-1-5-5-0-294807 LogonSessionId_0_294807
0 00 0002000F S-1-5-5-0-294807 LogonSessionId_0_294807
0 00 0002000F S-1-5-32-544 Administrators
0 02 00000003 S-1-1-0 Everyone
0 00 00000002 S-1-5-12 RESTRICTED
17 00 00000001 S-1-16-4096 Low Mandatory Level

so who have DIRECTORY_CREATE_OBJECT (4) here ? DWM-1, SYSTEM, Administrators, current logon session users (LogonSessionId_0_294807 ), current user (John) - and all. zoom not have this access.

for example Everyone have (3) - DIRECTORY_QUERY|DIRECTORY_TRAVERSE - Name lookup and Query but not Name creation

you can ask where in this case I can create mutex after impersonation ? need use \BaseNamedObjects ( global namespace )OR \BaseNamedObjects\Restricted directory - I test it security descriptor and result :

for \BaseNamedObjects

T FL AcessMsK Sid
0 00 0002000F S-1-1-0 Everyone
0 00 00000002 S-1-5-12 RESTRICTED
0 00 000F000F S-1-5-90-0-0 
0 00 000F000F S-1-5-18 SYSTEM
17 00 00000001 S-1-16-4096 Low Mandatory Level

for \BaseNamedObjects\Restricted

T FL AcessMsK Sid
0 00 0002000F S-1-1-0 Everyone
0 00 0002000F S-1-5-12 RESTRICTED
0 00 000F000F S-1-5-90-0-0 
0 00 000F000F S-1-5-18 SYSTEM
17 00 00000001 S-1-16-4096 Low Mandatory Level

so how you can view Everyone here have 2000F - all needed access. hope zoom is member of Everyone ? next code I sure will be worked

CreateMutexA(0, 0, "Global\\mutex_797");

for \BaseNamedObjects (global namespace) exist one exception:

The creation of a file-mapping object in the global namespace, by using CreateFileMapping, from a session other than session zero is a privileged operation. Because of this, an application running in an arbitrary Remote Desktop Session Host (RD Session Host) server session must have SeCreateGlobalPrivilege enabled in order to create a file-mapping object in the global namespace successfully. The privilege check is limited to the creation of file-mapping objects, and does not apply to opening existing ones. For example, if a service or the system creates a file-mapping object, any process running in any session can access that file-mapping object provided that the user has the necessary access.

but for Mutex or say Event - not need SeCreateGlobalPrivilege enabled


you also can say, but zoom is Administrator account and Administrator have access to \Sessions\<N>\BaseNamedObjects - so why this not work ? because with LOGON32_LOGON_INTERACTIVE and UAC system assign to zoom filtered token. Administrator Group (S-1-5-32-544) exist in token but with SE_GROUP_USE_FOR_DENY_ONLY attribute only - as result it ignores access-allowed ACEs for the SID. and zoom have another LogonSessionId_0_XXX SID - as result and ERROR_ACCESS_DENIED

as noted @Harry Johnston - if we will use LOGON32_LOGON_BATCH instead LOGON32_LOGON_INTERACTIVE - we got elevated token - here Administrator Group will be with SE_GROUP_ENABLED attribute - is enabled for access checks for access-allowed ACEs

or how i offered - use Global\ prefix before name - for place object to \BaseNamedObjects where Everyone have full access

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.

the first parameter - pointer to SECURITY_ATTRIBUTES let 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 have DIRECTORY_CREATE_OBJECT access granted and we can not affect this by SECURITY_ATTRIBUTES - this affect on new object but not on existing Directory

and finally some visualization of NT Namespace



来源:https://stackoverflow.com/questions/41369232/createmutex-fails-after-impersonation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!