请注意,当元素的名称小于 4 个字节时,它与 VAR(元素值)存储在相同的结构中。否则,将有一个指向元素名称的指针。名称长度 <=4 对我们来说就足够了,所以我们不需要详细说明。
对象哈希表是一个很好的覆盖对象,因为:
为了可靠地执行覆盖,我们执行以下操作:
图 5 显示了围绕排序缓冲区地址(红线)的堆可视化。您可以看到排序缓冲区被大小相似的分配包围,这些分配都对应于对象哈希表。您还可以观察到 LFH 随机性,因为后续分配不一定在后续地址上,但这对我们的漏洞利用没有影响。
图 5:溢出缓冲区周围的堆可视化
如前所述,我们以这样一种方式设计了溢出,即不幸的 JScript 对象的一些哈希表指针将被指向我们控制的数据的指针覆盖。现在,我们最终在这些数据中添加了什么:我们精心设计了它,使其包含 5 个(假)JavaScript 变量:
溢出后损坏对象的状态如图 6 所示。
图 6:溢出后的对象状态。红色区域表示发生溢出的位置。底行中的每个框(标记为“...”的框除外)对应 8 个字节。为清楚起见,省略了“...”框中的数据
我们可以通过简单地访问正确索引处的损坏对象(我们称之为 index1)来访问变量 1,对于变量 2-5 也是如此。事实上,我们可以通过访问所有对象的 index1 并查看哪个对象的值现在为 1337 来检测我们损坏了哪个对象。
将变量 1 和变量 2 重叠的效果是,我们可以将变量 1 的类型(第一个 WORD)更改为 5(双精度)、8(字符串)或 0x400C(指针)。为此,我们读取变量 2、3 或 4,然后将读取的值写入变量 2。例如语句
损坏的对象index2 = 损坏的对象index4;
效果是变量 1 的类型将更改为字符串 (8),而变量 1 的所有其他字段将保持不变。
这种布局为我们提供了几个非常强大的利用原语:
使用这些漏洞利用原语,通常执行代码会非常简单,但由于我们正在利用 Windows 10,我们首先需要绕过控制流防护 (CFG)。
第 3 阶段:CFG 旁路
我们可能在这里使用了其他已知的绕过方法,但事实证明,有一些非常方便的绕过方法(一旦攻击者拥有读/写原语)特定于 jscript.dll。我们将利用以下事实:
具体来说,每个 NameTbl 对象(在 Jscript 中,所有 JavaScript 对象都从 NameTbl 继承)在偏移量 24 处保存一个指向 CSession 对象的指针。CSession 对象,在偏移量 80 处持有一个指向本机堆栈顶部附近的指针。
因此,通过任意读取,通过跟踪来自任何 JScript 对象的指针链,可以检索到本地堆栈的指针。然后,通过任意写入,可以绕过 CFG 覆盖返回地址。
第 4 阶段:将代码执行作为本地服务
有了所有的漏洞利用元素,我们现在可以继续执行代码了。我们按以下步骤进行:
我们使用的 ROP 链如下所示:
RET 的地址 //需要将堆栈对齐到 16 个字节
POP RCX地址;RET //将第一个参数加载到rcx中
要执行的命令地址
POP RDX地址;RET //将第二个参数加载到rdx
1
WinExec的地址
通过执行这个 ROP 链,我们使用我们指定的命令调用 WinExec。例如,如果我们运行命令“cmd”,我们将看到一个命令提示符正在生成,作为本地服务运行(相同的用户 WPAD 服务运行)。
不幸的是,从作为本地服务运行的子进程中,我们无法与网络通信,但我们可以做的是将我们的权限提升有效负载从内存中删除到本地服务可以从那里写入和执行它的磁盘位置。
阶段 5:权限提升
虽然本地服务帐户是服务帐户,但它没有管理权限。这意味着漏洞利用在系统上可以访问和修改的内容非常有限,特别是在利用后或系统重新启动后持续存在。虽然在 Windows 中总是可能存在未修复的权限提升,但我们不需要找到新的漏洞来提升我们的权限。相反,我们可以滥用内置功能从本地服务升级到系统帐户。让我们看一下 WPAD 的服务帐户已被授予的权限:
图 7:服务访问令牌的特权显示模拟特权
我们只有三个特权,但突出显示的特权 SeImpersonatePrivilege 很重要。此权限允许服务模拟本地系统上的其他用户。该服务具有模拟特权的原因是它接受来自本地系统上所有用户的请求,并且可能需要代表他们执行操作。但是,只要我们能够获得要模拟的帐户的访问令牌,我们就可以获得令牌用户帐户的完全访问权限,包括 SYSTEM ,这将为我们提供本地系统的管理员权限。
滥用模拟是 Windows 安全模型的一个已知问题(您可以通过搜索Token Kidnapping找到更多详细信息)。微软试图让特权用户更难获得访问令牌,但实际上不可能关闭所有可能的路线。例如,James 在 Windows 的 DCOM 实现中发现了一个漏洞,该漏洞允许任何用户访问 SYSTEM 访问令牌。虽然微软修复了直接权限提升漏洞,但他们没有,或者可能无法修复令牌绑架问题。我们可以滥用此功能来捕获 SYSTEM 令牌,冒充令牌,然后彻底破坏系统,例如安装特权服务。
有一个通过 DCOM ( RottenPotato )实现令牌绑架的现有实现,但是该实现是为与我们没有使用的 Metasploit 框架的getsystem命令一起使用而设计的。因此,我们在 C++ 中实现了我们自己的更简单的版本,它使用CreateProcessWithToken API直接生成带有 SYSTEM 令牌的任意进程。作为奖励,我们能够将其编译为 11KiB 大小的可执行文件,比 RottenPotato 小得多,这使得从 ROP 有效负载拖放到磁盘和运行变得更容易。
将它们捆绑在一起
当 WPAD 服务查询 PAC 文件时,我们提供利用 WPAD 服务并运行 WinExec 以删除并执行权限提升二进制文件的漏洞利用文件。然后这个二进制文件作为 SYSTEM 执行一个命令(在我们的例子中是硬编码的 'cmd')。
该漏洞在我们的实验中运行得非常可靠,但有趣的是,不需要 100% 可靠的漏洞 - 如果漏洞导致 WPAD 服务崩溃,当客户端从 WPAD 发出另一个请求时,将生成一个新实例服务,所以攻击者可以再试一次。UI 中不会显示 WPAD 服务已崩溃,但 Window Error Reporting 可能会发现崩溃并将其报告给 Microsoft,前提是用户没有禁用它。
事实上,我们的漏洞利用并没有优雅地清理,一旦它运行它的有效负载就会崩溃 WPAD 服务,所以如果我们在服务被利用后继续提供漏洞利用 PAC 文件,它只会再次被利用。您可以在图 7 中看到它的效果,这是在让漏洞利用服务器运行几分钟并在受害机器中发出大量 HTTP 请求后拍摄的。
图 7:我们是否让漏洞利用运行时间过长?
我们将很快在问题跟踪器中发布漏洞利用源代码。
执行不受信任的 JavaScript 代码是危险的,在非沙箱进程中执行它更危险。即使它是由相对紧凑的 JavaScript 引擎(例如 jscript.dll)完成的,也是如此。我们在其中发现了 7 个安全漏洞,并成功地展示了从本地网络(及其他网络)对安装了 Fall Creators Update 的完全修补(在撰写本文时)Windows 10 64 位的可靠代码执行。
既然已经修复了错误,这是否意味着我们已经完成并且可以回家了?不太可能。尽管我们花费了大量的时间、精力和计算能力来查找 jscript.dll 错误,但我们并没有声称我们找到了所有这些错误。事实上,如果有 7 个错误,则很可能有第 8 个。因此,如果某些事情没有改变,我们很可能有一天会看到这样的链在野外使用(当然,乐观地假设攻击者还没有这种能力)。
那么,微软可以做些什么来让未来的攻击变得更加困难:
如果您想自行采取行动,使用目前未知的新漏洞防止此类攻击的唯一方法似乎是完全禁用 WinHttpAutoProxySvc 服务。由于其他服务依赖于 WPAD,有时这无法在服务 UI 中完成(“启动类型”控件将显示为灰色),但可以通过相应的注册表项完成。在“HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\WinHttpAutoProxySvc”下,将“Start”的值从 3(手动)更改为 4(禁用)。
这些是搜索“禁用 WPAD”时在网上常见的一些建议,这些建议在我们的实验中无法阻止攻击:
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。