作者:青藤實驗室
原文鏈接: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 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/1424/