两个0day,一把辛酸泪:被禁言后,研究员再曝Steam Windows 客户端本地提权0day(详)
不久前,研究员Vasily Kraets 发现了 Steam Windows 客户端中的一个0day 漏洞,并通过HackerOne 平台提交给 Steam 所属公司Valve。但想不到的是,Kraets不仅未等到 Valve 的反馈,竟然还被禁言了。然而,Kraets再次发现了影响 Steam Windows 客户端的又一个0day,无奈之下他选择公开该漏洞的详情。另外,虽然Valve 公司迫于压力修复了第一个0day,但补丁已遭绕过。如下是 Kraets 对整个事件的简述以及对第二个0day的详述。
第1个提权0day
不久前,我发布了一篇关于 Steam 漏洞的文章。之后我收到了很多的反馈,但 Valve 公司并无任何回应。之后HackerOne 平台发送给我一封长信,但多数时候保持缄默。最终Valve 通过 HackerOne 平台把我禁言了:我无法参与他们的漏洞拒绝计划(不过余下计划仍然可参加)。
大家可阅读我之前发布的文章了解具体详情,现在我想针对现状说几句。现在的状况让人遗憾也很简单:Valve 公司继续失职。上次发布的补丁本应该能解决问题,但却被绕过了,因此问题还在。而且我已经检查过了,绕过方法有效。
不过这篇文章并非关于第1个0day,而是说明我发现的第2个0day。既然 Valve 公司拒绝接收私下提交的报告,那么我就如他们愿好了,让他们阅读一份公开的漏洞报告吧。我将不会剥夺他们的这种快乐。
第2个0day 漏洞简述
漏洞利用非常简单,分为三步:
(1)准备利用环境(可利用两种不同的弱点,获得两种准备方法)
(2)拷贝 Steam 并运行我们的 DLL
(3)DLL 必须满足某些条件
任何 OS 用户,更确切地说,计算机上的任意程序均可执行以上任何动作。结果是,可通过最大权限执行任意代码,该漏洞的类别是“权限提升 (eop)”或“本地权限提升(lpe)”。尽管应用程序本身可能是有害的,但实现最大权限可导致更具灾难性的后果。例如,禁用防火墙和杀毒软件、安装后门程序、隐藏进程挖矿机、窃取任意个人电脑用户的私密数据等等只是造成的一小部分后果。
理论基础
上篇文章的留言很有意思,有人说“用户无法写入 HKLM 注册键”或“你需要管理员权限才能创建一个符号链接。”有意思的是,查看这些评论花费的时间和写这些评论的时间几乎一样长。以防万一,这里说一下,这两种说法都是错误的。我在这里简单回复一下,顺便说明了利用中的一点难点问题。
(1)关于“用户无法写入HKLM 注册组”
不存在这样的一般规则。具体的注册表项适用于具体的安全规则。Valve 用户可以完全控制 HKLM\SOFTWARE\Wow6432Node\Valve\steam 分支,因此任何用户能够随心所欲,为所欲为。
(2)关于“启动或停止服务需要具有管理员权限”
不存在这类一般规则。具体的服务适用于具体的安全规则。Valve 授予所有用户启动和停止 Steam Client Service 的权限。
(3)关于“需要具有管理员权限才能创建符号链接”
这种陈述本身就很有趣,因为 Windows 中存在五种常规的链接类型,其中只有一个半的类型需要具备这类权限。这五种链接类型是:文件符号链接、对象目录符号链接、硬链接、NTFS重新分析点和 reg_link。只有创建文件符号链接和永久对象目录符号链接才需要具备管理员权限(临时的对象目录符号链接会存在,只要创建它的会话存在就会存在,一般会持续到重启之前,而且不要求具备任何特殊权限。)
(4)关于“文件夹到文件夹的符号链接”
它被称为 NTFS 重新分析点或 NTFS 安装点。叫什么不重要,重要的是它允许使用一个目录作为另一个目录的链接。如果用户具有写入权限,那么用户就能从空文件夹中创建它。使用 symboliclink 测试工具包中的 CreateMountPoint.exe (https://github.com/googleprojectzero/symboliclink-testing-tools/)即可创建它。
(5)关于机会锁
机会锁或 OpLock (https://docs.microsoft.com/ru-ru/windows/win32/fileio/opportunistic-locks) 是一种特殊机制,允许临时拦截对某个文件的访问。我们可以展开说明很多详情,比如文件的功能以及不同类型的访问权限。简言之,该程序能够“捕获”某个文件的访问事件并临时持有它。可通过上述同样的 symboliclink 测试工具包中的 SetOpLock.exe 设置 OpLock。启动该工具即可设置所需的机会锁;当访问被机会锁锁定的文件时,该工具会打印一条信息;可通过按 “Enter” 键的方式释放 oplock。
(6)关于 BaitAndSwitch
它是一种结合了链接创建和机会锁以赢得 TOCTOU(检查时间\使用时间)的技术。我们通过一个例子更加简单地解释一下:
假设某程序作出如下动作:
ReadContentFromFile("C:\test\myfile.txt");
ReadContentFromFile("C:\test\myfile.txt");
它只是连续两次读取同一个文件。那么它两次读取的信息是相同的吗?不见得。
首先,我们创建两个文件夹 “C:\test1\myfile.txt”和 “C:\test2\myfile.txt”。接下来,我们清空 “C:\test” 并创建一个重新解析点 “C:\test1”。之后,我们将 oplock 设置为第一个文件夹中的文件并运行程序。一旦打开文件,就会触发oplock。我们更改重新解析点,因此 “C:\test” 链接到 “C:\test2”。现在,释放 oplock 之后,程序将从另一个文件中再次读取信息。
它的适用场景是什么?这个问题很好回答,有很多非常典型的情况。首先检查文件(第一次读取),然后执行(第二次读取)。这就是检查一个文件然后执行另外一个文件的情况。
现在,就等利用了。
利用第1步:环境准备
准备工作环境是必要的步骤。首先,我们需要获取 CreateMountPoint.exe 和 SetOpLock.exe 文件。
现在需要对 Steam 文件结构做出一些修改。我们的目标是拥有后缀为 Steam.exe 和 steamclient.dll 文件夹,同时删除 “bin” 文件夹。有两种方法可实现这一目标。
方法1
从 Steam 根文件夹中重命名/删除bin 文件夹。除此之外,无需任何动作。Steam 允许所有用户在文件夹中进行任何操作。
方法2
将 HKLM\SOFTWARE\Wow6432Node\Valve\steam registry key. CopySteam.exe and steamclient.dll 中任意文件夹路径的InstallPath 值更改为原始 Steam 文件夹中的文件夹路径的值。
这样,通过以上任何一种方法,我们就准备好 C:\Steam 文件夹(可以是任意路径,但我将会在例子中使用该文件夹)了。现在我们必须在其中创建 b1、b2、b3和b4 文件夹。我们首先在前三个文件夹(原来位于 Steam 数据包的 bin 文件夹中)中复制 steamservice.dll,之后在 b4 中复制精心构造的具有相同名称的库 (steamservice.dll)。我们将在第三个利用步骤中详细说明如何准备库。
打开两个控制台窗口。至此,环境准备完成。
利用第2步: 切换文件
从准备阶段来看,很明显这里应该出现类似上述说明的 BaitAndSwitch 这样的情况。
ProMon 截屏:
如上是典型的 Steam Client Service 启动日志片段。首先,dll 被复制到 C:\Program Files (x86)\CommonFiles\Steam,然后被加载。我们将使 Steam 从C:\Steam\b4 instead 中复制我们的库。遗憾的是,存在一些检查,其中包含对库签名的检查以阻止 dll 遭劫持(多么讽刺!)。
因此,我将逐步说明利用步骤。这些步骤组合在一组类似的操作中。我将在每个步骤中说明需要执行什么、在哪里执行以及执行后会发生什么(控制台窗口的名称是 “cmd1” 和“cmd2”)。
(1) 创建 C:\Steam\bin 文件夹并在 cmd1 中执行如下命令:
CreateMountPoint.exeС:\Steam\bin C:\Steam\b1
(2) 在 cmd1 中设置 oplock:
SetOpLock.exeC:\Steam\b1\steamservice.dll
(3) 运行 Steam Client Service。你将在cmd1 中看到已捕获到对文件的访问。
(4) 删除C:\Steam\bin并创建C:\Steam\bin 文件夹,之后在 cmd2 中执行如下命令:
CreateMountPoint.exeС:\Steam\bin C:\Steam\b2
(5) 在cmd2中设置oplock:
SetOpLock.exeC:\Steam\b2\steamservice.dll
(6) 在 cmd1 中发布 oplock。可以看到在 cmd2 中已经捕获到对文件的访问权限。
(7) 删除C:\Steam\bin并创建C:\Steam\bin 文件夹,之后在 cmd1 中执行如下命令:
CreateMountPoint.exeС:\Steam\bin C:\Steam\b3
(8) 在 cmd1 中设置 oplock:
SetOpLock.exe C:\Steam\b3\steamservice.dll
(9) 在 cmd2 中发布 oplock。可以看到在 cmd1 中已经捕获到对文件的访问权限。
(10)删除C:\Steam\bin并创建C:\Steam\bin 文件夹,之后在 cmd2 中执行如下命令:
CreateMountPoint.exeС:\Steam\bin C:\Steam\b2
(11)在cmd2中设置 oplock:
SetOpLock.exeC:\Steam\b2\steamservice.dll
(12)在cmd1 中发布 oplock。可以看到在 cmd2中已经捕获到对文件的访问权限。
(13)删除C:\Steam\bin并创建C:\Steam\bin 文件夹,之后在 cmd1中执行如下命令:
CreateMountPoint.exeС:\Steam\bin C:\Steam\b3
(14)在cmd1中设置oplock:
SetOpLock.exeC:\Steam\b3\steamservice.dll
(15)在cmd2中发布 oplock。可以看到在 cmd1中已经捕获到对文件的访问权限。
(16)删除C:\Steam\bin并创建C:\Steam\bin 文件夹,之后在 cmd2中执行如下命令:
CreateMountPoint.exeС:\Steam\bin C:\Steam\b4
(17) 在 cmd1 中发布 oplock。
这些步骤看似复杂但想法实际上很简单:将C:\Steam\bin\steamservice.dll 的前5个(共6个)访问权限重定向至不同文件夹所给予的原始文件中(按访问顺序排列:b1、b2、b3、b2、b3),之后把第6个访问权限重定向至我们的 payload。
概要说明如下图:
左边是应用程序的正常行为,后边是利用过程中的行为。
利用第3步:可注入的库
首先我尝试使用最常用的dll,在DllEntry 中创建交互性控制台作为 payload。由于 dll 代码在 Steam Client Service 中执行,因此它将以该服务的权限得以执行:NT AUTHORITY\SYSTEM。但在最终利用中控制台并未出现。
加载后,Steam 发现被骗,因此在我的 dll 中的 payload 执行之前就关闭了。
然后我不得不进行逆向,之后发现该服务检查 dll 加载后库中是否存在如下函数:
int WINAPISteamService_RunMainLoop()
void WINAPISteamService_Stop()
另外,服务调用第一个函数,而这也是我决定放 payload 的地方(以服务权限运行交互性控制台:NT AUTHORITY\SYSTEM)。大功告成,我重复所有的动作并以最大权限获得了控制台。
结论
所有的内容都可封装在 exe-file 中,不过我不想这么做。我认为演示视频就足够了:
注册表项方法:https://www.youtube.com/watch?v=ZCHrjP0cMew
文件系统方法:https://www.youtube.com/watch?v=I93aH86BUaE
我不会像上一篇文章那样做出“推测”。事实就是:这个新的0day 和上一个 0day 之间是相关的;你所看到的就是这个新 0day 漏洞的情况,而 Valve 公司仍然在掩耳盗铃。
*作者发布的关于第一个 0day 的文章原文地址:
https://amonitoring.ru/article/steamclient-0day/。
原文链接
题图:Pixabay License
本文由奇安信代码卫士编译,不代表奇安信观点,转载请注明“转自奇安信代码卫士 www.codesafe.cn”
奇安信代码卫士 (codesafe)
国内首个专注于软件开发安全的产品线。