如何检查TRUSTEE是否是我

时间:2017-11-20 17:05:01

标签: windows security winapi

我使用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 DELETE
      • 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 DELETE
      • 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 - 因为我是业主,{{3 }})。

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

在这种情况下,碰巧有三个受托人

  • S-1-5-21-6198258843-697258998-2146844275-1109 (使用我)
  • S-1-5-18 (用户LocalSystem - 不是我)
  • S-1-5-5-0-20117843 (group LoginSession - me)

受托人作为which means i implicitly have WRITE_DACL对象呈现给我们(注意,并非所有受试者都有SID)。我从经验中知道我其中两位受托人;但不是第三个。

是否有一项功能可用于将" me" TRUSTEE 进行比较?

Boolean DoIMatchThisTrustee(TRUSTEE trustee)
{

}

为什么我这样做?

没理由。我已经在自己的流程中删除了PROCESS_VM_READPROCESS_VM_WRITEPROCESS_VM_OPERATION

3 个答案:

答案 0 :(得分:1)

你真的希望检查自由访问控制列表(DACL),这是" me" - 因此启用了您的流程令牌成员。

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

使用GetSecurityInfo不是我认为的最佳选择,在这里更好地使用GetKernelObjectSecurity。但是你可以检查和受托人是否愿意("注意,并非所有人都有SID" - 这是一般情况,但是如果 DACL 你将只获得{{1托管人)。代码可以是下一个:

TRUSTEE_IS_SID

答案 1 :(得分: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"和#34; BUILTIN \管理员"这些权利。

登录会话是否是"你"是值得商榷但你不能比较完整的SID来找出,只有SECURITY_NT_AUTHORITY + SECURITY_LOGON_IDS_RID parts

答案 2 :(得分:0)

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