导语
Apache ShenYu 是一个异步的,高性能的,跨语言的,响应式的 API 网关。近期VLab监测到其历史版本(2.3.0-2.4.0)中存在登录认证绕过的风险,CVE编号为CVE-2021-37580
本文仅限于对漏洞点进行研究讨论,禁止任何人用于非法途径,所产生的任何非法攻击都与本作者无关,本文会对具体PoC部分进行阉割.请严格遵守《网络安全法》
环境搭建
先从官方仓库克隆一份最新代码到本地,然后切换到相关tag,方便分析漏洞。
git clone https://github.com/apache/incubator-shenyu.git
然后按照官方手册启动ShenyuAdminBootstrap和ShenyuBootstrapApplication即可,(https://shenyu.apache.org/zh/docs/2.4.0/deployment/deployment-local)
漏洞复现
根据CVE-2021-37580描述我们可以知道,该漏洞点在jwt认证的过程中,我看到漏洞描述的第一时间以为是jwt秘钥硬编码导致的漏洞,但是后面分析的时候才发现我格局小了。查看源码可以知道其认证过程使用的是shiro+jwt认证方式。那么直接找到shiro的验证逻辑进行断点即可跟进整个认证登录流程。在shenyu-admin/src/main/java/org/apache/shenyu/admin/shiro/config/ShiroRealm.java中 可以看到两个doGetAuthorizationInfo方法,其中doGetAuthorizationInfo(final PrincipalCollection principalCollection)是用来鉴权使用的,我们先跳过,主要是下面的doGetAuthenticationInfo(final AuthenticationToken authenticationToken),这个方法是用来进行认证的。
从上图我们可以看到整个认证的代码很简单,首先获取到token,然后判断token是否为空,不为空的话接着调用getUserInfoByToken方法获取用户信息实体,然后返回一个SimpleAuthenticationInfo信息,整个逻辑结束,那么用户能不能登录,核心点就是在getUserInfoByToken方法中,下面是getUserInfoByToken的代码片段.
String userName = JwtUtils.getIssuer(token);
上面的代码逻辑也很简单,就是根据token获取用户名,然后用户名不为空的话就从数据库中查找该用户名相对应的用户实体信息,找到后就返回一个UserInfo对象。接着我们看JwtUtils.getIssuer这个方法,可以看到就是简单的decode了下token,然后从里面获取userName相关的信息并且返回。看到这里其实已经发现问题了,在目前看到的逻辑中,没有对token是否有效进行校验。在最新的代码中看其ShiroRealm.java中的代码,发现其已对该漏洞进行了修复。
验证截图
漏洞总结
该漏洞是由于仅仅对token进行了解析,但是并没有对token是否有效进行验证而导致的。在官方修改后的最新版本,作者使用了解析token后获取到用户相关的密码作为了jwt的key,然后对token进行校验是否有效,一举两得的解决了该问题以及jwt秘钥硬编码的会导致的一些安全问题。
修复建议
- 升级到2.4.1以上