Shiro相关漏洞研究
简介
Apache Shiro 是 Java 的一个安全框架。目前,使用 Apache Shiro 的人越来越多,因为它相当简单,对比 Spring Security,可能没有 Spring Security 做的功能强大,但是在实际工作时可能并不需要那么复杂的东西,所以使用小而简单的 Shiro 就足够了。对于它俩到底哪个好,这个不必纠结,能更简单的解决项目问题就好了。
从shiro基础知识聊起
Apache Shiro 是一个 Java 安全框架,包括如下功能和特性:
- Authentication:身份认证/登陆,验证用户是不是拥有相应的身份。在 Shiro 中,所有的操作都是基于当前正在执行的用户,这里称之为一个
Subject
,在用户任意代码位置都可以轻易取到这个Subject
。Shiro 支持数据源,称之为Realms
,可以利用其连接 LDAP\AD\JDBC 等安全数据源,并支持使用自定义的Realms
,并可以同时使用一个或多个Realms
对一个用户进行认证,认证过程可以使用配置文件配置,无需修改代码。同时,Shiro 还支持 RememberMe,记住后下次访问就无需登录。 - Authorization:授权,即权限验证,验证某个已认证的用户是否拥有某个权限。同样基于
Subject
、支持多种Realms
。Shiro 支持Wildcard Permissions
,也就是使用通配符来对权限验证进行建模,使权限配置简单易读。Shiro 支持基于Roles
和基于Permissions
两种方式的验证,可以根据需要进行使用。并且支持缓存产品的使用。 - Session Manager:会话管理,用户登陆后就是一次会话,在没有退出之前,它的所有信息都在会话中。Shiro 中的一切(包括会话和会话管理的所有方面)都是基于接口的,并使用 POJO 实现,因此可以使用任何与 JavaBeans 兼容的配置格式(如 JSON、YAML、Spring XML 或类似机制)轻松配置所有会话组件。Session 支持缓存集群的方式;还支持事件侦听器,允许在会话的生命周期内侦听生命周期事件,以执行相关逻辑。Shiro Sessions 保留发起会话的主机的 IP 地址,因此可以根据用户位置来执行不同逻辑。Shiro 对 Web 支持实现了
HttpSession
类及相关全部 API。也可以在 SSO 中使用。 - Cryptography:加密,保护数据的安全性;Shiro 专注于使用公私钥对数据进行加密,以及对密码等数据进行不可逆的哈希。
- Permissions:用户权限;Shiro 将所有的操作都抽象为 Permission,并默认使用
Wildcard Permissions
来进行匹配。Shiro 支持实例级别的权限控制校验,例如domain:action:instance
。 - Caching:缓存,为了提高 Shiro 在业务中的性能表现。Shiro 的缓存支持基本上是一个封装的 API,由用户自行选择底层的缓存方式。缓存中有三个重要的接口
CacheManager
/Cache
/CacheManagerAware
,Shiro 提供了默认的MemoryConstrainedCacheManager
等实现。
架构
官方用例分析
现从下一份示例代码看看
https://github.com/apache/shiro
自带session功能
接着往下看看权限部分
分为粗粒度和细粒度
整合springboot
在三梦师傅的复现环境上改的
可以看到 对应上面架构图中的三个部分
漏洞复现
CVE-2020-1957
配置
1 | map.put("/admin/list","authc,roles[admin]"); |
bypass
1 | /aaaaa/..;/admin/list |
绕过的原理就是访问 /aaaadawdadaws;/..;wdadwadadw/;awdwadwa/audit/list
这个请求的时候会被 shiro 和 spring 解析成不同的结果
看一下shiro的处理方式
跟进
这里是 直接截断;
(59ascii 是 ;
)
spring呢?
跟进 UrlPathHelper#removeSemicolonContent
su18师傅的原文:
可以看到,spring 处理了每个 / / 之间的分号,均把 “;” 及之后的内容截取掉了。所以当请求
/aaaadawdadaws;/..;wdadwadadw/;awdwadwa/audit/list
进入到UrlPathHelper#decodeAndCleanUriString
方法时,会逐渐被处理:
- removeSemicolonContent:”/aaaadawdadaws/..//audit/list”
- decodeRequestString:”/aaaadawdadaws/..//audit/list”
- getSanitizedPath:”/aaaadawdadaws/../audit/list”
这样再标准化就会成为正常的 “/audit/list”。
CVE-2021-41303
当以下这样配置时,会出现绕过
1 | map.put("/bypass/*/index", "authc"); |
绕过方法
1 | /bypass/id/index |