无 Java 依赖的 Shiro 靶场
背景Apache Shiro 中一个已知的反序列化漏洞——Shiro-550,它尽管存在已久,但由于其自带的加密特性和影响力,在近几年的安全演练中受到了特别关注。Yakit 中也很早就添加了 Shir
2023-7-7 17:34:16
Author: Yak Project(查看原文)
阅读量:29
收藏
![]()
Apache Shiro 中一个已知的反序列化漏洞——Shiro-550,它尽管存在已久,但由于其自带的加密特性和影响力,在近几年的安全演练中受到了特别关注。Yakit 中也很早就添加了 Shiro 相关的漏洞检测插件,但在 YAK 引擎的更新迭代中,一些 bug 影响了一些漏洞的检出。为了确保我们没有无意中破坏了现有的功能(这称为回归错误),我们对一些插件进行了内置化,同时结合 vulinbox
靶场当作测试靶场,对目前的几个社区呼声较高的插件来了一波 "出厂检验"。
Shiro RememberMe 反序列化漏洞检测
shiro 漏洞相关的原理以及利用工具已经有很多师傅分享了。如今主流的检测 Shiro Key 的方式是由 l1nk3r
师傅分享的,使用一个空的 SimplePrincipalCollection
序列化后和要检测的 Key 进行加密作为 payload 发送,判断响应头中的 deleteMe
个数。
在总结和学习了很多师傅的检测逻辑后,目前 Yakit shiro 插件的检测逻辑如下:
- 首先发送一个 Cookie: rememberMe= 随机值,记录响应头 deleteMe 的个数
- 判断 Set-Cookie 中的值是 rememberMe 还是 remeberMe,作为后续的关键字
- 结合上一步获取的关键字,开始发送使用 Key 加密后的反序列化 SimplePrincipalCollection 数据,判断 deleteMe 的个数是否小于第一步中统计的个数,如果小于(一般是减少1)则代表本次使用的 Key 正确
- 通过获取的正确的 Key ,使用四条最为常见的利用链配合 Header 回显,进行盲打
- 如果回显盲打不成功,使用 dnslog 进行利用链的探测
使用的四条回显链分别为,CB183NOCC、CB192NOCC、CCK1、CCK2
在步骤 d 中,为了保证回显的随机性,我们执行的操作是:先加载回显的 Class 文件,在 Class 常量池中找到我们预设的常量值,替换为随机值,得到修改后的 Class 字节码。得益于 Yaklang 完善的 java 字节码相关的基础设施,上述的操作十分的简单,仅需如下几行代码即可完成:当 a,b 步骤通过时,插件会发出一个风险提示——检测到 Shiro(Cookie) 框架使用
当 c 步骤通过时,插件会发出第二个风险提示——(Shiro 默认 KEY)
当 d 步骤通过时,插件会发出第三个风险提示——(Shiro Header 回显)
当 d 不通过且 e 步骤通过时,插件会发出第三个风险提示——(Shiro 利用链探测)
在知道了我们 Shiro 插件的检测逻辑后,我们就可以开始写对应的靶场逻辑了,根据上面的检测逻辑,我们的靶场逻辑如下:启动靶场时,随机使用 Shiro Key 列表中的一个当作默认的 Key,随机使用 Gadget 列表(CB183NOCC、CB192NOCC、CCK1、CCK2)中的一个,模拟可利用链
为了简单,在非在 SimplePrincipalCollection 序列化加密后的 payload 请求的响应头中添加 Set-Cookie: rememberMe=deleteMe
获取 Cookie rememberMe 的值,Base64 解码后再使用第一步中的默认 Key 进行 AES/GCM 解密
判断解密后的数据是否是一个正常的 Java 序列化对象,如果是,反序列化Java对象流,判断是否包含值为org.apache.shiro.subject.SimplePrincipalCollection 的 ClassName,如果包含,去掉响应头中的 Set-Cookie: rememberMe=deleteMe 字段
- 如果上一步 SimplePrincipalCollection 没有检测到,我们会根据启动时随机使用的Gadget进行判断,也就是尝试进行org.apache.commons.beanutils.BeanComparator、org.apache.commons.collections.keyvalue.TiedMapEntry、org.apache.commons.collections4.keyvalue.TiedMapEntry 的判断,以及在 Header 中回显
不过得益于 Yaklang 完善的 Java 序列化相关的基础设施,我们可以轻易地判断一个数据流是否是 Java 序列化对象流,并且将其反序列化。其实也就是早已添加在 Codec 模块中的 Java 相关的功能。我们使用的四条回显链分别为,CB183NOCC、CB192NOCC、CCK1、CCK2,其中CB183 和 CB192 的 SerialVersionUID
是不一样的,所以除了类名org.apache.commons.beanutils.BeanComparator
我们也要判断 SerialVersionUID
, 上图中的 serial_version
字段在经过转换后,其实就是常见的 -3490850999041592962
这种 SerialVersionUID 了。UID 和 类名的问题解决了,我们开始着手构造出符合 payload 预期结果的 fake Header 回显。熟悉这四条链的师傅应该能知道,这四条链有一个共同点,那就是可以利用 TemplatesImpl 执行字节码,可以更加直观的感受一下:发现了十分熟悉的 yv66
,那接下来的思路就简单多了,反序列化 Java 对象流(也就是解密后的payload) -> 拿到 Class
字节码 -> 解析 Class
字节码 -> 遍历常量池,找到 setHeader
的传入值 -> 靶场 Server 响应头添加对应回显 -> Shiro 插件检出(Shiro Header 回显)
风险。让我们直接启动靶场来看看实际的效果,先启动 Vulinbox 靶场 ,如下图,我们可以看到本次启动随机使用的 Shiro Key IduElDUpDDXE677ZkhhKnQ==
和 gadget CCK1
:随后我们在 Yakit 中的插件调试功能中,选择 Shiro 插件,输入 Vulinbox 靶场中的 Shiro 地址,点击执行插件。可以发现检出了三个风险,分别是:发现 shiro 框架、发现 shiro 默认 Key 、发现 shiro 回显。查看一下风险详细信息,Shiro Key 和利用链符合预期,响应头也存在 Vhmymv: emImhYiW。
靶场效果完美符合预期,赶紧添加一个测试用例,设置检出预期值 ,提交代码后自动跑个 CI, 有了这一层保障,也不用担心再出现回归错误啦~在修改完插件后,为了测试其健壮性,找了一些使用了 Shiro 框架的进行测试,发现其中一个网站连 Shiro 框架都没有探测出来。经过测试发现必须在 body
中存在 rememberMe=1
或者 rememberMe=true
时,才会进入后续的 Cookie rememberMe
处理流程。勾选 Shiro 插件,开启 MITM 劫持,成功检出,这种边缘情况也确实不太好处理,好在还有被动扫描的模式。本次以 Shiro 靶场为例展开说明,其实现在内置的 4 个插件,均有对应的靶场和检出预期值。最后想说说,Yak的一些基础设施库确实很好用,很多功能都可以直接拿来即用,但是也缺少了很多接口的使用文档。未来我们不仅会持续补充和完善文档,而且也会合理利用 CI/CD 配合测试,提供插件评估机制,构建更加可靠的插件生态。Yakit 1.2.2-sp1
1. webfuzzer新增标签与编解码辅助工具,支持新增常用标签
2. 修复批量发包列表加载问题
3. 恢复发包后可提取数据的功能
4. 新增靶场功能,安装即可使用(设置—试验性功能)
Yaklang 1.2.2-sp3
1. 新增插件自动评估机制的 gRPC 接口,可以自动检查插件质量
2. 新增 Web Fuzzer Tag 缓存机制
3. 优化 HTTP2 中 :authority 被强制加端口的情况
4. 修复 params 的对 JSON 的展示信息
5. 修复浏览器爬虫库的一些小问题
6. 新增靶场管理的 gRPC 接口
![]()
文章来源: http://mp.weixin.qq.com/s?__biz=Mzk0MTM4NzIxMQ==&mid=2247500416&idx=1&sn=cee740b6e09735c169cc7b13aa3487cb&chksm=c2d1be24f5a63732477bb6ea3b45a71c104a91fa63ca47cd7f7b18fa7262275203cfc36af926#rd
如有侵权请联系:admin#unsafe.sh