Apache Shiro权限绕过漏洞分析(CVE-2020-11989)

Apache Shiro作为常用的Java安全框架,拥有执行身份验证、授权、密码和会话管理等功能,通常会和Spring等框架一起搭配使用来开发Web应用。最近研究Shiro本来是为SCTF出题做准备,但在测试过程中却发现了一些新的缺陷能导致权限绕过,便报告给Apache Shiro官方。玄武实验室安全研究人员也单独发现了另外一种绕过方式

影响范围

  • Apache Shiro < 1.5.3
  • Spring框架中使用Shiro鉴权

漏洞复现

测试Demo: https://github.com/l3yx/springboot-shiro

权限配置如下,其中/admin下的路由需要登录才能访问

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@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的方式来进行绕过了。

处理时间线

  • 2020-6-18 16:30 边界无限安全研究员淚笑向 Apache Shiro 官方报告漏洞
  • 2020-6-19 00:04 Apache Shiro 开始处理漏洞,issue为SHIRO-782
  • 2020-6-22 22:49 Apache Shiro 发布致谢