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