c++ - 模拟后CreateMutex失败

标签 c++ windows mutex 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的第一个参数传递意味着将使用“默认”安全属性。在这种情况下,它将是与线程关联的安全参数,即与模拟用户关联的安全参数。

我的假设正确吗?

最佳答案

首先,您需要了解NT Namespaces并使用WinObj工具。

这就像带有文件夹和不同"file"的内存中的小文件系统(此处"file"下的意思是不同的对象类型-EventMutant(mutex),SectionDevice,...)。每次创建命名对象时,都会将其放置在NT Namespaces中的某个文件夹中。此处的文件夹(如NTFS中的文件夹)具有安全描述符。结果并不是每个人都可以在任何文件夹下创建对象。

解释您对文件系统语言所做的操作(也许会更清楚):

我(John)尝试在%USERPROFILE%\Documents下创建文件“mutex_good”,这没关系。因为这是我的个人文件夹,并且我对此具有写权限。

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

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

现在让我们返回NT Namespaces。当我们调用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

所以说,如果你调用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访问权限(对目录对象的名称创建访问权限)才能在Directory中创建互斥锁(或事件或任何对象)

现在了解为什么您可以在\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,当前登录 session 用户(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");\BaseNamedObjects(全局 namespace )存在一个异常(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.



但对于Mutex或说事件-不需要启用SeCreateGlobalPrivilege

您也可以说,但是zoom是管理员帐户,而Administrator可以访问\Sessions\<N>\BaseNamedObjects-为什么这不起作用?因为使用LOGON32_LOGON_INTERACTIVEUAC系统将分配给zoom过滤的 token 。 Administrator组(S-1-5-32-544)存在于 token 中,但仅具有 SE_GROUP_USE_FOR_DENY_ONLY 属性的-结果是它忽略了SID允许访问的ACE。
zoom具有另一个LogonSessionId_0_XXX SID-结果和ERROR_ACCESS_DENIED
如@Harry Johnston所述-如果我们将使用LOGON32_LOGON_BATCH代替LOGON32_LOGON_INTERACTIVE-我们获得了提升的 token -此处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的可视化
enter image description here

关于c++ - 模拟后CreateMutex失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41369232/

相关文章:

c++ - 如何在不公开 C API 的情况下包装 C API?

c++ - 如果未捕获异常会发生什么?

c++ - 如何将具有字符串数据成员的类的对象传递给C++中的另一个类

windows - 代理未实现该功能的应用程序

c# - 设置多张壁纸?

windows - 如何让 Windows 控制台\命令提示符显示颜色?

c++ - boost 互斥量抛出(奇数?)异常

c++ - 表达优先?这个结果是如何发生的?

mutex - 条件变量是如何实现的?

c - 如何使用pthread_mutex_trylock?