模拟后 CreateMutex 失败

CreateMutex fails after impersonation

这是我尝试模拟用户然后创建互斥体的代码。互斥锁没有被创建。我收到 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);
}

我发现了几个类似的主题,但它们都在讨论从两个不同的用户上下文创建同名互斥体,即在模拟之前已经创建了一个互斥体 "MUTEX_1",并尝试调用 CreateMutex由于缺乏权限,来自模拟用户的相同名称失败。

这里不是这种情况,因为我很确定在此代码之前没有创建同名互斥锁(或根本没有任何互斥锁)。

我想我应该将非空值传递给 CreateMutex,但具体是什么?

我在 Windows 安全方面不是很好。我知道将 NULL 作为 CreateMutex 的第一个参数传递意味着将使用 'default' 安全属性。在这种情况下,它将是与线程关联的安全参数,即模拟用户。

我的假设是否正确?

首先你需要了解NT Namespaces and use WinObj工具。

这就像内存中带有文件夹的小型文件系统,其中有不同的 "files"(此处 "files" 表示不同的对象类型 - EventMutant(互斥锁), Section, Device, ...)。每次创建命名对象时,它都会放置在 NT Namespaces 中的某个文件夹中。此处的文件夹(如 NTFS 中的文件夹)具有安全描述符。结果不是每个人都可以在任何文件夹下创建对象。

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

i (John) 尝试在 %USERPROFILE%\Documents 下创建文件 "mutex_good",这没问题。因为这是我的个人文件夹,我有写入权限。

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

zoom 无法创建文件。为什么 ?只是他无权这样做。只有 JohnAdministartorsSYSTEM 具有对 c:\Users\John 的写入权限,但对 zoom.

没有写入权限

现在让 return 变为 NT Namespaces。当我们调用 CreateMutexA( NULL, FALSE, "mutex_797" ); 时,"mutex_797" 会放在哪里?

如果您在系统 session 0 中不是 appcontainer 而不是 运行 - 您在某些用户 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

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

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

有关此内容的更多信息,请阅读 Kernel object namespaces

当然我们必须了解How AccessCheck Works

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

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

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

也可以在 DirectoryObject DesiredAccess Flags

阅读更多相关信息

我们需要DIRECTORY_CREATE_OBJECT访问权限(对目录对象的名称创建访问权限)以在目录

中创建互斥(或事件或任何对象)

现在了解为什么您可以在 \Sessions\<N>\BaseNamedObjects 中创建互斥锁但 zoom 不能 - 需要为此文件夹查找 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

谁有 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

对于\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

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

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

for \BaseNamedObjects (global namespace) 存在一个例外:

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.

但对于 Mutex 或事件 - 不需要启用 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_XXX SID - 作为结果和 ERROR_ACCESS_DENIED

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

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

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.

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

最后是 NT Namespace 的可视化