作者:青藤實驗室
原文鏈接:https://mp.weixin.qq.com/s/ZLSFXUoNNAFxqeiD9RpYZg

SharePoint Rce 系列分析(一) 里我簡單介紹了 SP 的沙箱機制,并且通過 CVE-2020-0974 展示了 bypass 原理:

VerifyControlOnSafeList(..., false)

這類漏洞原理簡單,正則特征明顯,可以借助自動化手段檢測,除非找到新的 bypass 點,之后再出現同類型的漏洞概率不大。

本文介紹的是議題中的另一個漏洞:CVE-2020-1444。它在所有安全機制開啟,沒有方法參數使用不當情況下,通過 TOCTOU 實現了 rce;這種漏洞很難通過有效的漏洞模型去自動化檢測,所以后續出現這種漏洞的可能性仍然存在,比如 CVE-2020-16951。

調試環境

Server2016
SP2016
dnSpy

通過 proexp 找到管理 web 的 pid -w981 dnSpy attach 進程后在觸發 url 被處理的地方下斷點 -w1433

背景知識

ObjectDataSource

通過 ObjectDataSource 定義 知道在 asp.netObjectDataSource 可以調用任意運行時方法,類似 ObjectDataProvider

Asp.Net 的內聯表達式

<%-- ... -- %> 表示注釋
<%@ ... %> 表示指令

以上都是 asp.net 的內聯表達式,更具體點,比如下面 Register 指令實例:

<%@ Register TagPrefix="asp3" Namespace="System.Web.UI.WebControls" Assembly="System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" %>

<asp3:ObjectDataSource ID="ODS1" runat="server" SelectMethod="Start" TypeName="System.Diagnostics.Process" >
    <SelectParameters>
        <asp3:Parameter Direction="input" Type="string" Name="fileName" DefaultValue="calc"/>
    </SelectParameters>
</asp3:ObjectDataSource>
<asp3:ListBox ID="LB1" runat="server" DataSourceID = "ODS1" />

第1行注冊了對 System.Web.UI.WebControls 命名空間的引用,類似 python 中的 import,別名是 asp3。

之后的 <asp3:ObjectDataSource...> 表示 System.Web.UI.WebControls 下必有一個名為 ObjectDataSource 的類。

CVE-2020-1444

借用議題中的原圖來概括漏洞過程: -w642 用戶輸入在經過服務端校驗后,被服務端修改后再使用,這個順序顯然是有問題的,也是漏洞成因,具體到代碼里: -w931 為了方便理解,我把 "change and use" 指向了 "check" 下一行,實際上這里只是 change 的開始,也是漏洞成因的一個關鍵地方,不是最終解析的地方。

check

SP 的沙箱機制在議題中有詳細介紹,上篇文章也說過,下面直接說漏洞相關的部分。

在 design mode 下,Check 通過 VerifyControlOnSafeList 完成。它位于: -w748 -w919 請求發生時的調用棧 -w1408 通過 call stack 可以看到 check 始于 ConvertWebPartMarkup

暫時不考慮具體的校驗邏輯,試想一下,假如上傳的整個網頁文件是個注釋,比如: -w622

這時 Check 肯定能通過。

Change

Change 發生在 ConvertMarkupToTree。通過 OnLoad 前幾行代碼可以看出有兩個必須提供的參數:WebPartUrlUrl

Url 參數暫時不管,在后面漏洞利用章節會去討論。通過對代碼 trace 可以發現 WebPartUrl 指向的文件必須是一個 xml,這個 xml 還有其他要求,暫且不提。從服務端取參到 ConvertMarkupToTree 的處理步驟是:

  1. 取參(url of xml)
  2. 通過 web 獲取 xml 的字符串流(GetWebPartMarkup)
  3. 對字符串流做一些預處理,包括校驗(ConvertWebPartMarkup)
  4. 將字符串流轉成 xml 樹(ConvertMarkupToTree)
  5. 經過各種處理...,將 xml 樹 轉回字符串流(xelement2.ToString)
  6. 網頁解析(ParseControl)

從上面可以看出 string -> xml tree 發生在校驗之后,看看具體做了哪些事 -w761 下面是正則定義: -w764 這個正則匹配的是內聯表達式中的 Register 指令,有兩個命名捕獲:TagPrefix 和 DllInfo。

TagPrefix 用正則捕獲,DllInfo 是 TagPrefix 之后的所有內容。比如下面的例子: -w718 再來看 ConvertMarkupToTree:首先把所有 Register 指令從字符串流中取出來做特殊處理(比如全部放到 xml 首尾這樣的特殊位置),把剩下的內容簡單處理一下,比如去掉轉義、重新添加一個 root 就轉成 xml tree 了: -w677 回憶一下剛才通過 Check 的 demo: -w622 由于正則匹配到了其中的 Register 指令,取出 Register 指令之后:

webPartMarkup = webPartMarkup.Replace(match.Value, "")

demo 就變成了: -w627 之后會繼續構造 xml tree,在最終網頁解析之前肯定還要轉回字符串流,那么這里本應該是注釋的內容({unsafe ...})就在變成了一個 ASPX 標簽,實現了沙箱逃逸。

漏洞利用

BH 上作者給出了一部分 poc: -w632 我參考了 CVE-2020-16951 的 poc,另一個 SP 的 TOCTOU 漏洞,結合上述分析,明白上述 xml 是這個漏洞利用的第一步,這個漏洞是分兩步實現:

// put xml
PUT /poc.xml HTTP/1.1
...
// trigger rce
GET /_layouts/15/WebPartEditingSurface.aspx?WebPartUrl=http://.../poc.xml&Url=? HTTP/1.1

問題就出在 GET 請求的 URL 參數上,作者對這個參數的要求進行了簡單說明: -w660 我自然就想到了 Master Page Gallery 里的幾個 master 文件 -w852 CVE-2020-16951 的 poc 就用了其中的 seattle.master -w1051 我嘗試也用這個文件作為參數響應報錯,calc 進程也沒啟動 -w1439 在 SMP 中開啟了啟用詳細日志:

Set-SPLogLevel –TraceSeverity VerboseEx
New-SPLogFile
Get-SPDiagnosticConfig | select LogLocation
Clear-SPLogLevel

通過重新錯誤的報錯信息得到了報錯時的 call stack:

Application error when access /_layouts/15/WebPartEditingSurface.aspx, Error=The field b510aac1-bba3-4652-ab70-2d756c29540f does not exist in the list item _catalogs/masterpage/seattle.master.   
at Microsoft.SharePoint.Publishing.Internal.WebControls.ComponentRibbonHelper.GetContentTypeFieldValue(String pathToPageLayout)     
at Microsoft.SharePoint.Publishing.Internal.WebControls.ComponentRibbonHelper.IsPageLayout(String pathToPageLayout, ContentTypeIdFieldValue& associatedContentTypeFieldValue)     
at Microsoft.SharePoint.Publishing.Internal.WebControls.ComponentRibbonHelper.OnPreRender(EventArgs e)     
at System.Web.UI.Control.PreRenderRecursiveInternal()     
at System.Web.UI.Control.PreRenderRecursiveInternal()     
at System.Web.UI.Control.PreRenderRecursiveInternal()     
at System.Web....   2c6c909f-e9be-00ce-823a-6efbede23872
...

進而確定了出錯位置: -w1009 跟進后發現 b510aac1-bba3-4652-ab70-2d756c29540fFieldId.AssociatedContentType 的 GUID: -w802 正好和漏洞作者說的一致

It should contain the relative address of any file from the SharePoint 
DataBase with the FieldId.AssociatedContentType field

我怎么判斷 seattle.master 是否存在某個指定的 GUID 比如 b5..0f 呢。

通過了解 Onet.xml 文件這篇文章我知道了 Onet.xml 定義了所有的 BaseTypes,我在所有 Onet.xml 里搜索這個 GUID 并沒有找到,之后我擴大了搜索范圍在

C:\Program Files\Common Files\microsoft shared\Web Server Extensions\16\TEMPLATE

最終在

C:\Program Files\Common Files\microsoft shared\Web Server Extensions\16\TEMPLATE\FEATURES\PublishingResources

下找到了包含這個 GUID 的兩個 xml -w1436 參考 CVE-2020-16951 的 poc,url 如果是個 master 文件肯定沒問題,不管 master 如何和 xml 關聯,此時我想直接把PublishingMasterTemplate.master 作為 url,如果這樣我必須通過 web 能訪問到這個 master 文件。 -w1093 google 了一下 PublishingMasterTemplate.master 得到一個別人報錯信息中的 url:

/_catalogs/masterpage/Forms/Publishing Master Page/PublishingMasterTemplate.master

嘗試直接訪問這個 path 得到 404,進一步研究發現這個東西似乎和 publishingresources 這個 feature 有關,默認關閉

我用 SMP 打開了這個 feature -w959 之后再嘗試那個 path 仍然 404,但是嘗試原請求不再報 GUID 找不到的錯誤了 -w1439 也不再進入 catch 分支 -w1008 在 list 中能看到 FieldId.AssociatedContentType-w1007 calc 進程啟動 -w1025

我確定 publishingresources 這個 feature 在 SP2016 默認安裝條件下不會開啟,看漏洞作者和 @mr_me 用的也是 SP2016 測試但沒提到這個,查了下官方漏洞公告也沒提到。所以我不確定這個是否是漏洞利用的條件之一,但是我確實是在開啟了這個功能后復現成功,感興趣的朋友可以研究一下。

參考

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-16951.py.txt

https://msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2020-1444

https://docs.microsoft.com/en-us/dotnet/api/system.web.ui.webcontrols.objectdatasource?view=netframework-4.8

https://docs.microsoft.com/zh-cn/previous-versions/office/developer/sharepoint-2010/ms474369(v=office.14)


Paper 本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/1430/