内容简介:0x00 漏洞概况 漏洞编号:CVE-2018-1260 漏洞等级:严重 漏洞描述:在Spring Security OAuth 2.x老的版本中,恶意用户可以向授权服务器发起授权请求,当转发至授权审批终端(Approval Endpoint)时,会导致远程代码执行漏洞的攻击。攻击发生需要满足的条件:
0x00 漏洞概况 漏洞编号:CVE-2018-1260 漏洞等级:严重 漏洞描述:
在Spring Security OAuth 2.x老的版本中,恶意用户可以向授权服务器发起授权请求,当转发至授权审批终端(Approval Endpoint)时,会导致远程代码执行漏洞的攻击。
攻击发生需要满足的条件:
1.被攻击端作为授权服务器时(如使用了@EnableAuthorizationServer注解)
2.使用了默认审批终端,或重写的审批终端逻辑中使用SpelExpressionParser等对输出内容进行SPEL表达式解析
3.未配置Scopes
受影响版本:
1.Spring Security OAuth 2.3到2.3.2
2.Spring Security OAuth 2.2到2.2.1
3.Spring Security OAuth 2.1到2.1.1
4.Spring Security OAuth 2.0到2.0.14
5.已经停止支持的老版本
修复建议:
1.Spring Security OAuth 2.3.x升级到2.3.3
2.Spring Security OAuth 2.2.x升级到2.2.2
3.Spring Security OAuth 2.1.x升级到2.1.2
4.Spring Security OAuth 2.0.x升级到2.0.15
5.其他或更早期版本升级到相关支持的分支版本
0x01 漏洞分析
通过对漏洞描述的理解,我们可以猜测漏洞触发点应该在Approval Endpoint附近。
对比修复前后两个版本:
分析其中的提交信息和有变更的文件名,可以很快定位到漏洞相关信息的Commit。
修改代码比较多,就不贴图了。核心的修改内容是在WhitelabelApprovalEndpoint中使用直接生成HTML字符串(调用了HtmlUtils.htmlEscape()对用户可控的输出值进行URL编码)代替了原来使用SpelView解析模板的方式,并且彻底删除了SpelView。
“Endpoint”、“SpelView”这些关键字,有没有让你想起Spring Security OAuth以前的一个RCE?没错,就是CVE-2016-4977。不太了解的同学可以去回顾回顾
同时,官方也在修复版本中增加了一个对这个漏洞的测试用例,贴心的把控制点和PoC都告诉我们了。
赶紧搭个环境看看。
环境搭建
结合补丁对比分析得到的结论,我们可以搭建两种环境帮助对漏洞的理解和分析:
1.spring-security-oauth源码调试环境
需要对Spring Security和Spring Security OAuth框架有一定的了解(原理和执行流程)
2.spring-security-oauth示例项目环境
参考先知上的另一篇分析文章
本文使用第一种:
IDE:IDEA
JDK:1.8
Project:spring-security-oauth-2.2.1.RELEASE
在WhitelabelErrorEndpointTests的测试集中增加2.2.2.RELEASE新增的测试用例,关键代码如下:
parameters.put("client_id", "client"); HashMap<String, Object> model = new HashMap<String, Object>(); model.put("authorizationRequest", createFromParameters(parameters)); model.put("scopes", Collections.singletonMap("${T(java.lang.Runtime).getRuntime().exec("calc")}", "true")); ModelAndView result = endpoint.getAccessConfirmation(model, request); result.getView().render(result.getModel(), request , response);
流程跟踪
调用WhitelabelErrorEndpoint.getAccessConfirmation(),传入携带scopes键值对(我们的PoC在里面)的model。createTemplate()在创建页面模板时,会判断是否存在scopes,是则调用createScopes()将其值转换为HTML字符串,并替换模板中的%scopes%关键字。
在返回ModelAndView前,用模板字符串创建了一个SpelView:
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); Object value = expression.getValue(context); return value == null ? null : value.toString(); } }; }
resolver实现了PlaceholderResolver.resolvePlaceholder(),在其中对传入的参数进行SPEL表达式解析。
回到测试用例,调用SpelView.render()对传入的model进行渲染,渲染什么?其实就是递归查找模板字符串中所有的SPEL表达式,并调用PlaceholderResolver.resolvePlaceholder()解析得到它的值。
好的,重点来了。
当解析到我们传入的T(java.lang.Runtime).getRuntime().exec(\"calc\")时,计算器自然也就弹出来了。 一些你可能不太感兴趣的小细节 关于CVE-2016-4977的补丁
为什么CVE-2016-4977的补丁对这个漏洞没有效果?
我们先回顾一下CVE-2016-4977的大致细节。
为了修复CVE-2016-4977,Spring Security OAuth在2.0.10.RELEASE及之后版本的SpelView中,将模板字符串内所有的${}替换成了[6位随机字符串]{}(详见CVE-2016-4977补丁),并将其作为SPEL表达式标识符,提取其包裹的字符串(CVE-2016-4977中是errorSummary)进行解析。
当递归解析到内部${}字符串(即恶意用户传入PoC部分)时,由于此时用于识别SPEL表达式的标识符已经不是${}了,且6位字符串的随机性也使得用户无法猜测其当前值,所以恶意用户传入的数据无法再被当成SPEL表达式来执行。
也可以这么说,CVE-2016-4977的补丁主要用于防止SpelView中任何递归形式的表达式的解析被恶意利用。
而在这个漏洞中,PoC内容被直接拼接进模板字符串中被解析,所以不受6位随机字符串的影响。
Spring官方一气之下,把SpelView给删了。
<html> <body> <h1>OAuth Approval</h1> <p>Do you authorize 'xJPRnj{authorizationRequest.clientId}' to access your protected resources?</p> <form id='confirmationForm' name='confirmationForm' action='xJPRnj{path}/oauth/authorize' method='post'> <input name='user_oauth_approval' value='true' type='hidden'/> <ul> <li> <div class='form-group'> xJPRnj{T(java.lang.Runtime).getRuntime().exec("calc")}: <input type='radio' name='xJPRnj{T(java.lang.Runtime).getRuntime().exec("calc")}' value='true' checked>Approve</input> <input type='radio' name='xJPRnj{T(java.lang.Runtime).getRuntime().exec("calc")}' value='false'>Deny</input> </div> </li> </ul> <label><input name='authorize' value='Authorize' type='submit'/></label> </form> </body> </html>
一个被连续执行三次的RCE
由于每个Scope会被解析成一个包含两个成组的radioHTML元素,所以在解析之前,模板字符串是长成这样的:
看到了什么?是的,两个radio的name属性值也变成了我们的PoC,所以在运行完测试用例之后,会弹出三个计算器。
另外,Scopes是一个集合,因此理论上我们也可以一次传入多个SPEL表达式:
HashMap<String, Object> scopes = new HashMap<String, Object>();
scopes.put("${T(java.lang.Runtime).getRuntime().exec(\"calc\")}", "true");
scopes.put("${T(java.lang.Runtime).getRuntime().exec(\"calc.exe\")}", "false");
model.put("scopes", scopes);
这次是六个计算器。
Web应用环境中的Scopes值
分析到这里,对于不太了解Spring Security OAuth的同学,会有一个疑问,这个漏洞到底怎么利用?
虽然WhitelabelApprovalEndpoint.getAccessConfirmation()配置了@RequestMapping()注解,可以直接访问/oauth/confirm_access直接进入该方法,但方法中判断并获取scopes是通过model.get()或request.getAttribute(),无法通过URL的请求参数对其传参赋值。
简单介绍一下其相关流程。
1.当客户端向授权服务器发起授权请求时(/oauth/authorize),会将请求参数中scope的值转换为Set集合封装进AuthorizationRequest中,校验应用配置的Scopes是否为空或所有Scope都有效
2.授权服务器内部重定向请求至/oauth/confirm_access,之后的事就不用再多说了吧
因此可以这样请求:
需要注意的是,/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
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 漏洞分析:OpenSSH用户枚举漏洞(CVE-2018-15473)分析
- 【漏洞分析】CouchDB漏洞(CVE–2017–12635, CVE–2017–12636)分析
- 【漏洞分析】lighttpd域处理拒绝服务漏洞环境从复现到分析
- 漏洞分析:对CVE-2018-8587(Microsoft Outlook)漏洞的深入分析
- 路由器漏洞挖掘之 DIR-815 栈溢出漏洞分析
- Weblogic IIOP反序列化漏洞(CVE-2020-2551) 漏洞分析
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
高性能JavaScript
【美】Nicholas C. Zakas(尼古拉斯.泽卡斯) / 丁琛 / 电子工业出版社 / 2015-8-1 / 65
如果你使用 JavaScript 构建交互丰富的 Web 应用,那么 JavaScript 代码可能是造成你的Web应用速度变慢的主要原因。《高性能JavaScript》揭示的技术和策略能帮助你在开发过程中消除性能瓶颈。你将会了解如何提升各方面的性能,包括代码的加载、运行、DOM 交互、页面生存周期等。雅虎的前端工程师 Nicholas C. Zakas 和其他五位 JavaScript 专家介绍......一起来看看 《高性能JavaScript》 这本书的介绍吧!
html转js在线工具
html转js在线工具
RGB CMYK 转换工具
RGB CMYK 互转工具