首页
学习
活动
专区
圈层
工具
发布

Spring Security OAuth2 RCE漏洞分析

0x00 漏洞概况

漏洞编号:CVE-2018-1260

漏洞等级:严重漏洞描述:

在Spring Security OAuth 2.x老的版本中,恶意用户可以向授权服务器发起授权请求,当转发至授权审批终端(Approval Endpoint)时,会导致远程代码执行漏洞的攻击。

攻击发生需要满足的条件:

被攻击端作为授权服务器时(如使用了注解)

使用了默认审批终端,或重写的审批终端逻辑中使用等对输出内容进行SPEL表达式解析

未配置Scopes

受影响版本:

Spring Security OAuth 2.3到2.3.2

Spring Security OAuth 2.2到2.2.1

Spring Security OAuth 2.1到2.1.1

Spring Security OAuth 2.0到2.0.14

已经停止支持的老版本

修复建议:

Spring Security OAuth 2.3.x升级到2.3.3

Spring Security OAuth 2.2.x升级到2.2.2

Spring Security OAuth 2.1.x升级到2.1.2

Spring Security OAuth 2.0.x升级到2.0.15

其他或更早期版本升级到相关支持的分支版本

0x01 漏洞分析

通过对漏洞描述的理解,我们可以猜测漏洞触发点应该在Approval Endpoint附近。

对比修复前后两个版本:

分析其中的提交信息和有变更的文件名,可以很快定位到漏洞相关信息的Commit。

修改代码比较多,就不贴图了。核心的修改内容是在中使用直接生成HTML字符串(调用了对用户可控的输出值进行URL编码)代替了原来使用解析模板的方式,并且彻底删除了。

“Endpoint”、“SpelView”这些关键字,有没有让你想起Spring Security OAuth以前的一个RCE?没错,就是CVE-2016-4977。不太了解的同学可以去回顾回顾

同时,官方也在修复版本中增加了一个对这个漏洞的测试用例,贴心的把控制点和PoC都告诉我们了。

赶紧搭个环境看看。

环境搭建

结合补丁对比分析得到的结论,我们可以搭建两种环境帮助对漏洞的理解和分析:

spring-security-oauth源码调试环境

需要对Spring Security和Spring Security OAuth框架有一定的了解(原理和执行流程)

spring-security-oauth示例项目环境

参考先知上的另一篇分析文章

本文使用第一种:

IDE:IDEA

JDK:1.8

Project:spring-security-oauth-2.2.1.RELEASE

在的测试集中增加2.2.2.RELEASE新增的测试用例,关键代码如下:

流程跟踪

调用,传入携带键值对(我们的PoC在里面)的。在创建页面模板时,会判断是否存在,是则调用将其值转换为HTML字符串,并替换模板中的关键字。

在返回前,用模板字符串创建了一个:

实现了,在其中对传入的参数进行SPEL表达式解析。

回到测试用例,调用对传入的进行渲染,渲染什么?其实就是递归查找模板字符串中所有的SPEL表达式,并调用解析得到它的值。

好的,重点来了。

当解析到我们传入的时,计算器自然也就弹出来了。

一些你可能不太感兴趣的小细节

关于CVE-2016-4977的补丁

为什么CVE-2016-4977的补丁对这个漏洞没有效果?

我们先回顾一下CVE-2016-4977的大致细节。

为了修复CVE-2016-4977,Spring Security OAuth在2.0.10.RELEASE及之后版本的中,将模板字符串内所有的替换成了(详见CVE-2016-4977补丁),并将其作为SPEL表达式标识符,提取其包裹的字符串(CVE-2016-4977中是)进行解析。

当递归解析到内部字符串(即恶意用户传入PoC部分)时,由于此时用于识别SPEL表达式的标识符已经不是了,且6位字符串的随机性也使得用户无法猜测其当前值,所以恶意用户传入的数据无法再被当成SPEL表达式来执行。

也可以这么说,CVE-2016-4977的补丁主要用于防止中任何递归形式的表达式的解析被恶意利用。

而在这个漏洞中,PoC内容被直接拼接进模板字符串中被解析,所以不受6位随机字符串的影响。

Spring官方一气之下,把给删了。

一个被连续执行三次的RCE

由于每个Scope会被解析成一个包含两个成组的HTML元素,所以在解析之前,模板字符串是长成这样的:

看到了什么?是的,两个的属性值也变成了我们的PoC,所以在运行完测试用例之后,会弹出三个计算器。

另外,Scopes是一个集合,因此理论上我们也可以一次传入多个SPEL表达式:

HashMap scopes =newHashMap();

scopes.put("$","true");

scopes.put("$","false");

model.put("scopes", scopes);

这次是六个计算器。

Web应用环境中的Scopes值

分析到这里,对于不太了解Spring Security OAuth的同学,会有一个疑问,这个漏洞到底怎么利用?

虽然配置了注解,可以直接访问/oauth/confirm_access直接进入该方法,但方法中判断并获取scopes是通过或,无法通过URL的请求参数对其传参赋值。

简单介绍一下其相关流程。

当客户端向授权服务器发起授权请求时(/oauth/authorize),会将请求参数中的值转换为集合封装进中,校验应用配置的Scopes是否为空或所有Scope都有效

授权服务器内部重定向请求至/oauth/confirm_access,之后的事就不用再多说了吧

因此可以这样请求:

http://domain.com/oauth/authorize?client_id=[id]&response_type=[type]&scope=%24%7BT%28java.lang.Runtime%29.getRuntime%28%29.exec%28%22calc%22%29%7D&redirect_uri=[uri]

需要注意的是,/oauth/authorize和/oauth/confirm_access默认都有认证保护

参考

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

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

http://secalert.net/#CVE-2016-4977

  • 发表于:
  • 原文链接:http://kuaibao.qq.com/s/20180514G07E2Y00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。
领券