The SECURITY_ATTRIBUTES struct and CreateNamedPipe()

The SECURITY_ATTRIBUTES struct and CreateNamedPipe()

本文关键字:CreateNamedPipe and struct SECURITY ATTRIBUTES The      更新时间:2023-10-16

我的方案如下:使用 CreateNamedPipe() 创建命名管道对象的进程具有管理员权限,但使用 CreateFile() "连接"到该对象的客户端进程没有管理员权限。 将NULL作为最后一个参数传递给CreateNamedPipe()似乎默认为仅限管理员的访问权限。

作为一个黑客,我尝试在管道相关代码的持续时间内做一个服务器端ImpersonateLoggedOnUser()/RevertToSelf()方法,但它失败了。在我看来,这里最好的办法是实际上为 CreateNamedPipe() 的最后一个参数设置一个适当的SECURITY_ATTRIBUTES结构,但我很难弄清楚如何做到这一点。

MSDN 示例有一个与注册表项操作相关的示例,但我缺乏使其适应我的目的的专业知识。

这是我尝试过的:

if (!AllocateAndInitializeSid(&SIDAuthWorld, 1,
    SECURITY_WORLD_RID,
    0, 0, 0, 0, 0, 0, 0,
    &pEveryoneSID))
{
    _tprintf(_T("AllocateAndInitializeSid Error %un"), GetLastError());
    ret_val = 0;
    goto Cleanup;
}
// Initialize an EXPLICIT_ACCESS structure for an ACE.
// The ACE will allow Everyone read access to the key.
ZeroMemory(&ea, 2 * sizeof(EXPLICIT_ACCESS));
ea[0].grfAccessPermissions = STANDARD_RIGHTS_ALL;
ea[0].grfAccessMode = SET_ACCESS;
ea[0].grfInheritance = NO_INHERITANCE;
ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
ea[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
ea[0].Trustee.ptstrName = (LPTSTR)pEveryoneSID;
// there's another ACE for administrators in between, but is of no relevance here
dwRes = SetEntriesInAcl(2, ea, NULL, &pACL);
// Initialize a security descriptor.  
pSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR,
    SECURITY_DESCRIPTOR_MIN_LENGTH);
if (NULL == pSD)
{
    _tprintf(_T("LocalAlloc Error %un"), GetLastError());
    ret_val = 0;
    goto Cleanup;
}
if (!InitializeSecurityDescriptor(pSD,
    SECURITY_DESCRIPTOR_REVISION))
{
    _tprintf(_T("InitializeSecurityDescriptor Error %un"),
        GetLastError());
    ret_val = 0;
    goto Cleanup;
}
// Add the ACL to the security descriptor. 
if (!SetSecurityDescriptorDacl(pSD,
    TRUE,     // bDaclPresent flag   
    pACL,
    FALSE))   // not a default DACL 
{
    _tprintf(_T("SetSecurityDescriptorDacl Error %un"),
        GetLastError());
    ret_val = 0;
    goto Cleanup;
}
    // Initialize a security attributes structure.
*sa = new SECURITY_ATTRIBUTES;
(*sa)->nLength = sizeof(SECURITY_ATTRIBUTES);
(*sa)->lpSecurityDescriptor = pSD;
(*sa)->bInheritHandle = FALSE;

结果是客户端在CreateFile()上收到错误0x5(访问被拒绝)。这是怎么回事?

可以将描述符的 DACL 设置为 NULL,以允许任何人访问管道:

pSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
if (!pSD)
{
    ...
}
if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION))
{
    ...
}
if (!SetSecurityDescriptorDacl(pSD, TRUE, NULL, FALSE))
{
    ...
}
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = pSD;
sa.bInheritHandle = FALSE;
... = CreateNamedPipe(..., &sa);

这是你的问题:

ea[0].grfAccessPermissions = STANDARD_RIGHTS_ALL;

STANDARD_RIGHTS_ALL不是所有权限,只有所有标准权限,即删除、读取控制、同步、写入 DAC 和写入所有者。 特别是,它不授予客户端读取和/或将数据写入管道所需的FILE_READ_DATAFILE_WRITE_DATA

我推荐

ea[0].grfAccessPermissions = GENERIC_READ | FILE_WRITE_DATA;

并让客户端在打开管道时请求相同的访问权限。 (显然,如果这是出站管道,则可以省略FILE_WRITE_DATA,尽管在这种情况下,默认权限应该没问题。

行 SetEntriesInAcl(2, ea, NULL 和 pACL)

中的错误; 当需要 SetEntriesInAcl(1, ea, NULL 和 pACL) 时; - 你真的初始化并且只使用 1 个条目。 而不是检查 SetEntriesInAcl 返回的结果。下一个代码将正常工作:

        EXPLICIT_ACCESS ea = {
            STANDARD_RIGHTS_ALL,SET_ACCESS, NO_INHERITANCE, { 0, NO_MULTIPLE_TRUSTEE, TRUSTEE_IS_SID, TRUSTEE_IS_WELL_KNOWN_GROUP, (LPTSTR)pEveryoneSID }
        };
        PACL pACL;
        if (SetEntriesInAcl(1, &ea, NULL, &pACL) == ERROR_SUCCESS)
        {
        }

此处也可以被完整性级别拒绝访问。 需要检查操作系统版本,如果 Vista+ 在安全描述符中设置 LowLabel。 并且可以使用 0 DACL。(默认情况下,系统假设 MediumLabelSid 如果未显式设置,则导致 LowIntegrity 客户端无法打开管道,但对于通常不是管理员客户端的解决方案,由 @Remy Lebeau 就足够了)

PSECURITY_DESCRIPTOR pSecurityDescriptor = (PSECURITY_DESCRIPTOR)alloca(SECURITY_DESCRIPTOR_MIN_LENGTH);
BOOL fOk = FALSE;
if (
    InitializeSecurityDescriptor(pSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION) 
    && 
    SetSecurityDescriptorDacl(pSecurityDescriptor, TRUE, 0, 0)
    )
{
    RTL_OSVERSIONINFOW rov = { sizeof (rov)};
    if (0 <= RtlGetVersion(&rov))
    {
        if (rov.dwMajorVersion < 6)
        {
            fOk = TRUE;
        }
        else
        {
            PSID LowLabelSid = (PSID)alloca(64);
            ULONG cbSid = 64;
            if (CreateWellKnownSid(::WinLowLabelSid, 0, LowLabelSid, &cbSid))
            {
                ::PACL LowLabelAcl = (::PACL)alloca(64+cbSid);
                InitializeAcl(LowLabelAcl, 64+cbSid, ACL_REVISION);
                if (AddMandatoryAce(LowLabelAcl, ACL_REVISION, 0, SYSTEM_MANDATORY_LABEL_NO_WRITE_UP, LowLabelSid))
                {
                    fOk = SetSecurityDescriptorSacl(pSecurityDescriptor, TRUE, LowLabelAcl, FALSE);
                }
            }
        }
    }
}