6.5.10. 访问控制

6.5.10.1. 访问控制的目的

  • 限制安全主体(用户、进程、服务等)对客体(文件目录、注册表键等)的访问权限,从而使系统在安全合法范围内使用。

  • 客体包括:
    • 文件、目录

    • 注册表键

    • 活动目录对象

    • 内核对象(事件、信号量、互斥体)

    • 服务

    • 进程、线程

    • 防火墙端口

    • 窗口工作站和桌面

6.5.10.2. Windows访问控制的本质

安全主体的访问令牌 <- 比较 -> 客体的安全描述 - 用户成功登录时,系统的本地安全授权(LSA)为其创建访问令牌。 - 用户启动程序创建进程时,线程获取该令牌的拷贝。 - 用户程序请求访问客体时,向系统提交该令牌。 - 系统使用该令牌与客体的安全描述进行比较来执行访问检查和控制。

6.5.10.3. 安全访问令牌

  • 用户帐号SID(User account SID)

  • 用户所属组的SID(Group 1-n SID)

  • 受限SID (Restricted SID 1-n)

  • 会话ID (Session ID)
    • 所属会话的ID

  • 特权列表(Privilege1-n)
    • 与该令牌关联的权限和特权列表

  • 源(Token Source)
    • 创建此令牌的实体,比如会话管理器、网络文件服务器,或者RPC服务器等。

  • 完整性级别(Integrity Level)
    • Windows Vista开始引入,用以限制读取/写入对象的范围。

  • 默认自主访问控制列表(Default DACL)
    • 用以创建对象时为其设置的初始DACL

  • 令牌类型(Type)
    • 主令牌(primary)还是模拟( impersonation )令牌。

  • 模拟级别(Impersonation Level)

  • 令牌标记(Flags)和强制策略(Mandatory Policy)
    • 决定UAC和UIPI机制的行为表现。

  • 默认主安全组(Default primary group)

6.5.10.4. 令牌类型

6.5.10.4.1. 主令牌(Primary Token)

  • 每个进程都有一个主令牌来描述与该进程相关的用户帐号的安全上下文。模拟令牌(Impersonation Token)

  • 服务进程在自己的帐号下运行,使用自己的主令牌,但当服务接受一个用户的访问请求时,它创建一个线程来完成这项工作并将用户的访问令牌与工作线程相关联。用户的访问令牌是一个模拟令牌,用来标识用户、用户的组和特权。

  • 当线程代表用户请求访问资源(比如文件、打印机、数据库等)时,在访问检查过程中使用该信息。在模拟结束后,线程重新使用主令牌并返回到服务自己的安全上下文里操作。

  • 服务器只能在发起模拟请求的线程内模拟用户

6.5.10.4.2. 模拟级别

  • 为了防止滥用模拟机制,Windows不允许服务器在没有得到用户同意的情况下执行模拟。用户进程在连接到服务器的时候可以指定一个安全服务质量,以此来限制服务器进程可以执行的模拟级别。
    • SecurityAnonymous级别:最为限制,服务器不能模仿或者识别出用户

    • SecurityIdentification级别:允许服务器得到用户的SID和特权 ,但不能模拟该用户

    • SecurityImpersonation级别:默认级别,允许服务器在本地系统上识别和模拟该用户

    • SecurityDelegation:最为随意,允许服务器在本地系统或远程系统上模拟该用户

6.5.10.4.3. 受限制的令牌(Restricted Token)

  • 出于安全原因,应用程序可创建一个受限的令牌并将它分配给子进程或模拟线程来为它们创建受限的安全上下文。

  • 受限令牌在主令牌或模仿令牌的基础上创建的,来源于令牌的拷贝,但可能进行如下修改:
    • 从该令牌的特权列表中删除一些特权

    • 该令牌中的SID被标记为仅仅拒绝(Deny-only)

    • 该令牌中的SID被标记为受限制的(Restricted)

  • 在进行对象访问检查的时候,系统要执行两次访问检查:一次使用令牌的“Enable SID”和“Deny SID”,另一个使用Restricted SID的列表。只有当这两个访问检查都允许请求的访问权限时才能允许访问。

  • 受限令牌的应用被过滤的管理员令牌(UAC权限提升之前)
    • 完整性级别被设置为中等

    • 除了Change Notify、Shutdown、Undock、Increase Working Set、Time Zone以外的其他特权都被去掉了

    • 给管理员以及类管理员的SID标记“Deny-only”,可以消除以下安全缺陷:比如某个文件拒绝管理员组用户的访问,但允许其他包含这个管理员用户的组的访问,这将会导致这个用户最终能够访问该文件

6.5.10.5. 账户权限和特权

  • 进程在运行过程中执行的许多操作是无法通过对象访问保护来授权控制的,因为这些操作并没有与一个特定的对象打交道。Windows使用特权(Privilege)和账户权限(Account Right),以使得管理员可以控制哪些账户能够执行与安全相关的操作。

  • 特权是指一个账户执行某个与系统相关的操作的权限,比如,关 闭计算机或者改变系统的时间。

  • 账户权限则把“执行某一特定登录类型(比如本地登录或交互式登录到一台计算机上)的能力”授予它所针对的账户,或拒绝分配给该账户。

6.5.10.5.1. 账户权限(Account Rights)

  • 账户权限并不是由安全引用监视器(SRM)强制实施的,也不存储在令牌中。

  • 当一个用户企图登录到系统中时,作为对登录请求的响应,LSA从LSA数据库中获取到已赋予该用户的账户权限,对登录类型(交互式登录、网络登录、批作业方式登录、服务方式登录、终端服务登录等)进行检查,如果该用户的账户没有“允许此种登录类型”的权限,或者具有“拒绝此种登录类型”的权限,则LSA拒绝该用户的登录请求

6.5.10.5.2. 特权(Privilege)

  • 与用户权限不同,不同的特权是由不同的组件来定义的,并且也是由这些组件来强制使用的。比如调试特权是由进程管理器来检查的,它使得一个进程在利用Windows API函数OpenProcess来打开另一个进程的句柄时可以绕过安全检查。

  • 与账户权限不同,特权是可以被允许和禁止的。想让一个特权检查能够成功地通过,该特权必须出现在当前特定的令牌中,而且它必须是允许(Enabled)的。

6.5.10.5.3. 超级特权

  • 调试程序(SeDebugPrivilege)
    • 具有此特权的用户可以打开系统中的任何一个进程,而不必考虑该进程上的安全描述符。例如,用户可以实现这样一个程序,它打开LSASS进程,将可执行代码拷贝到它的地址空间中,然后通过CreateRemoteThread注入一个线程,让它在一个更加有特权的安全环境下执行这些注入的代码。

  • 接管所有权(SeTakeOwnershipPrivilege)
    • 特权持有者能够接管任何一个被保护对象的所有权。做法是,将他自己的SID写到该对象的安全描述符的所有者域中。由于所有者总是被授予“读取和修改该安全描述符的DACL”许可,所以,具有此特权的进程可以修改此DACL,以授予他自己对于该对象的完全访问权。

  • 恢复文件和目录(SeRestorePrivilege)
    • 具有此特权的用户能够用自己的文件来替代系统中的任何文件。

  • 加载和卸载设备驱动程序(SeLoadDriverPrivilege)
    • 一个恶意用户可以使用这种特权将一个设备驱动程序加载到系统中。设备驱动程序被认为是操作系统的可信任部分,操作系统会在SYSTEM账户凭证下运行设备驱动程序中的代码。

  • 创建一个令牌对象(SeCreateTokenPrivilege)
    • 可以生成一些代表任意用户账户的令牌,而且其中的用户账户可以有任意的组成员关系和特权。

  • 作为操作系统的一部分来执行(SeTcbPrivilege)
    • 具有此特权的恶意用户可以建立一个可信的Lsass连接,然后可以使用他的用户名和口令来创建一个新的登录会话(通过LsaLogonUser这个创建新登录会话的函数),而新的登录会话在其令牌中包含多个特权组或用户的SID

6.5.10.6. 完整性级别

强制完整性控制( MIC ,Mandatory Integrity Control)

  • Windows Vista之后开始引入,将进程分为不同的完整性级别,从而保证低级别的进程无法影响高级别的进程。

  • 进程的完整性级别由令牌中的SID声明。

  • 系统首先进行完整性级别的检查,然后再进行DACL的检查。

6.5.10.6.1. 安全描述(Security Descriptor,SD)

  • 版本号(Revision Number)

  • 标志(Flags/Control)

  • 所有者的SID(Owner SID)

  • 所有者主要组的SID(Group SID),仅被POSIX使用

  • DACL(Discretionary Access Control List)
    • 自主访问控制列表:规定谁可以用什么方式访问对象。

  • SACL(System Access Control List)
    • 系统访问控制列表:规定哪些用户的哪些操作应该被记录到安全审计日志中。

6.5.10.6.2. 访问控制项(ACE)

  • ACE大小(Size)

  • ACE标志(Flags)

  • ACE类型(Type)
    • DACL包含ACE的类型:访问允许、访问拒绝、允许的-对象、拒绝的-对象等。

    • SACL包含ACE的类型:系统审计、系统审计-对象

  • 用户SID

6.5.10.6.3. DACL访问权限的确定

确定对于对象期望的访问是否允许(AccessCheck函数)

  • 如果该对象没有DACL(即一个空DACL),则该对象没有设置保护,所以安全系统授予调用者期望的访问权限。

  • 如果调用者具有“接管-所有权(take-ownership)”的特权,则安全系统授予“写-所有者(write-owner)”访问权,然后检查DACL。

  • 如果调用者是该对象的所有者,则授予“读-控制(read-control)”和“写DACL”访问权。

  • 从前往后检查DACL中的每一个ACE。对于每个ACE,如果下面的条件之一被满足,则它被处理:
    • “访问-拒绝”的ACE,且ACE中的SID是一个可允许的SID,或者是一个仅仅拒绝的SID;

    • “访问-允许”的ACE,且ACE中的SID不是仅仅拒绝类型的可允许SID;

    • 在第二遍检查受限制的SID过程中,ACE的SID与一个受限制的SID合;

    • ACE没有标记为仅仅继承;

  • 如果是一个“访问-允许”的ACE,则只要调用者请求了,就将该ACE的访问掩码中的权限授予给它;如果调用者请求的所有访问权限都已经被授予了,则访问检查成功。如果是一个“访问-拒绝”的ACE,只要调用者请求的任何一个访问权限属于拒绝访问的权限,则调用者对该对象的访问请求被拒绝。

  • 如果已经到达DACL的末尾,而且调用者请求的有些访问权限仍然末被授予,则访问被拒绝。

  • 如果所有的访问权限都被授予了,但是调用者的访问令牌至少有一个受限制的SID,则系统重新扫描该DACL的ACE,以寻找这样的ACE:其访问掩码与用户所请求的访问权限相匹配,并且该ACE的SID与调用者的任何一个受限制的SID相匹配。只有对DACL的这两遍扫描都授予用户所请求的权限,才允许该用户访问此对象

6.5.10.7. 用户权限控制

6.5.10.7.1. RunAs服务(辅助登录服务)

  • 使得管理员平时使用标准的用户账户登录,然后在必要的时候调用具有更高权限的管理员控制台来执行管理任务。

  • 在管理工具(Administrative Tool)应用组件上右击,然后从弹出的菜单中选择“运行为…” 。

  • 在CMD命令提示符中输入“runas”,并按回车键

6.5.10.7.2. 用户账户控制(UAC)

UAC,User Account Control

  • 在Windows Vista之后的系统中,需要管理员权限的操作标有盾牌图标,表示需要经过系统UAC的提升确认才能进行进一步的操作。

  • UAC其实就是一种特殊的“缩减特权”模式。

6.5.10.7.3. 用户界面权限隔离(UIPI)

UIPI, User Interface Privilege Isolation

  • UIPI是UAC机制的一部分,目的在于防止窗口消息攻击。

  • 通过结合完整性级别控制,UIPI具体所做的保护包括:
    • 低级别进程无法对高级别的窗口句柄做验证

    • 低级别进程无法向高级别进程的窗口发送消息(SendMessage或PostMessage等)

    • 低级别进程无法把线程注入到高级别进程

    • 低级别进程无法对高级别进程进行消息或日志挂钩

    • 低级别进程无法把DLL注入到高级别进程

    • 低级别的进程不可以读取高级别的内存地址空间