首页 文章

如何检查TRUSTEE是否是我

提问于
浏览
1

我正在使用GetSecurityInfo功能来获取我自己的进程的自由访问控制列表(DACL):

PACL oldAcl;
Pointer se;
GetSecurityInfo(GetCurrentProcess, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, 
      null, null, ref oldAcl, nil, ref se);

然后我可以使用GetExplicitEntriesFromAcl来破解ACL以获取其内部的访问控制条目(ACE)列表:

UInt32 nCount;
EXPLICIT_ACCESS[] list;
GetExplicitEntriesFromAcl(oldAcl, ref nCount, ref list);

我可以查看我的流程中的三个条目列表:

  • STACKOVERFLOW \ ian(S-1-5-21-6198258843-697258998-2146844275-1109)[SidTypeUser]

  • 授予访问权限

  • 0x00010000删除

  • 0x00020000 READ_CONTROL

  • 0x00040000 WRITE_DAC

  • 0x00080000 WRITE_OWNER

  • 0x00100000 SYNCHRONIZE

  • ......

  • 0x00000008 PROCESS_VM_OPERATION

  • 0x00000010 PROCESS_VM_READ

  • 0x00000020 PROCESS_VM_WRITE

  • NT AUTHORITY \ SYSTEM(S-1-5-18)[SidTypeWellKnownGroup]

  • 授予访问权限

  • 0x00010000删除

  • 0x00020000 READ_CONTROL

  • 0x00040000 WRITE_DAC

  • 0x00080000 WRITE_OWNER

  • 0x00100000 SYNCHRONIZE

  • ......

  • 0x00000008 PROCESS_VM_OPERATION

  • 0x00000010 PROCESS_VM_READ

  • 0x00000020 PROCESS_VM_WRITE

  • NT AUTHORITY \ LogonSessionId_0_20117843(S-1-5-5-0-20117843)[SidType_11]

  • 授予访问权限

  • 0x00020000 READ_CONTROL

  • 0x00100000 SYNCHRONIZE

  • 0x00000010 PROCESS_VM_READ

  • 0x00000400 PROCESS_QUERY_INFORMATION

  • 0x00001000 PROCESS_QUERY_LIMITED_INFORMATION

我现在想要通过并更新进程的DACL(当然我已经允许这样做,因为我有 WRITE_DACL - 因为我是所有者,which means i implicitly have WRITE_DACL) .

但我只想重写适用于"me"的访问控制条目 .

在这种情况下碰巧有三个 Trustees

  • S-1-5-21-6198258843-697258998-2146844275-1109(用户)

  • S-1-5-18(用户LocalSystem - 不是我)

  • S-1-5-5-0-20117843(组LoginSession - 我)

受托人作为TRUSTEE对象呈现给我们(注意,并非所有受试者都有SID) . 我从经验中知道我是两个受托人;但不是第三个 .

是否有一个函数可以用于比较"me"与 TRUSTEE

Boolean DoIMatchThisTrustee(TRUSTEE trustee)
{

}

为什么我这样做?

没理由 . 我正在自己的进程中删除 PROCESS_VM_READPROCESS_VM_WRITEPROCESS_VM_OPERATION .

3 回答

  • 0

    你真的想要检查Sids的自由访问控制列表(DACL),这是"me" - 所以启用了你的进程令牌成员 .

    要确定是否在令牌中启用了SID,我们可以使用 CheckTokenMembership 函数 .

    使用 GetSecurityInfo 不是我认为最好的选择,更好用 GetKernelObjectSecurity 这里 . 但是你可以检查和受托人是否愿意("note, not all of which have an SID" - 这是一般情况下,但如果DACL你只有 TRUSTEE_IS_SID 受托人) . 代码可以是下一个:

    void Test()
    {
        HANDLE hToken, hImpToken;
    
        if (OpenProcessToken(NtCurrentProcess(), TOKEN_QUERY|TOKEN_DUPLICATE, &hToken))
        {
            BOOL fOk = DuplicateToken(hToken, ::SecurityIdentification, &hImpToken);
    
            CloseHandle(hToken);
    
            if (fOk)
            {
                ULONG cb = 0, rcb = 256;
    
                static volatile UCHAR guz = 0;
                PVOID stack = alloca(guz);
                union {
                    PVOID buf;
                    PSECURITY_DESCRIPTOR pSD;
                };
    
                do 
                {
                    if (cb < rcb)
                    {
                        cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
                    }
    
                    if (GetKernelObjectSecurity(NtCurrentProcess(), DACL_SECURITY_INFORMATION, pSD, cb, &rcb))
                    {
                        BOOL bPresent, bDefault;
    
                        union {
                            PACL Acl;
                            PBYTE pb;
                            PACE_HEADER pah;
                            PACCESS_ALLOWED_ACE paaa;
                        };
    
                        if (GetSecurityDescriptorDacl(pSD, &bPresent, &Acl, &bDefault) && bPresent && Acl)
                        {
                            CheckSidsInAcl(Acl);
    
                            if (USHORT AceCount = Acl->AceCount)
                            {
                                Acl++;
    
                                do 
                                {
                                    if (pah->AceType == ACCESS_ALLOWED_ACE_TYPE)
                                    {
                                        BOOL IsMember;
                                        if (CheckTokenMembership(hImpToken, &paaa->SidStart, &IsMember))
                                        {
                                            PWSTR sz;
                                            if (ConvertSidToStringSid(&paaa->SidStart, &sz))
                                            {
                                                DbgPrint("%x %S\n", IsMember, sz);
                                                LocalFree(sz);
                                            }
                                        }
                                        else
                                        {
                                            GetLastError();
                                        }
                                    }
    
                                } while (pb += pah->AceSize, --AceCount);
                            }
                        }
                        break;
                    }
    
                } while (GetLastError() == ERROR_INSUFFICIENT_BUFFER);
    
                CloseHandle(hImpToken);
            }
        }
    }
    
  • 0

    我认为没有任何功能可以比较或规范化TRUSTEE .

    ACL中的ACE总是存储一个SID(据我所知),因此当您从ACL获取TRUSTEE时,可以安全地假设TRUSTEE将是TRUSTEE_IS_ * SID表单 .

    PSID GetSID(const TRUSTEE&t)
    {
        if (TRUSTEE_IS_SID == t.TrusteeForm) return (PSID) t.ptstrName;
        if (TRUSTEE_IS_OBJECTS_AND_SID == t.TrusteeForm) return ((OBJECTS_AND_SID*)t.ptstrName)->pSid;
        return NULL;
    }
    
    bool DoIMatchThisTrustee(TRUSTEE&t)
    {
      PSID tsid = GetSID(t);
      PSID mysid = GetMySid(); // From process/thread token or somewhere else
      return tsid && EqualSid(tsid, mysid);
    }
    

    如果您不想假设,则可以在字符串表单上使用 LookupAccountName 来获取SID .

    如果由于某种原因您不想查找任何字符串,您可以执行NT4样式并直接使用ACL . 调用 GetAce 枚举ACL并使用如下内容:

    PSID GetAllowedSID(const ACE_HEADER&ah)
    {
        switch(ah.AceType)
        {
        case ACCESS_ALLOWED_ACE_TYPE: return (PSID) &((ACCESS_ALLOWED_ACE*)&ah)->SidStart;
        case ACCESS_ALLOWED_CALLBACK_ACE_TYPE: return (PSID) &((ACCESS_ALLOWED_CALLBACK_ACE*)&ah)->SidStart;
        case ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE: return (PSID) &((ACCESS_ALLOWED_CALLBACK_OBJECT_ACE*)&ah)->SidStart;
        case ACCESS_ALLOWED_OBJECT_ACE_TYPE: return (PSID) &((ACCESS_ALLOWED_OBJECT_ACE*)&ah)->SidStart;
        default: return NULL;
        }
    }
    

    如果您这样做是为了提高安全性,您可能希望以相反的方式执行操作,并且只允许“NT AUTHORITY \ SYSTEM”和“BUILTIN \ Administrators”这些权限 .

    登录会话是否为"you"是有争议的,但您无法比较完整的SID以找出,只有SECURITY_NT_AUTHORITY SECURITY_LOGON_IDS_RID parts .

  • 1

    RbMm的评论提醒我,我已经知道了我脑中某处的答案: CheckTokenMembeship

    //Get the ACL on the process
    PACL oldAcl;
    Pointer se;
    
    GetSecurityInfo(GetCurrentProcess, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, 
          null, null, ref oldAcl, nil, ref se); //allocates memory into se, which we must LocalFree later
    //oldAcl is a pointer to inside the se blob
    
    
    //Crack open the ACL, to feast on the entries inside
    UInt32 nCount;
    EXPLICIT_ACCESS[] list;
    GetExplicitEntriesFromAcl(oldAcl, ref nCount, ref list); //allocates memory into list, which we must localFree later
    
    
    //the flags i want to remove me from having    
    DWORD removeFlags = PROCESS_VM_READ || PROCESS_VM_WRITE || PROCESS_VM_OPERATION;
    
    //Go through the list, looking for entries that are "me"
    for (EXPLICIT_ACCESS ea in list)
    {
       if (ea.Trustee.TrusteeForm != TRUSTEE_IS_SID) 
          continue;
    
       BOOL isMember;
       CheckTokenMembership(0, PSID(ea.Trustee.ptstrName), out isMember);
    
       if (!isMember)
          continue;
    
       //Remove the permissions
       ea.grfAccessPermissions = ea.grfAccessPermissions && (!removeFlags);
       aclUpdateNeeded = true;
    }
    
    
    //write the new DACL
    SetEntriesInAcl(nCount, list, null, out newAcl); //allocates a new acl
    SetSecurityInfo(GetCurrentProcess, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, 
          null, null, newAcl, null); //apply the new acl
    
    LocalFree(list); //free the memory allocated by GetExplicitEntriesFromAcl
    LocalFree(se); //free the memory allocated by GetSecurityInfo
    

相关问题