Shiro权限绕过4
Shiro漏洞复盘系列--1.6.0版本以下的权限绕过复现分析。(CVE-2020-13933)
# 简介
影响版本:shiro < 1.6.0
限制条件:
- 匹配非固定路由,比如
/admin/{name}
# 配置
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>1.5.3</version>
</dependency>
@Bean
ShiroFilterFactoryBean shiroFilterFactoryBean() {
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
bean.setSecurityManager(securityManager());
// 配置认证权限
bean.setLoginUrl("/login");
HashMap<String, String> map = new HashMap<>();
map.put("/login", "anon");
map.put("/user", "anon");
map.put("/admin/*", "authc");
bean.setFilterChainDefinitionMap(map);
return bean;
}
@ResponseBody
@RequestMapping("/admin/{name}")
public String admin(String name) {
return "hello admin";
}
# 分析
正常访问/admin/auth
,被shiro拦截:
访问/admin/%3bauth
,绕过shiro拦截:
# shiro
来看shiro对于URL处理的部分,跟入getServletPath
:
URL会先被URLdecode一次:
%3b --> ;
,然后进入shiro的;
号截断过程:
之后会判断处理的结果是否以/
结尾,如是,则去之:
之后会进入URL和pattern的匹配逻辑中:
/admin/*
无法匹配/amdin
,所以就导致了shiro的权限绕过:
# Spring
来到Spring的部分,org.springframework.web.util.UrlPathHelper#getLookupPathForRequest
:
跟进getPathWithinServletMapping
方法:
再跟进getPathWithinApplication
方法,再跟进其中的getRequestUri
:
在decodeAndClenUriString
方法中会进行URL的处理:
这三个方法的具体逻辑不再赘述,之前的文章就已经分析过了,由于此时的URL中为%3b
,是经过URL编码的;
号,所以在removeSemicolonContent
方法中并不会被截断,之后在decodeRequestString
中进行URLdeocde:
最后getPathWithinServletMapping
方法的最终返回值就为/admin/;auth
:
由于Map设置为/admin/{name}
,那么此时的/admin/;auth
就可以匹配该规则({name}
就为;auth
),然后获取到对应的Controller
,请求被Spring正常处理:
如果这样来看,如果Spring的路由设置方式为固定路由的话(比如/admin/auth
),则无法进行匹配,最终会返回404。
# 修复
shiro层会将URL先进行decode,然后进入分号截断;Spring层会先将URL进行分号截断,之后再进行deocde,正是两者的这个差异导致的漏洞的发生。
可以通过修改匹配规则,比如
/admin/**
来解决shiro1.6.0的解决方案是增加了一个类
InvalidRequestFilter
来对;
号进行拦截:但是我本地使用shiro1.6.0版本测试的时候发现%3b仍然可以绕过(待解决):
- 02
- CommonsBeanUtils04-19
- 03
- 基于Tomcat全局存储进行回显04-16