Shiro权限绕过1
Shiro漏洞复盘系列--1.5.0版本以下的权限绕过复现分析。(无CVE编号)
# 简介
影响版本:shiro < 1.5.0
# 配置
依赖:
<!-- shiro dependence -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>1.4.2</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.2</version>
</dependency>
shiro配置:
@Configuration
public class shiroConfig {
@Bean
Auth auth() {
return new Auth();
}
@Bean
SecurityManager securityManager() {
DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
manager.setRealm(auth());
return manager;
}
@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;
}
}
# 分析
正常访问/admin路由,因为过滤器的配置,所以会302跳转到/login路由下:

在/admin路由后面加/,访问/admin/路由,发现可以绕过shiro的鉴权:

# shiro
shiro处理URL从而进行匹配的方法为org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver#getChain,打下断点,发送请求:

在获取到请求的URL之后,会进入到pathMatches方法中进行匹配:

连续跟进到doMatch方法中:

return pattern.endsWith(this.pathSeparator) ? path.endsWith(this.pathSeparator) : !path.endsWith(this.pathSeparator);
在这一行中,pattern为/admin,pathSeparator为/,path为/admin/,所以返回的!path.endsWith(this.pathSeparator)就为false,shiro就认为没有匹配到对应路由,绕过了shiro的权限验证。
# Spring
Spring处理URL的逻辑在org.springframework.web.util.UrlPathHelper#getLookupPathForRequest方法中:
public String getLookupPathForRequest(HttpServletRequest request) {
String pathWithinApp = this.getPathWithinApplication(request);
if (!this.alwaysUseFullPath && !this.skipServletPathDetermination(request)) {
String rest = this.getPathWithinServletMapping(request, pathWithinApp);
return StringUtils.hasLength(rest) ? rest : pathWithinApp;
} else {
return pathWithinApp;
}
}
获取到请求路径之后并返回到getHandlerInternal方法中,进入lookupHandlerMethod中寻找HandlerMethod:


跟进该方法,在获取到mappingRegistry之后会在map中尝试获取路由:

this.pathLookup中储存了我们配置的三个路由和另外一个/error路由,调用get方法尝试匹配我们的请求路径:

获取的结果为null,之后会调用addMatchingMappings方法,便利mappingRegistry中的每一个map进行匹配:

主要匹配的逻辑是在getMatchingMapping方法中:

接着跟进到getMatchingCondition方法中,再跟入this.patternsCondition.getMatchingCondition(request):

获取到lookupPath之后再跟入getMatchingPatterns方法:

再跟入getMatingPattern方法:

这个方法最后的返回值如下:
return this.useTrailingSlashMatch && !pattern.endsWith("/") && this.pathMatcher.match(pattern + "/", lookupPath) ? pattern + "/" : null;
会在pattern(/admin)后加一个/:

逐层返回,获取到对应的hanlderMethod,spring处的URL匹配成功:

# 修复
通过diff一下新版本的代码,可以发现shiro对于此漏洞的修复方案是对URL和匹配的pattern的末尾做了去/号的处理。

下篇文章将会复现分析 shiro < 1.5.2 版本下的权限绕过问题。
- 02
- CommonsBeanUtils04-19
- 03
- 基于Tomcat全局存储进行回显04-16