模拟后 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" 表示不同的对象类型 - Event
、Mutant
(互斥锁), Section
, Device
, ...)。每次创建命名对象时,它都会放置在 NT Namespaces 中的某个文件夹中。此处的文件夹(如 NTFS 中的文件夹)具有安全描述符。结果不是每个人都可以在任何文件夹下创建对象。
转述一下你在文件系统语言上做的事情(也许会更清楚):
i (John
) 尝试在 %USERPROFILE%\Documents
下创建文件 "mutex_good",这没问题。因为这是我的个人文件夹,我有写入权限。
然后我登录(模拟)为 zoom
并尝试在 %USERPROFILE%\Documents
下再次创建文件 "mutex_797"(%USERPROFILE%
在这两种情况下都扩展到相同的路径,比如 c:\Users\John
模拟不影响这个)
和 zoom
无法创建文件。为什么 ?只是他无权这样做。只有 John
、Administartors
、SYSTEM
具有对 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-1
、SYSTEM
、Administrators
、当前登录会话用户 (LogonSessionId_0_294807
)、当前用户 (John
) - 以及所有。 zoom
没有此权限。
例如 Everyone
有 (3) - DIRECTORY_QUERY|DIRECTORY_TRAVERSE
- Name lookup
和 Query
但没有 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 - 所有需要的访问权限。希望 zoom
是 Everyone
的成员?下一个代码我肯定会工作
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_INTERACTIVE
和 UAC
系统分配给 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 的可视化
这是我尝试模拟用户然后创建互斥体的代码。互斥锁没有被创建。我收到 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" 表示不同的对象类型 - Event
、Mutant
(互斥锁), Section
, Device
, ...)。每次创建命名对象时,它都会放置在 NT Namespaces 中的某个文件夹中。此处的文件夹(如 NTFS 中的文件夹)具有安全描述符。结果不是每个人都可以在任何文件夹下创建对象。
转述一下你在文件系统语言上做的事情(也许会更清楚):
i (John
) 尝试在 %USERPROFILE%\Documents
下创建文件 "mutex_good",这没问题。因为这是我的个人文件夹,我有写入权限。
然后我登录(模拟)为 zoom
并尝试在 %USERPROFILE%\Documents
下再次创建文件 "mutex_797"(%USERPROFILE%
在这两种情况下都扩展到相同的路径,比如 c:\Users\John
模拟不影响这个)
和 zoom
无法创建文件。为什么 ?只是他无权这样做。只有 John
、Administartors
、SYSTEM
具有对 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-1
、SYSTEM
、Administrators
、当前登录会话用户 (LogonSessionId_0_294807
)、当前用户 (John
) - 以及所有。 zoom
没有此权限。
例如 Everyone
有 (3) - DIRECTORY_QUERY|DIRECTORY_TRAVERSE
- Name lookup
和 Query
但没有 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 - 所有需要的访问权限。希望 zoom
是 Everyone
的成员?下一个代码我肯定会工作
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_INTERACTIVE
和 UAC
系统分配给 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 的可视化