Apache Shiro 作为常用的 Java 安全框架,拥有执行身份验证、授权、密码和会话管理等功能,通常会和 Spring 等框架一起搭配使用来开发 Web 应用。笔者最近捣鼓 Shiro 本来是打算参考最近 Shiro 的一些 issue 然后为 SCTF 出题的,但在测试过程中却发现了一些新的缺陷能导致权限绕过,便报告给 Apache Shiro 官方。在此同时玄武实验室安全研究人员也单独发现了另外一种绕过方式,具体可见参考链接。
影响范围
Apache Shiro < 1.5.3
Spring 框架中只使用 Shiro 鉴权
测试 Demo :
https://github.com/l3yx/springboot-shiro
权限配置如下,其中 /admin 下的路由需要登录才能访问
@Bean
ShiroFilterFactoryBean shiroFilterFactoryBean(){
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
bean.setSecurityManager(securityManager());
bean.setLoginUrl("/login");
bean.setSuccessUrl("/index");
bean.setUnauthorizedUrl("/unauthorizedurl");
Map<String, String> map = new LinkedHashMap<>();
map.put("/doLogin", "anon");
map.put("/admin/*", "authc");
bean.setFilterChainDefinitionMap(map);
return bean;
}
---
@GetMapping("/admin/page")
public String admin() {
return "admin page";
}
maven 打包项目为 test.war ,部署于 Tomcat 。该漏洞成功利用存在下面两个条件
1.应用不能部署在根目录,也就是需要 context-path , server.servlet.context-path=/test ,如果为根目录则 context-path 为空,就会被 CVE-2020-1957 的 patch 将 URL 格式化,值得注意的是若 Shiro 版本小于 1.5.2 的话那么该条件就不需要。
2. Spring 控制器中没有另外的权限校验代码
如果直接访问 /test/admin/page ,会返回302跳转要求登录
但是访问/;/test/admin/page , 就能直接绕过 Shiro 权限验证,访问到 /admin 路由中的信息
由于Shiro的权限校验是通过判断 URL 匹配来做的,如果能找到 Shiro 获取的 URL 与 Web 框架处理 URL 不一致的情况就能造成权限绕过。 Shiro 中对于 URL 的获取及匹配在
org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver#getChain
以访问 /;/test/admin/page 举例,通过 getPathWithinApplication 函数得到的路径为 /
跟入该函数的处理逻辑 org.apache.shiro.web.util.WebUtils#getPathWithinApplication
可以看到 org.apache.shiro.web.util.WebUtils#getRequestUri 获取到的是 /
这里分别通过 getContextPath() getServletPath() getPathInfo() 获取并拼接得到 /;/test//admin/page ,传入后 decodeAndCleanUriString 变成了 / , org.apache.shiro.web.util.WebUtils#decodeAndCleanUriString
在 decodeAndCleanUriString ,会根据 Ascii 为 59 的字符也就是 ; 进行 URL 的截断,所以最终返回了 /
回到最开始的 /;/test/admin/page 请求,该 request 请求会进入 Spring 中, Spring 处理 URL 函数如下 org.springframework.web.util.UrlPathHelper#getPathWithinServletMapping
在 getPathWithinApplication 处理下是能正确获取到 context-path 与路由,最终经过 getPathWithinServletMapping 函数格式化处理后,得到最终路径为 /admin/page ,所以我们可以正常访问到该页面
因此总结来说就是当 URL 进入到 Tomcat 时, Tomcat 判断 /;test/admin/page 为 test 应用下的 /admin/page 路由,进入到 Shiro 时被 ; 截断被认作为 / ,再进入 Spring 时又被正确处理为 test 应用下的 /admin/page 路由,最后导致 Shiro 的权限绕过。
Shiro 1.5.3 修改了 URL 获取的逻辑,不单独处理 context-path ,具体代码如下所示 org.apache.shiro.web.util.WebUtils#getPathWithinApplication
因此就无法再通过构造 context-path 的方式来进行绕过了。
建议组件使用者升级至 Apache Shiro 1.5.3 或更高版本
2020-6-18 16:30 边界无限安全研究员淚笑向 Apache Shiro 官方报告漏洞
2020-6-19 00:04 Apache Shiro 开始处理漏洞,issue 为 SHIRO-782
2020-6-22 22:49 Apache Shiro 发布致谢
https://xlab.tencent.com/cn/2020/06/30/xlab-20-002/