作者:青藤实验室
原文链接: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 的沙箱机制。
上图是 writeup 中对 SP 沙箱的抽象,翻译过来就是,出于安全性考虑,通过 web 上传的用户网页文件存储在数据库中而非文件系统。如此,在网页解析时,从数据库中取出的网页文件被阉割了一部分功能,比如本地文件包含指令 <!-- #include PathType = FileName -->
,这类 aspx 就像运行在一个沙箱中。
上述逻辑具体是通过Microsoft.SharePoint.ApplicationRuntime.SPPageParserFilter
来实现,实际上是通过网页文件的 path 来区分:
如果进入了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 给出了漏洞利用方法的触发点:
下面是 SP 自带的 RenderWebPartForEdit
用法
直接测作者给出的 poc 返回 400
发送空字符串时我注意到响应中 RenderWebPartForEditResult 的值都是 html 转码
就明白了这里请求中的 webPartXml 参数也需要 html 转码
结果进行了4次 html 实例编码,不用解码,直接找 machineKey
对比 C:\inetpub\wwwroot\wss\VirtualDirectories\80\web.config
里的反序列化密钥完全一致。
另外,在 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
目录下有两个目录:
VirtualDirectories 后面的 80 和 15594 命名看着很像端口但是不是,参考 How to: Find the Web Application Root 可以知道默认安装会有两个,一个是 80 命名固定,另一个是管理 web 的 GUID,具体值随机比如这里是 15594。爆破是一个思路,另外由于 #include 指令支持两种模式
我测试了下面的指令没有成功
<!-- #include virtual ="/web.config" -->
如何更方便地获取管理 web 的 GUID 后期可能还需要探索,可以尝试在 layouts 目录下找找是否有能返回 GUID 的功能。
这里就直接用 15594 重新获取我需要的 machineKey
拿到 machineKey 后用 ysoserial.net 生成 payload 发送给 SP 即可,由于利用 _layouts/15/zoombldr.aspx
反序列化 rce 在 SP 利用中是个比较常见的需求,我改了一下 @mr_me 的利用脚本,去掉了读 machineKey 的部分,做完这些就可以弹出 calc 了
参考
https://srcincite.io/pocs/cve-2020-16952.py.txt
本文由 Seebug Paper 发布,如需转载请注明来源。本文地址:https://paper.seebug.org/1424/