主客体
在操作系统中,当我们提到安全的时候,意味着有一些资源需要被保护。
主体
每个进程都有一个基本令牌 (Primary Token),可以被进程中的每个线程所共享。而有些线程比较特殊,它们正在模拟(Impersonating)某个客户端的身份,因此拥有一个模拟令牌(Impersonation Token),对于这些线程来说,有效令牌是模拟令牌,而其他线程的有效令牌则是其所属进程的基本令牌。当主体尝试去访问客体时,操作系统会执行访问权限检查(Access Check),具体来说,是用主体的有效令牌与客体的安全描述符进行比对,从而确定该次访问是否合法。
为了提高效率,访问权限检查(Access Check)提供了一种缓存机制,即只有当一个对象被一个进程创建或者打开时,才会进行访问权限检查,访问权限检查的结果会被缓存到进程的句柄表(Handle Table)中,该进程对该对象的后续操作只需要查询句柄表中内容即可确定访问的合法性,而不必每次都执行开销更大的访问权限检查(Access Check)。
客体
在Windows操作系统中,这些被保护的资源大多以对象(Object)的形式存在,对象是对资源的一种抽象。每个对象都可以拥有自己的安全描述符(Security Descriptor),用来描述它能够被谁、以何种方式而访问。
继承
因为对象和进程都有各自的继承层次,所以对象的安全描述符和进程的令牌从逻辑上讲也是可以继承的,比如文件系统中的文件可以继承其所在目录的安全描述符,子进程可以继承父进程的令牌,这种继承机制使让对象和进程拥有了缺省的安全属性,因此,在一个系统中的安全描述符和令牌的实例数目非常有限,大多数情况下是从父辈们继承过来的缺省值。
访问检查
访问权限检查包含了多个维度上的检查:
DACL检查
Access Control Lists - Win32 apps | Microsoft Docs
DACL(自主访问控制表,Discretionary Access Control List)检查是最基本的访问权限检查。
在安全描述符中存在着一个DACL表(见安全描述符图解),里面描述了拥有何种身份的主体申请的何种访问权限会被允许或者拒绝。DACL表中的每个表项拥有如下的结构:
DACL里的每一项称作ACE(Access Control Entry),ACE结构是:
AceType可以是:
#define ACCESS_ALLOWED_ACE_TYPE (0x0)
#define ACCESS_DENIED_ACE_TYPE (0x1)
Mask是一个代表相关权限集合的位图
主体的身份使用Sid(Security Identifier)来表示,这是一个变长的数据结构:
+0x000 Revision : UChar
+0x001 SubAuthorityCount : UChar
+0x002 IdentifierAuthority : _SID_IDENTIFIER_AUTHORITY
+0x008 SubAuthority : [1] Uint4B
Sid是Windows安全系统中一个基本类型,可以用来唯一标识多种不同种类的实体,比如标识用户身份与组身份,标识完整性级别、可信赖级别,AppContainer中的Capability等等。
DACL检查过程是这样的,如果对象的没有DACL,代表着这个对象不受任何保护,即可以被任何令牌代表的主体访问;如果对象拥有一个DACL,但是Dacl里的ACE成员为空,代表该对象没有显式地赋予任何主体任何访问权限,即不允许被访问;如果Dacl成员非空,就按照表中的顺序逐一与当前主体的身份Sid进行比对,直到该主体所请求的权限被全部显式允许,或者某一请求的权限被显式地拒绝,检查结束;如果直到Dacl表检查结束,主体申请的权限仍未被全部显式允许,那么仍然代表拒绝。
根据以上规则可知,DACL中各个表项的顺序对访问权限检查的结果至关重要,比如说有一条有关某主体的显式拒绝的表项位于表的最后,如果位于其之前的表项已经显式允许了这一主体申请的权限,那么这条显式拒绝的表项将起不到任何作用。基于此种原因,如果通过Windows右键安全选项菜单添加的DACL表项,显式拒绝的表项永远被置于显式允许表项前面,以保证其有效性。直接通过API添加则不受此种限制。
SACL(system access control list)由管理员使用,尝试记录对安全对象的访问。每个ACE记录一个信任主体进行的访问类型,这个访问产生一个security event log日志。
特权以及超级特权检查
所谓特权,是指那些不与某一具体对象相关的、影响整个系统的访问权限。而超级特权是这样的一些特权,你一旦拥有其中的一项超级特权,就拥有了取得所有其他特权和权限的潜质,比如SeDebugPrivilege,在一般情况下,一旦拥有该特权,就可以任意读写目标进程的内存,而不仅仅局限于打开该进程获得句柄时得到的那些权限及特权。
IL(Integrity Level)和强制策略(Mandatory Policy)检查
Windows Integrity Mechanism Design | Microsoft Docs
完整性级别(IL)机制是Windows Vista引入的重要的安全机制,建立在其基础上的沙盒机制十分简单又异常强大。
受限令牌(Restricted Token)检查
通过创建受限令牌,可以获得一个普通令牌所有拥有的权限集合的一个子集,用来进行一些低权限操作,降低安全风险。
AppContainer`s Capabilities检查
LowBox令牌以及AppContainer’s Capabilities组身份是从Windows 8开始引入的安全机制,它提供了另一种更加复杂的沙盒机制。Capabilities与Android系统中对于App权限限制非常类似。
可信级别检查
完整性级别检查是一种粗粒度的、相对稳定的访问权限控制手段;伴随着Windows的不断进化,对于签名机制的依赖越来越明显,签名代表了一种可信赖程度。笔者认为,Windows正在逐渐建立一套完善的基于可信赖级别的权限检查机制,受保护进程(Protected Process)就是这是这套机制中一部分。
欢迎关注我的微博:大雄_RE。专注软件逆向,分享最新的好文章、好工具,追踪行业大佬的研究成果。