Apache Shiro 权限绕过多漏洞分析与教学文档
0x00 前言
Apache Shiro 是一个强大且易用的 Java 安全框架,提供认证、授权、加密和会话管理等功能。本文详细分析 Shiro 框架中的多个权限绕过漏洞(CVE-2010-3863、CVE-2016-6802、CVE-2020-1957、CVE-2020-11989、CVE-2020-13933、CVE-2020-17510、CVE-2020-17523、CVE-2021-41303),从环境搭建到漏洞原理分析,再到修复方案,全面剖析 Shiro 权限绕过漏洞。
0x01 Shiro 基础与流程分析
环境搭建
实现 Shiro 使用需要三个核心模块:
- 创建 Realm 对象(自定义类)
- DefaultWebSecurityManager
- ShiroFilterFactoryBean
核心配置示例:
@Configuration
public class ShiroConfig {
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager) {
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
bean.setSecurityManager(defaultWebSecurityManager);
// 添加Shiro内置过滤器
Map<String, String> filterMap = new LinkedHashMap<>();
filterMap.put("/user/add", "perms[user:add]");
filterMap.put("/user/update", "perms[user:update]");
filterMap.put("/user/*", "authc");
bean.setFilterChainDefinitionMap(filterMap);
bean.setLoginUrl("/toLogin");
bean.setUnauthorizedUrl("/noauth");
return bean;
}
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(UserRealm userRealm) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(userRealm);
return securityManager;
}
@Bean
public UserRealm userRealm() {
return new UserRealm();
}
}
Shiro 认证流程
-
初始化阶段:
ShiroFilterFactoryBean实现FactoryBean接口,Spring 初始化时调用getObject()方法- 创建
FilterChainManager管理过滤链 - 添加默认过滤器(anon、authc、perms等)
- 应用全局属性(loginUrl、successUrl、unauthorizedUrl)
- 加载自定义过滤器规则
-
请求处理阶段:
- Tomcat 收到请求后,调用 Shiro 的
OncePerRequestFilter - 通过
PathMatchingFilterChainResolver.getChain()匹配请求路径与过滤规则 - 使用
AntPathMatcher进行路径匹配 - 执行匹配到的过滤器链
- Tomcat 收到请求后,调用 Shiro 的
关键过滤器类对应关系:
| 过滤器名称 | 对应类 |
|---|---|
| anon | org.apache.shiro.web.filter.authc.AnonymousFilter |
| authc | org.apache.shiro.web.filter.authc.FormAuthenticationFilter |
| perms | org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter |
| roles | org.apache.shiro.web.filter.authz.RolesAuthorizationFilter |
0x02 CVE-2010-3863
漏洞详情
Shiro 在路径控制时未对传入的 URL 编码进行解码,导致攻击者可以绕过过滤器访问被过滤的路径。
影响版本:Shiro <= 1.0.0
环境搭建
pom.xml 配置:
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.0.0-incubating</version>
</dependency>
<!-- 其他shiro组件版本相同 -->
添加测试路由:
filterMap.put("/secret.html", "authc,roles[admin]");
漏洞复现与分析
PoC: /./secret.html
漏洞原理:
- 请求
/./secret.html进入PathMatchingFilterChainResolver.getChain() - Shiro 将路径拆分为
["." , "secret.html"] - 与配置的
/secret.html不匹配 - 最终匹配
/**的匿名访问规则,绕过认证
关键代码路径:
org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver#getChain()
-> pathMatches()
-> org.apache.shiro.util.AntPathMatcher#doMatch()
修复方案
Shiro 添加了路径标准化函数,处理 /、//、/./、/../ 等特殊路径。
0x03 CVE-2016-6802
漏洞详情
Shiro 未对 ContextPath 做路径标准化导致权限绕过。
影响版本:Shiro < 1.3.2
漏洞复现
PoC: /aa/../drunkbaby/listProduct.jsp
漏洞分析
- 请求进入
WebUtils#getPathWithinApplication() getContextPath()处理不一致:- Shiro 获取的 contextPath 为
/aa/../drunkbaby - 与实际 contextPath
/drunkbaby不匹配
- Shiro 获取的 contextPath 为
- 导致后续路径匹配失败,绕过权限检查
关键代码路径:
org.apache.shiro.web.util.WebUtils#getPathWithinApplication()
-> getContextPath()
-> org.apache.catalina.connector.Request#getContextPath()
修复方案
Shiro 在 1.3.2 版本中对 ContextPath 进行标准化处理:
normalize(decodeRequestString(request, uri))
0x04 CVE-2020-1957 (Shiro682)
漏洞详情
Spring 与 Shiro 对路径结尾 / 处理差异导致权限绕过。
影响版本:Shiro <= 1.5.1
漏洞复现
PoC: /user/add/
漏洞分析
- Shiro 将
/user/add和/user/add/视为不同路径 - Spring 将两者视为相同路径
- 配置
/user/add需要认证,但访问/user/add/可绕过
关键代码对比:
- Shiro 路径匹配:
org.apache.shiro.util.AntPathMatcher#doMatch() - Spring 路径匹配:
org.springframework.web.servlet.mvc.condition.PatternsRequestCondition#getMatchingPatterns()
修复方案
Shiro 1.5.2 版本中:
- 对路径结尾的
/进行统一处理 - 迁就 Spring 的路径处理方式
0x05 CVE-2020-11989
漏洞详情
双层编码绕过,需要特定条件:
- ant 风格配置为
*而非** - Controller 使用
@PathVariable且参数类型为 String
影响版本:Shiro < 1.5.3
漏洞复现
PoC: /toJsonList/r%25%32%66oot
漏洞分析
- Shiro 获取的路径:
/toJsonList/r/oot(不匹配/toJsonList/*) - Spring 解码后:
/toJsonList/r%2foot - 导致权限检查绕过
关键点:
org.apache.shiro.web.util.WebUtils#getRequestUri()
-> decodeAndCleanUriString()
修复方案
Shiro 1.5.3 修改路径获取方式:
- 使用
getPathWithinApplication()方法 - 改为
getServletPath(request) + getPathInfo(request)拼接
0x06 CVE-2020-13933
漏洞详情
分号(;)编码绕过,与 CVE-2020-11989 类似但使用 %3b。
影响版本:Shiro < 1.6.0
漏洞复现
PoC: /toJsonList/%3broot
漏洞分析
- Shiro 的
removeSemicolon()移除分号,得到/toJsonList/ - 与配置的
/toJsonList/*不匹配 - Spring 处理时先移除分号再解码,路径有效
修复方案
Shiro 1.6.0 新增全局 InvalidRequestFilter,过滤特殊字符(分号、反斜线、非ASCII字符)。
0x07 CVE-2020-17510
漏洞详情
使用 . 编码(%2e)绕过路径匹配。
影响版本:Shiro < 1.7.0
漏洞复现
PoC: /toJsonList/%2e
漏洞分析
- Shiro 解码后路径:
/toJsonList/. - 标准化后:
/toJsonList/ - 与
/toJsonList/*不匹配,绕过检查
修复方案
Shiro 1.7.0 新增 ShiroUrlPathHelper 类,重写路径处理方法。
0x08 CVE-2020-17523
漏洞详情
CVE-2020-17510 修复后的绕过,使用空格(%20)。
影响版本:Shiro < 1.7.1
漏洞复现
PoC: /toJsonList/%20
修复方案
Shiro 1.7.1 修改 AntPathMatcher 的 tokenizeToStringArray 方法参数。
0x09 CVE-2021-41303
漏洞详情
特定配置下路径匹配逻辑问题导致绕过。
影响版本:Shiro = 1.7.1
漏洞复现
配置:
filterMap.put("/toJsonList/*", "authc");
filterMap.put("/toJsonList/index", "authc");
Controller:
@GetMapping("/toJsonList/{name}/index")
public String namePage(@PathVariable String name) {
return name;
}
PoC: /toJsonList/xxx/index
漏洞分析
- Shiro 1.7.1 路径匹配逻辑变更:
- 先比较 pathPattern 和 requestURI
- 不匹配则比较去除尾部斜线的版本
- 导致特定配置下绕过
修复方案
Shiro 1.8.0 修改 filterChainManager.proxy 参数传递方式。
0x10 总结
Shiro 权限绕过漏洞主要成因:
- 路径处理不一致(Shiro 与 Spring/Tomcat)
- 编码解码顺序问题
- 特殊字符处理差异
- 路径标准化不完善
防护建议:
- 及时升级 Shiro 到最新版本
- 统一路径处理逻辑
- 严格校验特殊字符
- 采用最小权限原则配置
通过分析这些漏洞,可以深入理解 Shiro 的安全机制和常见问题,为安全开发和审计提供参考。