Shiro相关漏洞研究

简介

Apache Shiro 是 Java 的一个安全框架。目前,使用 Apache Shiro 的人越来越多,因为它相当简单,对比 Spring Security,可能没有 Spring Security 做的功能强大,但是在实际工作时可能并不需要那么复杂的东西,所以使用小而简单的 Shiro 就足够了。对于它俩到底哪个好,这个不必纠结,能更简单的解决项目问题就好了。

从shiro基础知识聊起

img

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 等实现。

架构

img

官方用例分析

现从下一份示例代码看看

https://github.com/apache/shiro

image-20230401164924876

自带session功能

image-20230401165154020

接着往下看看权限部分

image-20230401170038269

分为粗粒度和细粒度

整合springboot

在三梦师傅的复现环境上改的

可以看到 对应上面架构图中的三个部分

image-20230401171037308

漏洞复现

CVE-2020-1957

配置

1
map.put("/admin/list","authc,roles[admin]");

bypass

1
/aaaaa/..;/admin/list

image-20230401215850944

绕过的原理就是访问 /aaaadawdadaws;/..;wdadwadadw/;awdwadwa/audit/list 这个请求的时候会被 shiro 和 spring 解析成不同的结果

看一下shiro的处理方式

image-20230401220744799

跟进

image-20230401220827985

这里是 直接截断; (59ascii 是 ;)

spring呢?

位置 https://github.com/spring-projects/spring-framework/blob/main/spring-web/src/main/java/org/springframework/web/util/UrlPathHelper.java

image-20230401221547896

跟进 UrlPathHelper#removeSemicolonContent

image-20230401221704822

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

https://threedr3am.github.io/2021/09/22/%E4%BB%8E%E6%BA%90%E7%A0%81diff%E5%88%86%E6%9E%90Apache-Shiro%201.7.1%E7%89%88%E6%9C%AC%E7%9A%84auth%20bypass%EF%BC%88CVE-2021-41303%EF%BC%89/

当以下这样配置时,会出现绕过

1
map.put("/bypass/*/index", "authc");

绕过方法

1
/bypass/id/index

参考

https://su18.org/post/shiro-4/#cve-2021-41303

https://github.com/threedr3am/learnjavabug