2018-09-26 00:00 技术 观点 数据 836 收藏
在这篇文章中,详细地介绍漏洞的发现,并准确显示远程用户从http请求输入的结果如何被评估为OGNL表达式。
在这篇文章中,详细地介绍漏洞的发现,并准确显示远程用户从http请求输入的结果如何被评估为OGNL表达式。
首先,我将简要介绍Struts如何处理http请求。下图所示:
粗略地讲,当Struts的收到一个HTTP请求,它会先使用预配置ActionMapper来构造ActionMapping,其包含诸如namespace,actionName,method和params从请求。这ActionMapping随后被传递到Dispatcher,其中一个ActionProxy和ActionInvocation创建。然后,这些类将工作委托给相应的类Action和Result类来处理请求。这里将通过这个迷宫遵循http请求,并查看请求的各个元素如何最终被评估为OGNL。
从传入开始进行污点跟踪HttpServletRequest,展示它是如何在该namespace领域结束的ActionProxy。除了更清楚地了解namespace属性如何被污染之外,此次查询也将更加通用,并且能够识别其他先前的OGNL注入问题。这次用于污点跟踪的初始查询可以在这里找到。可对自定义数据流库进行了一些改进,并包括通过子类中的各种方法进行跟踪Collections。应该清楚它们CollectionEdges.qll和ExtraEdges.qll库中的文档做了什么。正如你所看到的,通过使用QL库,就可以在查询之间重用和共享代码,这意味着随着时间的推移,事情变得更容易,更容易。
仔细看看这个的各个组成部分DataFlow::Configuration。首先,看一下source,它指定了用户输入的来源。标准QL库提供了一个名为的类RemoteUserInput,它表示可能不受信任的输入。这个类通常适用于通用污点跟踪,它包含来自HttpServletRequest类的各种来源。当狩猎的漏洞就会喜欢把它扩大到包括多个数据源,所以说一下这个的dataflow_extra库:
它基本上将任何看起来像getter作为源的东西,除了getAttribute和getContextPath,通常从服务器端设置。给了这些来源:
对于水槽,上次使用了isOgnlSink。
对于其他流程步骤,使用了如下图所示:
前两个边缘,standardExtraEdges并且collectionsPutEdge是通用边缘用于跟踪集合。使用isTaintedFieldStep。这条边是跟踪这样的情况:
如前所述,如果在分配之前访问受污染的字段,则可能导致虚假结果。所以将其包括在内,因为从查看Struts的体系结构,看到来自http请求的污染数据首先用于创建ActionMapping和ActionProxy,然后在生命周期的后期访问这些对象的污染字段以执行操作。所以这个边缘的假设似乎对考虑的问题有效。
最后,还添加了taintStringFieldFromQualifier优势:
QL数据流库实际上具有相当精确的通过现场分配和访问进行污点跟踪的能力(得益于Anders Schack-Mulligen的辛勤工作)。例如,默认情况下会跟踪此信息:
但是,为了保持跟踪精确,当分析能够找到将污染数据分配给该特定字段的显式分配时,仅认为字段受到污染。这意味着默认情况下来自受污染源的字段可能不被视为污染,例如:
这是一个公平的假设,因为来自源的字段可能并不总是受到污染,例如:
所以需要明确告诉QL什么时候来源的字段应该被认为是污点。然后就可通过taintStringFieldFromQualifier帮助做到这一点。通过使用这个,希望任何字段访问被污染,如果对象本身被污染,只希望它如果字段是字符串类型这样做。这背后的基本原理是使来自源的所有字段访问都受到污染,但是如果因为在源级别,用户输入通常以字符串形式出现,所以只希望在被访问的字段是字符串类型时发生这种情况。这不会限制对源的字段访问。
使用了ToStringSanitizer和MapMethodSanitizer,但扩展它以涵盖所有对象和地图类型,因为已经在Struts中发现了一些这些方法的更多覆盖,给了伪造的结果。该StrutsTestSanitizer排除的代码处于测试代码,并且ognlSanitizers采取的各种消毒剂的方法等callMethod,cleanupActionName并且cleanupMethodName该固定s2-032,s2-033和s2-037考虑。
运行此查询,最后得到了13个结果。
查看数据流路径,便注意到其中许多都经历了一个名为的方法
getValidators:
被污染context在这里用作从缓存中key获取cfgs对象。除非攻击者也可以控制此缓存的内容,否则不太cfgs可能包含任何可能导致OGNL注入的内容。所以就添加一个消毒剂来过滤掉这个结果:
在检查了一些其他路径后,便添加了两个清洁剂来排除不太可能被击中的路径:
在仔细检查代码路径之后排除这些的确切原因,超出了本文的范围。添加这些消毒剂以清理结果后,现在可以得到7个结果与最终查询。点击第一个结果,看到经过几个步骤后,可以登陆了以下getMapping方法DefaultActionMapper:
如前所述,这发生在生命周期的早期阶段,其中ActionMapper使用传入HttpServletRequest来创建ActionMapping。点击几个步骤,进入了parseNameAndNamespace方法:
现在很清楚为什么alwaysSelectFullNamespace必须要使应用程序可以被利用。看看如何namespace在此函数中设置,这是namespace从用户控制的唯一分支uri。
在受到污染的数据之后,还有几个步骤,最终在Dispatcher:
这是Dispatcher创建一个ActionProxy来自的阶段ActionMapping。正如从第584行所看到的那样namespace,从第ActionMapping593行和第593行中可以看出,它用于构造ActionProxy。从现在开始,可以假设一个namespace领域ActionProxy可能会受到污染。在getNamespace路径浏览器中单击下一个后,便看到ActionProxy现在正在使用相应Result的处理请求。
然后namespace在这里进入determineActionURL第86行,然后进入findString第425行,该第425行评估namespace为引擎盖下的OGNL表达式。
刚刚完成了HttpServletRequestStruts 的整个生命周期,甚至没有运行它。此外,通过使用数据流分析,基本上同时查看了许多流路径,并且能够识别不同Struts配置的问题。
路径浏览器的一个警告是,默认情况下,只显示4条路径,因此要查看更多路径和结果,需要过滤掉已经看到的一些结果。为此目的,所以正在查询中包含了一个清洁剂:
将其添加到isBarrier谓词并注释掉相应的行以查看之前未见过的结果。
通过结果列表,可以看到除了CVE-2018-11776中的那些之外,还有其他一些有趣的:
FileUploadInterceptor跟踪Struts漏洞的人应该不陌生。可能是Struts近年来最严重的漏洞,S2-045影响了这个拦截器。
可以看到开始了multiWrapper.getErrors。这里multiWrapper是类的MultiPartRequestWrapper,是它的子类HttpServletRequest。该getErrors方法是一种覆盖方法,用于存储处理请求时发生的任何错误,并且可能包含用户控制的数据。该error对象来源于此,然后被传递到textProvider.getText方法。在几次传递之后,然后将其输入到getDefaultMessage方法中
几步之后,它最终进入了该translateVariables方法
它被评估message为引擎盖下的OGNL表达式。结果仍然存在,因为问题的修复涉及在创建MultiPartRequestWrapper用作源的对象之前清理用户输入。
在这篇文章中,展示了QL如何能够在从传入HttpServletRequest到OGNL评估的所有方式中跟踪Struts中的用户输入。通过在QL中使用数据流库,查询给了7个结果,其中5个对应于过去的真实RCE漏洞。总的来说,该查询发现了这些RCE:s2-008(部分),s2-032,s2-033,s2-037,s2-045,s2-057。
本文内容由 曲速未来 (WarpFuture.com) 安全咨询公司整理编译,转载请注明。 曲速未来提供包括主链安全、交易所安全、交易所钱包安全、DAPP开发安全、智能合约开发安全等相关区块链安全咨询服务。
本文为作者“曲速未来安全区”,原创文章,转载时请保留本声明及附带文章链接。 内容仅供读者参考,并非投资建议,本网站将保留所有法律权益。