SharePoint Rce 系列分析(一)

作者:青藤实验室

原文链接:https://mp.weixin.qq.com/s/FfHc8TFUs_4H8JHWbYv3FQ

得益于 @pwntester@Oleksandr 在 blackhat 上做的两次关于 .net 安全的分享,.net 应用的攻击面被越来越多的安全研究者了解。除了常规的反序列化,在今年的 blackhat-us 上两人更是通过一系列的 SharePoint(以下简称 SP) Rce 漏洞展示了如何通过各种手段 bypass SP 的安全沙箱,以至于此后,SP 成了微软月更新上的常客,后续的 SP Rce 漏洞大多使用了类似的手法,只是触发点不同,或者 bypass 了之前的 patch。

上个月花了点时间学习了该议题,该议题实际上分为 java 和 .net 两部分,java 部分比较直观也很精彩,本文不做讨论。由于之前对 .net 以及 SP 不太熟悉,于是搭了环境逐个调试了文中提到的漏洞。看议题的 writeup 时由于作者的讲述逻辑很清晰,感觉没啥问题,实际上手调试时仍遇到不少问题,在此记录这些问题与我的理解。

调试环境

Server2016

SP2016

背景知识

SP 一句话概括:微软用 .net 开发的一套 cms。既然是 cms 肯定允许用户上传,普通用户通过 PUT /my.aspx 的方式就可以上传自己写的任何内容,之后通过 GET /my.aspx 可以看到。

虽然我可以在 my.aspx 中写任何内容,但并不是我写的任何内容都会被 SP 服务端解析,不然任何 authed 用户都可以 rce 了。这里就要提到 SP 的沙箱机制。

-w700

上图是 writeup 中对 SP 沙箱的抽象,翻译过来就是,出于安全性考虑,通过 web 上传的用户网页文件存储在数据库中而非文件系统。如此,在网页解析时,从数据库中取出的网页文件被阉割了一部分功能,比如本地文件包含指令 <!-- #include PathType = FileName -->,这类 aspx 就像运行在一个沙箱中。

上述逻辑具体是通过Microsoft.SharePoint.ApplicationRuntime.SPPageParserFilter 来实现,实际上是通过网页文件的 path 来区分:

-w625

如果进入了if分支,沙箱就会生效,简称 filter 机制。

但是,在服务端最终用System.Web.UI.TemplateControl.ParseControl()解析网页时,如果按照下面的方式使用:

ParseControl(content);

ParseControl(content, ?true?);

filter 机制就会失效,只有第2个参数显示指定为 false 时才 ok,我猜作者大概按照这个思路没有找到直接可用的漏洞,但是发现在 design mode 下,filter 机制都会失效,但是会有新的校验方法:Microsoft.SharePoint.EditingPageParser.VerifyControlOnSafeList()

// Microsoft.SharePoint.EditingPageParser

internal static void VerifyControlOnSafeList(string dscXml, RegisterDirectiveManager registerDirectiveManager, SPWeb web, bool blockServerSideIncludes = false)

这个方法简称 verify 机制,和ParseControl一样,最后一个参数也会影响安全因素,当最后一个参数为 false 时(默认 false),允许使用 include 指令。

我在之前的 CVE-2020-17083:Exchange Authed Rce 分析 里提到过在 Exchange、SharePoint 里一旦可以任意读利用反序列化就可以 rce,include 指令就能实现任意读。

CVE-2020-0974

漏洞原理很简单,背景知识里说了,在 verify 机制中,VerifyControlOnSafeList 方法的 blockServerSideIncludes 参数(最后一个参数)为 false 时允许使用 include 指令。

writeup 给出了漏洞利用方法的触发点:

-w676

下面是 SP 自带的 RenderWebPartForEdit 用法

-w1437

直接测作者给出的 poc 返回 400

-w1287

发送空字符串时我注意到响应中 RenderWebPartForEditResult 的值都是 html 转码

-w1431

就明白了这里请求中的 webPartXml 参数也需要 html 转码

结果进行了4次 html 实例编码,不用解码,直接找 machineKey

对比 C:\inetpub\wwwroot\wss\VirtualDirectories\80\web.config 里的反序列化密钥完全一致。

-w915

另外,在 HMACSHA256 加密的情况下,我只需要 validationKey 字段就可以完成反序列化利用,别的加密方式需要更多参数本文不做讨论。

漏洞利用到此结束?并没有。这个 validationKey 不是我需要的。在分析 CVE-2020-16952 时我就发现 SP2016 中存在一个稳定的反序列化利用点:

_layouts/15/zoombldr.aspx

它位于管理 web 下,所以在 SP 中能读到 web.config 中的 machineKey 部分就能实现 rce,这也是大多数分析文章或者 poc 到实现读取 machineKey 就结束了,因为之后的流程是 SP 反序列化利用的常识。

简单解释一下,SP 下每个站的 web 根目录都有一个 web.config,这里面的反序列化加解密不是一样的,比如我的测试机上在 C:\inetpub\wwwroot\wss\VirtualDirectories 目录下有两个目录:

-w1432

VirtualDirectories 后面的 80 和 15594 命名看着很像端口但是不是,参考 How to: Find the Web Application Root 可以知道默认安装会有两个,一个是 80 命名固定,另一个是管理 web 的 GUID,具体值随机比如这里是 15594。爆破是一个思路,另外由于 #include 指令支持两种模式

-w426

我测试了下面的指令没有成功

<!-- #include virtual ="/web.config" -->

如何更方便地获取管理 web 的 GUID 后期可能还需要探索,可以尝试在 layouts 目录下找找是否有能返回 GUID 的功能。

这里就直接用 15594 重新获取我需要的 machineKey

-w1439

拿到 machineKey 后用 ysoserial.net 生成 payload 发送给 SP 即可,由于利用 _layouts/15/zoombldr.aspx 反序列化 rce 在 SP 利用中是个比较常见的需求,我改了一下 @mr_me 的利用脚本,去掉了读 machineKey 的部分,做完这些就可以弹出 calc 了

-w1424

参考

https://i.blackhat.com/USA-20/Wednesday/us-20-Munoz-Room-For-Escape-Scribbling-Outside-The-Lines-Of-Template-Security-wp.pdf

https://srcincite.io/pocs/cve-2020-16952.py.txt

以上是 SharePoint Rce 系列分析(一) 的全部内容, 来源链接: utcz.com/p/199800.html

回到顶部