模拟后 CreateMutex 失败

Vla*_*sky 4 c++ windows impersonation mutex

这是我尝试模拟用户然后创建互斥体的代码。未创建互斥体。我收到 ERROR_ACCESS_DENIED 错误。

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);
}
Run Code Online (Sandbox Code Playgroud)

我发现了几个类似的主题,但所有这些主题都在讨论从两个不同的用户上下文创建同名互斥体,即在模拟之前已经创建了互斥体“MUTEX_1”,并尝试使用相同的名称但从模拟的对象调用 CreateMutex用户由于缺乏权限而失败。

这里的情况并非如此,因为我非常确定在此代码之前没有创建同名的互斥体(或根本没有任何互斥体)。

我想我应该将一些非空值传递给 CreateMutex,但到底是什么?

我不太擅长 Windows 安全性。我理解将 NULL 作为 CreateMutex 的第一个参数传递意味着将使用“默认”安全属性。在这种情况下,它将是与线程关联的安全参数,即与模拟用户关联的安全参数。

我的假设正确吗?

RbM*_*bMm 5

首先,您需要了解NT 命名空间并使用WinObj工具。

这就像内存中的小型文件系统,其中包含文件夹和不同的“文件”(此处“文件”下表示不同的对象类型 - EventMutant(互斥体)Section,,,Device...)。每次创建命名对象时,它都会放置到NT 命名空间中的某个文件夹中。这里的文件夹(如 NTFS 中的文件夹)具有安全描述符。因此,并非每个人都可以在任何文件夹下创建对象。

解释一下你在文件系统语言上所做的事情(也许会更清楚):

我(John)尝试在下面创建文件“mutex_good” %USERPROFILE%\Documents,这是可以的。因为这是我的个人文件夹,我对其有写权限。

然后我登录(模拟)zoom并尝试再次创建文件“mutex_797” %USERPROFILE%\Documents%USERPROFILE%在两种情况下都扩展到相同的路径,说c:\Users\John模拟不会影响这一点)

并且zoom无法创建文件。为什么 ?只是他没有权利这样做。只有John, Administartors,SYSTEM具有写入权限,c:\Users\John但没有zoom

现在让我们回到NT 命名空间。当我们调用时,它将被放置CreateMutexA( NULL, FALSE, "mutex_797" );在哪里?"mutex_797"

如果您没有appcontainer并且不在系统中运行session 0- 您在某个用户中运行session <N>,您的命名对象将被放置在\Sessions\<N>\BaseNamedObjects目录中,其中 N=1,2..

所以打电话CreateMutexA( NULL, FALSE, "mutex_797" );

尝试创建互斥体\Sessions\<N>\BaseNamedObjects\mutex_797

但是\Sessions\<N>\BaseNamedObjects存在下一个 SymbolicLinks(这就像在 NTFS 文件系统中):

Global -> \BaseNamedObjects
Local  -> \Sessions\<N>\BaseNamedObjects
Session -> \Sessions\BNOLINKS
Run Code Online (Sandbox Code Playgroud)

所以说如果你打电话CreateMutexA( NULL, FALSE, "Global\\mutex_797" );

对象管理器尝试将互斥体放在\BaseNamedObjects\mutex_797

有关此内容的更多信息,请阅读内核对象命名空间

当然我们必须了解AccessCheck 的工作原理

对于目录对象定义了下一个访问权限:

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

#define DIRECTORY_QUERY                 (0x0001)
#define DIRECTORY_TRAVERSE              (0x0002)
#define DIRECTORY_CREATE_OBJECT         (0x0004)
#define DIRECTORY_CREATE_SUBDIRECTORY   (0x0008)
Run Code Online (Sandbox Code Playgroud)

还可以在DirectoryObject DesiredAccess Flags中阅读更多相关内容

我们需要DIRECTORY_CREATE_OBJECT访问(对目录对象的名称创建访问)来在目录中创建互斥体(或事件或任何对象)

现在要了解为什么您可以在其中创建互斥锁\Sessions\<N>\BaseNamedObjectszoom不能 - 需要查找Security Descriptor此文件夹。我转储它:

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
Run Code Online (Sandbox Code Playgroud)

那么这里谁有DIRECTORY_CREATE_OBJECT(4)?DWM-1SYSTEMAdministrators、当前登录会话用户 ( LogonSessionId_0_294807)、当前用户 ( John) - 以及所有。zoom没有此访问权限。

例如Everyone有 (3) - DIRECTORY_QUERY|DIRECTORY_TRAVERSE-Name lookupQuery不是Name creation

您可以问在这种情况下我可以在模拟后在哪里创建互斥体?需要使用\BaseNamedObjects全局命名空间)或\BaseNamedObjects\Restricted目录 - 我测试它的安全描述符和结果:

为了\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
Run Code Online (Sandbox Code Playgroud)

为了\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
Run Code Online (Sandbox Code Playgroud)

所以你如何Everyone在这里查看有 2000F - 所有需要的访问权限。希望zoom是 的成员Everyone?下一个代码我肯定会起作用

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

for \BaseNamedObjects(全局命名空间) 存在一个例外:

通过使用 CreateFileMapping 从会话零以外的会话在全局命名空间中创建文件映射对象是一项特权操作。因此,在任意远程桌面会话主机(RD 会话主机)服务器会话中运行的应用程序必须启用 SeCreateGlobalPrivilege 才能在全局命名空间中成功创建文件映射对象。权限检查仅限于创建文件映射对象,不适用于打开现有文件映射对象。例如,如果服务或系统创建文件映射对象,则在任何会话中运行的任何进程都可以访问该文件映射对象,前提是用户具有必要的访问权限。

但对于互斥体或事件 - 不需要启用SeCreateGlobalPrivilege


您也可以说,但是zoom是管理员帐户并且Administrator有权访问\Sessions\<N>\BaseNamedObjects- 那么为什么这不起作用?因为使用LOGON32_LOGON_INTERACTIVEUAC系统分配给zoom过滤的令牌。Administrator组 ( S-1-5-32-544) 存在于令牌中,但仅具有SE_GROUP_USE_FOR_DENY_ONLY属性 - 因此它会忽略 SID 允许访问的 ACE。并zoom有另一个LogonSessionId_0_XXXSID - 作为结果和ERROR_ACCESS_DENIED

LOGON32_LOGON_BATCH如@Harry Johnston所述 - 如果我们改为使用LOGON32_LOGON_INTERACTIVE- 我们获得了提升的令牌 - 这里Administrator组将具有SE_GROUP_ENABLED属性 - 启用对允许访问的 ACE 的访问检查

或者我如何提供 -Global\在名称之前使用前缀 - 将对象放置到具有完全访问权限的\BaseNamedObjects位置Everyone

我理解传递 NULL 作为第一个参数意味着CreateMutex将使用“默认”安全属性。在这种情况下,它将是与线程关联的安全参数,即与模拟用户关联的安全参数。

第一个参数 - 允许SECURITY_ATTRIBUTES您覆盖新对象的默认安全描述符的指针。这是控制谁可以访问它。但这不会让您或多或少地访问您尝试放置对象的目录 - 您必须授予DIRECTORY_CREATE_OBJECT访问权限,我们不能通过以下方式影响它SECURITY_ATTRIBUTES- 这会影响新对象,但不会影响现有目录

最后是NT 命名空间的一些可视化 在此输入图像描述