SharePoint站点页面安全性分析

来源:岁月联盟 编辑:猪蛋儿 时间:2020-03-16

如果大家使用过SharePoint,那么应该会对两种ASPX页面比较熟悉:
应用程序(Application)页面
站点(Site)页面
应用程序页面无法自定义,这类页面存放在文件系统中,负责基础性任务。比如/_layouts/[version]/settings.aspx文件就是一个典型的应用程序页面,负责各种站点设置。这些文件经过.NET Framework编译。
在SharePoint站点中,管理员可以自定义站点页面,这类页面存放在数据库中(未编辑的站点页面可以存放在文件系统中,可以进行编译)。默认情况下,每个SharePoint站点中都存在一些站点页面,这些页面在未编辑时也可以称为“Ghost页面”(Ghost Page)。每个站点都可以自定义这些页面,消除这些页面的“Ghost”状态。该过程将在站点数据库中创建目标页面的副本,以便后续的定制操作。
那么我们(包括SharePoint新手或者有经验的测试人员)自然会提出一个常见的安全性问题:
恶意管理员用户具备站点页面的创建及编辑权限,那么SharePoint如何保护站点安全?毕竟我们面对的是一些动态页面,比如default.aspx,我们能否使用ASPX文件在服务器上执行代码?
答案比较简单:SharePoint会禁止内联代码,也会在非编译模式下解析这些页面。这种安全机制的绕过方法基本上与绕过.NET Framework中的CompilationMode.Never设置相同,因此应该将其当成一个安全问题来处理。
在本次研究中,我们分析了SharePoint如何处理站点页面,也分析了如何绕过当前的缓解机制。这些绕过技术有可能帮助攻击者攻击SharePoint在线服务器,而在目前的漏洞赏金计划中,完成这些任务一般能收获不俗的赏金(大概1.5~2.0万美元)。
在本文中我们尽量使用最简单的示例及术语,没有花太多精力在逆向分析SharePoint或.NET Framework代码上,因此某些定义可能不够完整,但我们会尽力尝试囊括尽可能多的信息,以便在该领域开展后续研究。
 
0x01 CompilationMode
SharePoint使用了一些技术,避免攻击者在非Ghost状态的页面(即自定义页面)中执行代码。
比如,在反编译Microsoft.SharePoint.dll文件后,我们可以在Microsoft.SharePoint/Microsoft/SharePoint/ApplicationRuntime/PageParserSettings.cs类文件中找到如下设置。
CompilationMode.Never
CompilationMode.Never是SharePoint在处理自定义页面时的默认设置。因此,服务器会解析非Ghost ASPX页面,并没有将其编译到DLL中。这种机制实际上可以阻止所有的内联代码及事件处理程序。
另一方面,CompilationMode.Always适用于Ghost页面及应用程序页面。
AllowServerSideScript = False and AllowUnsafeControls = False
这是所有页面的默认设置,可以阻止内联代码,限制页面中可以使用的控件数量。
 
0x02 失败的尝试
我们尝试了许多绕过方法,也有很多方法没有成功,但还是可以提一下这些方法,供后续研究参考。此外,某些技术在某些类似场景下可能会派上用场。
在例外列表中创建不存在的文件或目录
除了应用程序页面及Ghost站点页面外,我们还有可能使用例外列表来运行代码。在默认安装的SharePoint中,例外列表中包含的文件和目录如下所示。
例外目录:
/app_themes
/app_browsers
/_layouts
/_controltemplates
/_wpresources
/_windows
/_vti_bin
/_login
/App_GlobalResources
/bin
/wpresources
/_app_bin
/_vti_pvt
例外文件:
/defaultwsdlhelpgenerator.aspx
/clientaccesspolicy.xml
/crossdomain.xml
/global.asax
/web.config
因此我们首先想到的是将自己的代码插入例外文件或者目录中,比如defaultwsdlhelpgenerator.aspx就是一个理想的目标,该文件并不存在于Web目录中。然而经过测试后,我们无法查看或者编辑创建后的站点页面,服务端会显示一个默认的.NET 404错误消息,这与正常不存在的文件不同。
例外列表中不存在的目录用处不大,不能承载任何文件。在此次研究过程中,我们使用dnSpy调试SharePoint,并没有找到明显的利用点,但后续还是可以研究一下为什么服务端会返回不同的错误消息(有可能这里存在没被人注意到的小细节)。
滥用文本模板指令
一开始我们认为可以使用特定指令(directive)中的某些属性实现绕过,不幸的是这种思路没有成功。服务器允许的指令及属性被列入了白名单中,并且某些有趣的属性也已经被服务端忽略。服务器也能够正确解析来自虚拟路径的嵌入文件,而可能被编译的文件(如XAMLX文件)也无法直接上传到SharePoint。后续我们还是可以继续研究是否有服务端允许的其他属性能够被滥用。
服务端允许的指令如下所示:
page, control, master, mastertype, register, previouspage, previouspagetype, reference, assembly, import, implements
我们可以通过反汇编代码中的Microsoft.SharePoint/Microsoft/SharePoint/ApplicationRuntime/SPPageParserFilter.cs类文件来查看关于服务端允许设置的更多信息。
滥用内联代码、事件或者表达式
尽管服务端阻止了内联代码,但我们不能轻易放弃这一点。如果能够使用内联表达式,这一点我们认为还是可以派上用场。然而经过研究后,我们发现自己需要处理的是.NET Framework的相关设置,而不单单是SharePoint的设置,因此工作量不可同日而语。
内联代码无法使用,是因为服务端能正确解析代码,默认情况下会禁用所有代码块。在这种情况下,服务端还会禁用某些内联表达式。比如,由于存在这种限制,服务端会阻止如下元素:
script runat="server">foobarscript>
script src="test.cs" runat="server">script>
% foobar %>
%= foobar %>
%# foobar %>
虽然如下表达式不会引起任何错误,但也不能用于代码执行:
1、表达式生成器:通常情况下,这种语法类似于。在默认情况下,服务端支持如下表达式生成器:
AppSettings:可以用来读取应用程序设置。然而,SharePoint应用程序设置中并没有嵌入任何私密代码。
ConnectionStrings:如果自定义SharePoint在共享的web.config文件中使用该表达式,那么我们只能使用该表达式来获取连接字符串。

[1] [2] [3]  下一页