从 CVE 学 Shiro 安全
本文首发在梅子酒师傅的知识星球《胡言乱语》,感谢师傅邀请为嘉宾。进一步排版、修改之后会发在 NoSec 平台及相关公众号中。
当然,校准后的文章和测试代码会更新至 JavaSec 中。
前言
本文继续漏洞原理系列文章,这次简单的学习和分析了权限校验框架 Shiro 在历史上爆出的共 11 个带有 CVE 编号的漏洞,根据每个 CVE 漏洞的原理,版本更新的代码来分析安全漏洞产生的原理、利用方式、特性、坑。
主要还是对基础洞的学习,用来积累思路和姿势,目前对于 Java 安全来讲,单一的基础洞只能打打垃圾站,能够普遍适用的漏洞还需要组合拳来搞定,因此对思路、姿势的积累愈发重要,任何一个小 tricks 都能成为日后组链的关键点。
个人能力有限,如文章中有描述不清、有偏差甚至是错误的情况,希望师傅们不吝赐教。
目录
点击左边连接可以直接跳到对应漏洞的调试记录。
链接 | 描述 |
---|---|
简介 | Apache Shiro 简介 |
初识 | 几个关键类的介绍 |
使用 | 在 Servlet 项目和 Spring 项目中的简单使用 |
CVE-2010-3863 | 由于未标准化路径导致的绕过 |
CVE-2014-0074 | 使用 ldap 服务器认证时两个场景的绕过 |
CVE-2016-4437 | RememberMe 反序列化漏洞 |
CVE-2016-6802 | Context Path 路径标准化导致绕过 |
CVE-2019-12422 | Padding Oracle Attack & CBC Byte-Flipping Attack |
CVE-2020-1957 | Spring 与 Shiro 对于 "/" 和 ";" 处理差异导致绕过 |
CVE-2020-11989 | Shiro 二次解码导致的绕过以及 ContextPath 使用 ";" 的绕过 |
CVE-2020-13933 | 由于 Shiro 与 Spring 处理路径时 URL 解码和路径标准化顺序不一致 导致的使用 "%3b" 的绕过 |
CVE-2020-17510 | 由于 Shiro 与 Spring 处理路径时 URL 解码和路径标准化顺序不一致 导致的使用 "%2e" 的绕过 |
CVE-2020-17523 | Shiro 匹配鉴权路径时会对分隔的 token 进行 trim 操作 导致的使用 "%20" 的绕过 |
CVE-2021-41303 | 由于 Shiro 的 BUG 导致特定场景的绕过(不确定) |
CVE-2022-32532 | 使用 RegExPatternMatcher 和 "." 误配置时导致权限绕过 |
总结
通过对 Shiro 漏洞的学习和调试,我们对 Shiro 的一些技术的实现和安全部署有了一定的了解。除了 SHIRO-550 和 SHIRO-721 的反序列化以及 CVE-2014-0074 的 ldap 绕过之外,其他的绕过都是在路径处理过程中产生问题导致的绕过。
这些绕过多数是由于 shiro 的处理逻辑有误,或和中间件、其他框架的处理逻辑不一致导致的安全问题,通常会依赖场景。
更多时候,在真实的环境中,开发人员自己的配置也会导致鉴权的绕过,例如配置顺序、配置中是否有空格、配置中一些特殊符号的使用、Ant 表达式使用差异、开发人员鉴权代码逻辑有误等等,这部分目前在文章中没有涉及,后续会考虑补上。
另外,随着一些转发中间件、API 中间件等等中间层的介入,会扰乱 shiro 的鉴权配置,也会导致很多的安全问题。
可以预见的是,在特定场景下的绕过还是会出现的。
在 Shiro 的修复过程中还能看到的是,shiro 会提供解决方案,但有时不是升级版本就可以的,也有时修复的也并不全面,所以实现 shiro 安全还是需要安全知识和经验的加持。
杂记汇总
在整个的学习和调试过程中,有一些觉得有趣的杂记,放在这里供大家查看。
Spring 版本
Spring 的版本会完全的影响漏洞的触发,在某些 CVE 中,低版本生效,高版本不生效,在某些 CVE 中则相反,还有时由于 Spring 版本高可以绕过 Shiro 的更新补丁。
这些在具体的漏洞分析都提到了,实际上是因为 alwaysUseFullPath
导致的,详细的内容可以自行了解。
Ant 表达式中的 “*”
在 Ant 表达式中的 “*” 撑起了 shiro bypass 的大旗。其中关键点用一句话解释就是:
/audit/*
不能匹配/audit/
也不能匹配/audit/a/
彩蛋
在翻 Shiro 的 ISSUES 时,发现李三师傅提交的 SHIRO-760 提到了在使用 Tomcat AJP 时会导致的绕过问题。
但是官方认为其不算漏洞,就没下文了。可以预想到,关于不同协议下对请求路径的处理差异、或能够控制 Attribute 的场景下也可能导致绕过的产生。
Tips
这里分享几个分析时的小技巧。
第一,通过如下链接就可以查看这个版本修复了哪些 ISSUES ,方便定位。
https://issues.apache.org/jira/issues/?jql=project%20%3D%20SHIRO%20AND%20fixVersion%20%3D%201.5.2
第二,通过 diff 版本来查看差异代码分析漏洞,语法如下。
https://github.com/用户名/项目/compare/TAG名...TAG名
例如:https://github.com/apache/shiro/compare/shiro-root-1.7.0...shiro-root-1.7.1
反序列化
目前针对 Shiro 讨论最多的,还是 RememberMe 反序列化漏洞的延伸和姿势,我大概过了一下全网的文章,主要包括以下几个点:
- Shiro 组件的检测:检测站点是否包含 shiro 组件,cookie 关键字不是 rememberMe 等情况;
- Shiro AES 弱密钥的检测:检测 Shiro 是否内置或配置了常见的弱密钥;
- Shiro 内置链的利用:无 CC 依赖的 CB 链反序列化利用;
- 配合 RMI 利用:处理由于插入反序列化链导致的 Header 长度的问题,以及 Transformer 数组加载不到报错问题;
- 其他绕过 Tomcat Header 长度的姿势:反射修改 AbstractHttp11Protocol 的 maxHeaderSize、gzip + base64压缩编码、从外部或从 HTTP 请求 body 中加载类字节码;
- Ysoserial 改造:由于 shiro RememberMe 反序列化流程中加载类方式不同导致需要对 ysoserial 中 CC 等链的改造;
- 组合攻击:在 weblogic/Tomcat 等中间件上完成 shiro 的攻击、gadget 的利用、内存马的写入等组合操作;
- 改 Key:对于弱加密密钥,在攻击后将其修改,让目标仅为自己所用。
这部分内容算是进阶内容,没有放在本篇用于入门学习的笔记类文章中。感兴趣的同学可以在先知和Seebug
Paper 中搜索关键字 Shiro 来了解。
感想
看师傅们文章越发的有感触,厚积才能薄发。搞安全搞的是什么?搞的是积累,搞的是思路,搞的不是混脸熟,搞的不是唬住要 50 k,唬不住要 5k。