对通过 Web API 触发的 SharePoint RCE 漏洞的分析

admin 2020年7月30日11:45:20评论364 views字数 7601阅读25分20秒阅读模式

近日,Microsoft发布了一个补丁程序,以修复 CVE-2020-1181 的Microsoft SharePoint Server版本中的远程代码执行漏洞,此文章更深入地研究了此漏洞的根本原因。

在此补丁程序可用之前,SharePoint Server允许经过身份验证的用户在SharePoint Web应用程序服务帐户的上下文和权限中在服务器上执行任意.NET代码。为了使攻击成功,攻击者应在SharePoint网站上具有“ 添加和自定义页面”权限。但是,SharePoint的默认配置允许经过身份验证的用户创建网站。当他们这样做时,用户将是该网站的所有者,并将拥有所有必要的权限。

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

0x01 漏洞描述

Microsoft SharePoint Server允许用户创建网页,但是为了防止被利用,它对可以在这些页面上显示的组件进行了严格限制。SharePoint服务器以不同的方式处理其“自己的”页面和用户定义的页面。SharePoint的“自有”页面存储在文件系统上,不受所有限制。用户页面存储在数据库中,并且受到限制。其中一些限制包括无法使用代码块或包含文件系统中的文件。他们通常只能使用预定义列表中允许的Web控件。

如果用户通过上传创建新页面,则该页面将照常受到限制。但是,如果新页面是通过SharePoint Web编辑器创建的,则它将被视为受信任的源。这是有道理的,因为SharePoint Web编辑器对可以添加到页面中的组件进行了限制,因此可以在不受限制的模式下安全地运行页面。

发生此漏洞的原因是编辑器允许的一种Web部件类型WikiContentWebpart,并且该Web部件允许包含任意ASP.NET标记。这为攻击者提供了一种以不受限制的方式运行任意ASP.NET标记的途径,从而导致远程执行代码。

0x02 漏洞代码

SharePoint用于SPPageParserFilter阻止所有危险内容,回顾一下如何初始化SPPageParserFilter:

 // Microsoft.SharePoint.ApplicationRuntime.SPPageParserFilter 
 protected override void Initialize() 
 { 
     if (!SPRequestModule.IsExcludedPath(base.VirtualPath, false)) 
     { 
         this._pageParserSettings = SPVirtualFile.GetEffectivePageParserSettings(base.VirtualPath, out this._safeControls, out this._cacheKey, out this._isAppWeb); 
         this._safeModeDefaults = SafeModeSettings.SafeModeDefaults; 
         return; 
     } 
 /* ... */ 
 } 
 // Microsoft.SharePoint.ApplicationRuntime.SPVirtualFile 
 internal static PageParserSettings GetEffectivePageParserSettings(string virtualPath, out SafeControls safeControls, out string cacheKeyParam, out bool isAppWeb) 
 { 
     HttpContext current = HttpContext.Current; 
     SPRequestModuleData requestData = SPVirtualFile.GetRequestData(current, virtualPath, true, true); 
     SPVirtualFile webPartPageData = requestData.GetWebPartPageData(current, virtualPath, true); 
     return webPartPageData.GetEffectivePageParserSettings(current, requestData, out safeControls, out cacheKeyParam, out isAppWeb); 
 } 
 // Microsoft.SharePoint.ApplicationRuntime.SPDatabaseFile 
 internal override PageParserSettings GetEffectivePageParserSettings(HttpContext context, SPRequestModuleData basicRequestData, out SafeControls safeControls, out string cacheKeyParam, out bool isAppWeb) 
 { 
     PageParserSettings pageParserSettings = this.PageParserSettings; 
     isAppWeb = this._isAppWeb; 
     safeControls = null; 
     cacheKeyParam = null; 
     if (pageParserSettings == null) 
     { 
         if (this.IsGhosted) 
         { 
             bool treatAsUnghosted = this.GetTreatAsUnghosted(context, basicRequestData, this.GetDirectDependencies(context, basicRequestData)); 
             if (!treatAsUnghosted) 
             { 
                 treatAsUnghosted = this.GetTreatAsUnghosted(context, basicRequestData, this.GetChildDependencies(context, basicRequestData)); 
             } 
             if (treatAsUnghosted) 
             { 
                 pageParserSettings = PageParserSettings.DefaultSettings; 
             } 
             else if (this._isAppWeb) 
             { 
                 pageParserSettings = PageParserSettings.GhostedAppWebPageDefaultSettings; 
             } 
             else 
             { 
                 pageParserSettings = PageParserSettings.GhostedPageDefaultSettings; 
             } 
         } 
         else 
         { 
             pageParserSettings = PageParserSettings.DefaultSettings; 
         } 
     } 
     if (!pageParserSettings.AllowUnsafeControls) 
     { 
         safeControls = this.SafeControls; 
     } 
     cacheKeyParam = this.GetVirtualPathProviderCacheKey(context, basicRequestData); 
     return pageParserSettings; 
 
 }

如果我们使用SharePoint Web Editor创建页面,则该页面将具有IsGhosted = true并且_isAppWeb将设置为false。请注意,还有一项额外的检查以确保没有较低信任级别的依赖项文件:

 // Microsoft.SharePoint.ApplicationRuntime.SPDatabaseFile 
 private bool GetTreatAsUnghosted(HttpContext context, SPRequestModuleData requestData, System.Collections.ICollection dependencyVirtualPaths) 
 { 
     bool result = false; 
     foreach (string path in dependencyVirtualPaths) 
     { 
         SPDatabaseFile sPDatabaseFile = requestData.GetWebPartPageData(context, path, true) as SPDatabaseFile; 
         if (sPDatabaseFile != null && !sPDatabaseFile.IsGhosted && (sPDatabaseFile.PageParserSettings == null || sPDatabaseFile.PageParserSettings.CompilationMode != CompilationMode.Always)) 
         { 
             result = true; 
             break; 
         } 
     } 
     return result; 
 }

但是,我们尚未添加任何此类文件,因此应该在这里通过并通过此检查。结果,GetEffectivePageParserSettings()将返回PageParserSettings.GhostedPageDefaultSettings:

 // Microsoft.SharePoint.ApplicationRuntime.PageParserSettings 
 internal static PageParserSettings GhostedPageDefaultSettings 
 { 
     get 
     { 
         if (PageParserSettings.s_ghostedPageDefaultSettings == null) 
         { 
             PageParserSettings.s_ghostedPageDefaultSettings = new PageParserSettings(CompilationMode.Always, true, true); 
         } 
         return PageParserSettings.s_ghostedPageDefaultSettings; 
     } 
 } 
 // Microsoft.SharePoint.ApplicationRuntime.PageParserSettings 
 internal PageParserSettings(CompilationMode compilationmode, bool allowServerSideScript, bool allowUnsafeControls) 
 { 
     this.m_compilationMode = compilationmode; 
     this.m_allowServerSideScript = allowServerSideScript; 
     this.m_allowUnsafeControls = allowUnsafeControls; 
 
 }

其结果是,我们的页面都会有compilationmode=Always,allowServerSideScript=true和allowUnsafeControls=true。现在让我们仔细看看WikiContentWebpart:

 // Microsoft.SharePoint.WebPartPages.WikiContentWebpart 
 protected override void CreateChildControls() 
 { 
     if (!this.Visible || this.Page == null) 
     { 
         return; 
     } 
     if (this.Page.AppRelativeVirtualPath == null) 
     { 
         this.Page.AppRelativeVirtualPath = "~/current.aspx"; 
     } 
     Control obj = this.Page.ParseControl(this.Directive + this.Content, false); 
     this.AddParsedSubObject(obj); 
 }

这意味着其参数(Directive和Content)中的内容将由ParseControl(text2, false)解析。第二个参数(false)将强制使用PageParserFilter,但将与PageParserSettings.GhostedPageDefaultSettings一起使用。

因为该ParseControl()方法永远不会被编译,所以我们不能直接指定.NET代码。但是,我们可以在SharePoint中使用危险控件来调用任意方法并执行代码。WikiContentWebpart是将运行任意OS命令的配置示例:

image.png

0x03 漏洞验证

在我们的演示中,我们使用了Microsoft SharePoint 2019 Server,并在Windows Server 2019 Datacenter版系统上安装了所有默认选项。我们为其分配了名称sp2019.contoso.lab,并使其成为contoso.lab域的成员。我们的域控制器位于单独的虚拟机上。到2020年2月,我们的目标计算机已安装了所有可用的补丁程序,其版本为16.0.10355.20000。

我们的攻击者系统仅需要任何受支持的Web浏览器。在下面的截图中,我们使用了Mozilla Firefox 69.0.3。我们还将使用类似于上面示例的WikiContentWebpart自定义,将其命名为 WikiContentRCE.xml 。

访问我们的SharePoint Server并以普通用户身份进行身份验证。在此示例中,它是 user2 :

image.png

image.png

创建一个站点,以便成为所有者并拥有完全权限。

点击顶部面板上的“ SharePoint ”:

image.png

点击  “ +创建网站 ”  链接:

image.png

选择  团队站点。现在,我们需要为新站点选择一个名称。在此示例中,它是  testsiteofuser2。

image.png

单击“ 完成 ”,将创建新站点:image.png

现在,我们单击“ 页面” 链接:

image.png

我们需要切换到  经典视图。为此,只需单击左下角的“ 返回经典SharePoint ”链接:

image.png

单击“ +新建 ”,然后为我们的新页面选择任何名称。在此示例中,我们将其称为  newpage1:

image.png

单击  创建  按钮进行确认。

image.png

现在我们需要 在“ 插入”  选项卡上选择“  Web部件 ”  :

image.png

在对话框窗口中,选择左下角的“ Upload Web Part ”链接,然后上传精心制作的  WikiContentRCE.xml文件:

image.png

点击  上传。你可能会收到一个弹出警告,指出:“ 此页面要求你确认要离开-输入的数据可能不会保存。” 只需单击“ 离开页面 ”按钮进行确认。然后,我们返回到主编辑视图:

image.png

我们需要 再次 在INSERT选项卡上选择  Web部件小部件  。它将具有我们导入的精心制作的Web部件:

image.png

在单击“  添加”  按钮之前,让我们转到目标SharePoint服务器并打开  C: windows temp  文件夹:

image.png

请注意,没有  RCE_PoC.txt 文件。

现在,让我们回到攻击者机器上,并将导入的Web部件添加到页面中:

image.png

再次检查目标服务器上的  C: windows temp文件夹:

image.png

这样,我们的攻击者可以执行任何OS命令并破坏服务器。他们只需要用echo pwned > c:/windows/temp/RCE_PoC.txt所需的命令替换WikiContentRCE.xml文件中的字符串。

0x04 分析总结

Microsoft在其补丁程序文档中将此漏洞的漏洞利用指数(XI)分级为2,这意味着他们认为不太可能利用此漏洞。但是,正如我们在PoC部分中所展示的那样,对于任何经过身份验证的用户而言,利用此漏洞都是非常简单的。因此,我们建议将XI视为1,这表明有可能被利用。根据Microsoft的说法,他们通过“更正Microsoft SharePoint Server处理已创建内容的方式”修补了该漏洞。在这种情况下,这似乎是一条合理的途径。SharePoint仍然是研究人员和攻击者的有吸引力的目标,并且我们即将发布的一些与SharePoint相关的漏洞披露。

本文翻译自:https://www.zerodayinitiative.com/blog/2020/6/16/cve-2020-1181-sharepoint-remote-code-execution-through-web-parts如若转载,请注明原文地址

本文来源于互联网

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2020年7月30日11:45:20
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   对通过 Web API 触发的 SharePoint RCE 漏洞的分析https://cn-sec.com/archives/78630.html

发表评论

匿名网友 填写信息