阅读本文,你可以初步了解 Windows 上的 UAC 用户账户控制机制。本文不会涉及到 UAC 的底层实现原理和安全边界问题。
本文内容
用户账户
在 Windows 中有多种不同的账户:
- SYSTEM
- Administrators 用户组
- Administrator
- 管理员账户
- Users 用户组
- 标准账户
我们需要将这些账户列举出来是因为在解释 UAC 账户控制的时候,会与此相关。
SYSTEM 在系统中拥有最高权限。
默认我们安装 Windows 时会创建一个管理员账户,这也是 Windows 系统推荐我们使用的管理员账户,其权限等级比 SYSTEM 低。
Administrator 的权限级别和我们用户创建的管理员账户的权限级别是一样的,但是访问令牌(Access Token)的管理方式不一样,所以这里我们需要分开说。
标准账户是我推荐大家使用的首选账户种类,因为在普通使用场景下,这个是最安全的。
Administrator 账户目前的主要作用就是准备 OOBE 开箱体验,不适合日常使用,因为很不安全。关于 OOBE 开箱体验与审核模式,可以阅读我的另一篇博客:
UAC 通知等级
Windows Vista 开始引入了 UAC,不过在 Windows Vista 上只有两种 UAC 设置——开启和关闭。如果开启,那么应用试图安装软件或更改计算机、或者更改了 Windows 设置时将弹出 UAC 提示框;如果关闭,那么 UAC 就此关闭。Windows Vista 的 UAC 一直饱受诟病就是因为这种情况下的 UAC 提示是非常频繁的(而且以前的程序迁移到不需要管理员权限需要时间)。
在 Windows 7 上,在开启和关闭中间新引入了两个 UAC 级别,都是在更改 Windows 设置时不通知(实际上就是加了一些 UAC 提权的白名单)。只是一个会进入“黑屏”状态,另一个不会进入此状态。从表现上看这两个只是黑屏与不黑屏,但从安全性上讲黑屏的安全性会高很多。UAC 通知时进入的黑屏状态在 Windows 中称之为“安全桌面”,这时整个桌面进入了 SYSTEM 账户,原用户账户下的所有程序都无法得知此时 UAC 弹窗的情况,也无法通过模拟用户操作来跳过这个 UAC 框。而不黑屏时,不会切换到新的桌面环境,原有程序依然可以获得此 UAC 弹窗的一些信息,这很不安全。
但是!无论是 Windows Vista 还是 Windows 7,一旦你将 UAC 设置拖到最底,那么此时 UAC 将彻底关闭。如果你是管理员账户,那么运行的程序都将以管理员权限运行。
从 Windows 8 开始到现在的 Windows 10,虽然依然是上面四个设置,但拖到最底的“从不通知”时,UAC 依然是开启的状态。也就是说,用户正常启动的进程依然是标准权限,要获得管理员权限提升依然需要重启整个进程。这个安全性限制是很重要的。
特别说明!实际上 UAC 拖到最顶部,也就是所有 UAC 通知都显示 UAC 提示窗口才是真的在利用 UAC 保护你的电脑。因为 Windows 7 开始新增的两个中间级别都是在部分情况下静默提权,而这两种级别因为可以静默提权,所以也可以很容易被程序绕过。微软认为绕过 UAC 弹窗不是漏洞,因为这是用户自己的选择——如果用户选择全部通知是不会绕过的,用户选择了默认值,于是才可以绕过。所以这里推荐大家使用 UAC 的最高档,也就是全部提权都通知,这可以让大多数绕过 UAC 的方法失效。
虽然说通知等级给了用户四个设置项,但实际上真正有用的只有两个而已,参见我的另一篇博客:Windows 的 UAC 设置中的通知等级实际上只有两个档而已 - 吕毅。
完整性级别(Integrity Level)
从 Windows Vista 开始,进程在创建的时候,可以得到一个访问令牌(Access Token),这个令牌有四个完整性级别:
- System(系统)
- High(高)
- Medium(中)
- Low(低)
System 令牌是对系统完全操作的令牌,对应 SYSTEM 用户拥有的最高权限,可以对 Windows 操作系统做任何事。通常一个服务进程会以 SYSTEM 用户启动,拿到 System 令牌。
High 对应 Administrators 组拥有的最高权限,也就是前面所说的 Administrator 用户和用户自己创建的管理员账户的权限级别。此权限级别用来管理计算机,可以修改其他用户,可以修改系统的设置,这些设置可能会造成安全问题(比如更改系统时间可能导致杀毒软件失效)。
Medium 对应 Users 组拥有的最高权限,也就是前面所说的用户自己创建的标准用户。此权限级别用来日常使用。Medium 权限在 Windows Vista(实际上是其内核 NT6)中相比于之前版本的 Windows 有一些权限的提升,不危及系统安全性的操作在 Medium 下即可以完成,不需要切换到 High 级别。Users 组的用户是没有 High 和 System 令牌的,程序在此用户账户下,无论如何也无法拿到 High 和 System 令牌的,因为这个用户没有这样的令牌;如果要权限提升,需要输入管理员账号密码,而这时拿到的是这个管理员账号的 High 和 System 令牌。
Low 并不对应者一个用户组,这是为了一些需要特殊保护的应用程序准备的。有些应用容易受到攻击,那么使用 Low 令牌启动这些应用程序,可以最大程度减少利用这些应用对系统造成攻击。比如 IE 浏览器的页面进程使用 Low 令牌运行,其对系统很难做出什么改动,甚至也影响不了当前用户的文件;当需要需系统计算机进行交互的时候,会与 IE 的 UI 进程(Medium 令牌)进行通信,请求协助完成。
当 UAC 是开启状态,无论是管理员账户还是标准账户,Windows 资源管理器进程(explorer.exe)都是以 Medium 令牌启动进程。由于子进程通常能够继承父进程的令牌完整性级别,所以这样的设定可以防止用户双击打开的程序得到过高的令牌,从而在用户不知情的情况下危及系统安全。
当程序需要以管理员权限运行(对应 High 级别的令牌)时,可以自己在 Manifest 里面声明,也可以自己使用 runas
谓词重启自己。而这个时候是会弹出 UAC 提示的,用户知情。
前面我们说过在 Administrators 组中,Administrator 账户和普通管理员账户要分开说。差别就在令牌的管理上。普通管理员账户下,正常启动进程使用的是继承自 explorer.exe 的 Medium 访问令牌,当进程需要提升权限时,会弹出 UAC 提示框来启动一个子进程以获得 High 令牌。而 Administrator 账户下,正常启动的进程也都获得了 High 令牌。
关于如何通过 Manifest 设置管理员权限运行,可以参考我的另一篇博客:
权限提升
在 Windows 系统中,不同权限的进程是隔离的(虽然不是完全隔离)。
如果你希望你的程序在执行某个操作的时候提升权限来执行,实际上你不能在你原来的进程上直接提升权限。你有很多种方法来提权,甚至绕过 UAC 来提权,但无论哪一种,你的进程实际上都是重启了,你是在新的提升的进程中执行了这个需要权限的操作。
对于管理员账户,如果启动一个普通进程,那么此进程在管理员账户下运行,获得的是 Medium 访问令牌。当此进程提升权限,将弹出 UAC 提示框,用户同意后继续使用此同一个管理员账户运行,但子进程将获得 High 访问令牌。
对于标准账户,如果启动一个普通进程,那么此进程在标准账户下运行,获得的是 Medium 访问令牌。当此进程提升权限,将弹出 UAC 提示框,用户输入管理员账号密码后,子进程将在输入的管理员账户下运行,获得此管理员的 High 访问令牌。标准账户没有 High 访问令牌,如果说绕过 UAC 来提权是为了获取 High 访问令牌,那么在标准账户下根本没有 High 访问令牌,所以你绕不过。
管理员账户的 UAC 弹窗是这样的,要求用户选“是”或者“否”:
而标准账户的 UAC 弹窗是这样的,要求输入管理员账号和密码:
以上两个弹窗都是蓝色的,代表发起此 UAC 请求的子进程其程序的证书是经过认证的。如果没有证书那么提示框是黄色的,如果证书过期,那么提示框是红色的。这可以帮助用户区分 UAC 弹窗做出决策(虽然实际上没什么用)。
以上在标准账户下用管理员账户打开子进程的例子可以看下图:
lvyi 是我安装系统时创建的管理员账号,但是我使用的是 walterlv 标准账号。正常是在 walterlv 账号下启动程序,但以管理员权限运行时,会要求输入 lvyi 账号的密码来提权,于是就会以 lvyi 的身份运行这个程序。这种情况下,那个管理员权限运行的程序会以为当前运行在 lvyi 这个账户下,程序员需要小心这里的坑,因为拿到的用户路径以及注册表不是你所期望的 walterlv 这个账号下的。
在上图中,你会发现当前账户下的任务管理器连管理员账户运行的程序图标都拿不到。