不久之前,我刚发表过关于Steam漏洞的一篇研究文章。我收到了许多反馈,但Valve并没有发表任何看法,HackerOne给我发了一封内容颇多的信,但后面也没有任何进展。最终这个事件升级,Valve拒绝在HackerOne上接收我的报告,我无法再继续参与他们的漏洞拒绝计划(但H1剩余部分仍然可以参与)。
大家可以阅读之前的文章了解详细信息。
Valve新推出一个补丁想解决这个问题,然而该补丁可以轻松被绕过,因此这个漏洞依然存在。
然而本文并不想讨论之前的老漏洞,会介绍一个全新的漏洞。由于Valve更喜欢看到直接公开的漏洞报告,而不是通过私下的沟通渠道解决问题,因此我决定满足他们的愿望。
0x01 简要描述
漏洞利用非常简单,主要包括3个步骤:
1、准备利用环境;
2、让Steam复制并运行我们自己的DLL;
3、DLL必须满足某些条件。
系统上任何用户(或者更明确地说,是主机上任何程序)都可以执行以上步骤,利用该漏洞最终可以以更高权限执行任意代码,因此该漏洞属于权限提升(EOP)或者本地提权(LPE)漏洞。尽管应用程序本身可能可能有潜在风险,但提升至更高权限后可以造成更严重后果,比如可以禁用防火墙及杀毒软件、安装rootkit、隐藏挖矿进程、窃取用户隐私数据等。
0x02 背景知识
上一篇文章的评论有些非常有趣,有人提到“用户不能往HKLM注册表中写入数据”或者“我们需要管理员权限才能创建符号链接”。想要核实这些言论其实很简单,大家也能猜到,这些结论都不正确。这里我想稍微提一下这方面内容,顺便介绍漏洞利用过程中稍微困难的几个点。
1)“用户不能往HKLM注册表中写入数据”。
实际上并没有这种规则,特定注册表项可以对应特定的安全规则。Valve向所有用户开放了HKLM\SOFTWARE\Wow6432Node\Valve\steam的完整控制权限,因此任意用户都可以随意操纵该表项。
2)“如果不具备管理员权限就不能开始或停止服务”。
也没有这种规则,特定服务可以对应特定的安全规则。Valve向任意用户开放了Steam Client Service的开始或停止权限。
3)“我们需要管理员权限才能创建符号链接”。
这个表述本身就比较有趣。在Windows系统中总共有5种常见的链接,但只有一半需要管理员权限。这5种链接分别为:文件符号链接、对象目录符号链接、硬链接、NTFS重解析点以及reg_link。只有在创建文件符号链接以及永久对象目录符号链接时才需要管理员权限(临时对象目录符号链接的生存周期与会话保持一致,在大多数情况下,一旦创建成功可以维持到重启之前,并且不需要特殊权限)。
4)“从目录到目录的符号链接”。
实际上这是NTFS重解析点(reparse point)或者是NTF挂载点(mount point)。名字本身并不关键,我们可以利用重解析点将一个目录作为另一个目录的链接。如果用户具备写入权限,就可以通过空目录创建这种链接。我们可以使用symboliclink testing tools中的CreateMountPoint.exe来创建该链接。
5)OpLock
OpLock(或者Opportunistic Lock,机会锁)是一种特殊机制,可以用来临时阻止对特定文件的访问。大家可以参考官网了解关于OpLock的更多细节,比如在文件处理以及不同访问类型时的功能等。简而言之,程序可以通过该功能“捕捉到”访问某个文件的事件,然后临时阻止该操作。我们可以使用symboliclink testing tools工具包中的SetOpLock.exe工具来设置OpLocks。设置所需的OpLock后,当访问被锁定的文件时,该工具就会打印一条消息,如果我们按下回车键,就可以释放OpLock。
6)BaitAndSwitch
这是一种技术手法,将链接创建以及OpLock结合起来,以赢得TOCTOU(time of check/time of use)竞争条件。这里我们举个例子来描述这种技术:
设想某个程序会执行如下操作:
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后,第二次读取时该程序就会从另一个文件读取出内容。
这种 *** 的应用场景在哪?其实很容易想到,比如我们可以让目标检查之一个文件(之一次读取)然后执行第二个文件(第二次读取)。这样我们就实现一个文件用来检查,另一个文件用来执行的应用场景。
以上就是我们在漏洞利用中所涉及到的一些背景知识。
0x03 漏洞利用
环境准备
环境准备非常重要。首先,我们需要准备好CreateMountPoint.exe以及SetOpLock.exe这两个工具。
现在需要稍微改变一下Steam的文件结构。我们的目标是修改目录,使得其中包含Steam.exe以及steamclient.dll,不包含bin目录。我们可以通过两种 *** 完成该任务:
*** 1
在Steam根目录中重命名/移动bin目录,就这么简单(Steam为所有账户都开放了该目录权限)。
*** 2
在HKLM\SOFTWARE\Wow6432Node\Valve\steam注册表项中,将InstallPath的值修改为我们的目录路径,然后从原始的Steam目录中将Steam.exe以及steamclient.dll拷贝到该目录中。
我们通过任意一种 *** 构造出C:\Steam目录(这里可以选择任意路径)。现在我们需要在其中创建b1、b2、b3以及b4目录。我们将steamservice.dll拷贝到前3个目录(该dll位于Steam安装目录的bin目录中),然后使用相同名称构造出一个dll(steamservice.dll),拷贝到b4目录中。DLL的构造 *** 可以参考下文。
启动两个Windows控制台,现在我们的利用环境已准备就绪。交换文件
根据前面的环境准备要点,大家应该能猜到我们准备使用前文提到的BaitAndSwitch技术。
ProcMon的输出结果如下所示:
当Steam Client Service启动时,我们通常可以在ProcMon中看到上图所示日志。这里简单描述一下,首先目标服务会将dll拷贝到C:\Program Files (x86)\Common Files\Steam目录中,然后加载该dll。我们可以让Steam从C:\Steam\b4拷贝我们的dll,不幸的是,Steam首先会执行检查操作,判断程序库的是特征否正常,避免dll劫持攻击。
这里我准备逐个步骤描述漏洞利用过程,相同操作的步骤会归在一个组中。在每个步骤中,我们要注意需要执行的程序、执行的位置以及执行后的结果(前面启动的两个Windows控制台分别为“cmd1”以及“cmd2”).
具体步骤如下:
1)创建C:\Steam\bin目录,在cmd1中执行如下命令:
CreateMountPoint.exe С:\Steam\bin C:\Steam\b1
2)在cmd1中设置OpLock:
SetOpLock.exe C:\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.exe C:\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.exe C:\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.exe C:\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。
流程图如下所示:
上图中左图是应用程序正常的访问行为,右图是漏洞利用过程中被我们改造过的行为。
构造payload
在payload构造中,我首先尝试最常用的dll,在DllEntry中创建一个交互式控制台。由于dll代码会在Steam Client Service上下文中执行,因此能够拿到服务对应的权限,即NT AUTHORITY\SYSTEM。然后执行完利用步骤后,我并没有看到想要的控制台。
在dll加载后,Steam服务会发现程序流程存在异常,因此会在执行dll中的payload前关闭服务。
这里我只能稍微逆向分析一波,发现目标服务会在加载dll后,检查dll中是否存在如下函数:
int WINAPI SteamService_RunMainLoop()
void WINAPI SteamService_Stop()
此外,目标服务还会调用之一个函数,因此我决定将payload放在这个函数中(这样就能以NT AUTHORITY\SYSTEM权限运行交互式控制台)。就这么简单,准备就绪后我就可以重复利用步骤,拿到更高权限的控制台。
0x04 总结
其实这些利用过程都可以封装在一个exe中,但我懒得去处理了,大家可以自己尝试一下。大家可以观看此处视频了解通过注册表的利用方式,观看此处视频了解通过文件系统的利用方式。
Valve在Beta版客户端中修复了这个漏洞,当正式版客户端安装更新后,我也会检查漏洞是否修复。
此外,Valve在HackerOne上修改了关于LPE的策略,这也是非常不错的一个消息。
大家可以阅读之前的文章了解详细信息。
Valve新推出一个补丁想解决这个问题,然而该补丁可以轻松被绕过,因此这个漏洞依然存在。
然而本文并不想讨论之前的老漏洞,会介绍一个全新的漏洞。由于Valve更喜欢看到直接公开的漏洞报告,而不是通过私下的沟通渠道解决问题,因此我决定满足他们的愿望。
0x01 简要描述
漏洞利用非常简单,主要包括3个步骤:
1、准备利用环境;
2、让Steam复制并运行我们自己的DLL;
3、DLL必须满足某些条件。
系统上任何用户(或者更明确地说,是主机上任何程序)都可以执行以上步骤,利用该漏洞最终可以以更高权限执行任意代码,因此该漏洞属于权限提升(EOP)或者本地提权(LPE)漏洞。尽管应用程序本身可能可能有潜在风险,但提升至更高权限后可以造成更严重后果,比如可以禁用防火墙及杀毒软件、安装rootkit、隐藏挖矿进程、窃取用户隐私数据等。
0x02 背景知识
上一篇文章的评论有些非常有趣,有人提到“用户不能往HKLM注册表中写入数据”或者“我们需要管理员权限才能创建符号链接”。想要核实这些言论其实很简单,大家也能猜到,这些结论都不正确。这里我想稍微提一下这方面内容,顺便介绍漏洞利用过程中稍微困难的几个点。
1)“用户不能往HKLM注册表中写入数据”。
实际上并没有这种规则,特定注册表项可以对应特定的安全规则。Valve向所有用户开放了HKLM\SOFTWARE\Wow6432Node\Valve\steam的完整控制权限,因此任意用户都可以随意操纵该表项。
2)“如果不具备管理员权限就不能开始或停止服务”。
也没有这种规则,特定服务可以对应特定的安全规则。Valve向任意用户开放了Steam Client Service的开始或停止权限。
3)“我们需要管理员权限才能创建符号链接”。
这个表述本身就比较有趣。在Windows系统中总共有5种常见的链接,但只有一半需要管理员权限。这5种链接分别为:文件符号链接、对象目录符号链接、硬链接、NTFS重解析点以及reg_link。只有在创建文件符号链接以及永久对象目录符号链接时才需要管理员权限(临时对象目录符号链接的生存周期与会话保持一致,在大多数情况下,一旦创建成功可以维持到重启之前,并且不需要特殊权限)。
4)“从目录到目录的符号链接”。
实际上这是NTFS重解析点(reparse point)或者是NTF挂载点(mount point)。名字本身并不关键,我们可以利用重解析点将一个目录作为另一个目录的链接。如果用户具备写入权限,就可以通过空目录创建这种链接。我们可以使用symboliclink testing tools中的CreateMountPoint.exe来创建该链接。
5)OpLock
OpLock(或者Opportunistic Lock,机会锁)是一种特殊机制,可以用来临时阻止对特定文件的访问。大家可以参考官网了解关于OpLock的更多细节,比如在文件处理以及不同访问类型时的功能等。简而言之,程序可以通过该功能“捕捉到”访问某个文件的事件,然后临时阻止该操作。我们可以使用symboliclink testing tools工具包中的SetOpLock.exe工具来设置OpLocks。设置所需的OpLock后,当访问被锁定的文件时,该工具就会打印一条消息,如果我们按下回车键,就可以释放OpLock。
6)BaitAndSwitch
这是一种技术手法,将链接创建以及OpLock结合起来,以赢得TOCTOU(time of check/time of use)竞争条件。这里我们举个例子来描述这种技术:
设想某个程序会执行如下操作:
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后,第二次读取时该程序就会从另一个文件读取出内容。
这种 *** 的应用场景在哪?其实很容易想到,比如我们可以让目标检查之一个文件(之一次读取)然后执行第二个文件(第二次读取)。这样我们就实现一个文件用来检查,另一个文件用来执行的应用场景。
以上就是我们在漏洞利用中所涉及到的一些背景知识。
0x03 漏洞利用
环境准备
环境准备非常重要。首先,我们需要准备好CreateMountPoint.exe以及SetOpLock.exe这两个工具。
现在需要稍微改变一下Steam的文件结构。我们的目标是修改目录,使得其中包含Steam.exe以及steamclient.dll,不包含bin目录。我们可以通过两种 *** 完成该任务:
*** 1
在Steam根目录中重命名/移动bin目录,就这么简单(Steam为所有账户都开放了该目录权限)。
*** 2
在HKLM\SOFTWARE\Wow6432Node\Valve\steam注册表项中,将InstallPath的值修改为我们的目录路径,然后从原始的Steam目录中将Steam.exe以及steamclient.dll拷贝到该目录中。
我们通过任意一种 *** 构造出C:\Steam目录(这里可以选择任意路径)。现在我们需要在其中创建b1、b2、b3以及b4目录。我们将steamservice.dll拷贝到前3个目录(该dll位于Steam安装目录的bin目录中),然后使用相同名称构造出一个dll(steamservice.dll),拷贝到b4目录中。DLL的构造 *** 可以参考下文。
启动两个Windows控制台,现在我们的利用环境已准备就绪。交换文件
根据前面的环境准备要点,大家应该能猜到我们准备使用前文提到的BaitAndSwitch技术。
ProcMon的输出结果如下所示:
当Steam Client Service启动时,我们通常可以在ProcMon中看到上图所示日志。这里简单描述一下,首先目标服务会将dll拷贝到C:\Program Files (x86)\Common Files\Steam目录中,然后加载该dll。我们可以让Steam从C:\Steam\b4拷贝我们的dll,不幸的是,Steam首先会执行检查操作,判断程序库的是特征否正常,避免dll劫持攻击。
这里我准备逐个步骤描述漏洞利用过程,相同操作的步骤会归在一个组中。在每个步骤中,我们要注意需要执行的程序、执行的位置以及执行后的结果(前面启动的两个Windows控制台分别为“cmd1”以及“cmd2”).
具体步骤如下:
1)创建C:\Steam\bin目录,在cmd1中执行如下命令:
CreateMountPoint.exe С:\Steam\bin C:\Steam\b1
2)在cmd1中设置OpLock:
SetOpLock.exe C:\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.exe C:\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.exe C:\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.exe C:\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。
流程图如下所示:
上图中左图是应用程序正常的访问行为,右图是漏洞利用过程中被我们改造过的行为。
构造payload
在payload构造中,我首先尝试最常用的dll,在DllEntry中创建一个交互式控制台。由于dll代码会在Steam Client Service上下文中执行,因此能够拿到服务对应的权限,即NT AUTHORITY\SYSTEM。然后执行完利用步骤后,我并没有看到想要的控制台。
在dll加载后,Steam服务会发现程序流程存在异常,因此会在执行dll中的payload前关闭服务。
这里我只能稍微逆向分析一波,发现目标服务会在加载dll后,检查dll中是否存在如下函数:
int WINAPI SteamService_RunMainLoop()
void WINAPI SteamService_Stop()
此外,目标服务还会调用之一个函数,因此我决定将payload放在这个函数中(这样就能以NT AUTHORITY\SYSTEM权限运行交互式控制台)。就这么简单,准备就绪后我就可以重复利用步骤,拿到更高权限的控制台。
0x04 总结
其实这些利用过程都可以封装在一个exe中,但我懒得去处理了,大家可以自己尝试一下。大家可以观看此处视频了解通过注册表的利用方式,观看此处视频了解通过文件系统的利用方式。
Valve在Beta版客户端中修复了这个漏洞,当正式版客户端安装更新后,我也会检查漏洞是否修复。
此外,Valve在HackerOne上修改了关于LPE的策略,这也是非常不错的一个消息。
版权声明
本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。