Shiro-550漏洞分析(CVE-2016-4437)
对shiro-550漏洞的简单分析及poc利用分析
漏洞简介
官方issues:https://issues.apache.org/jira/browse/SHIRO-550
Apache Shiro框架提供了记住我(RememberMe)的功能,功能表现为关闭浏览器再次访问时无需再登录即可访问。shiro默认使用CookieRememberMeManager,对rememberMe的cookie做了加密处理,在CookieRememberMeManaer类中将cookie中rememberMe字段内容先后进行序列化、AES加密、Base64编码
操作。服务器端识别身份解密处理cookie的流程则是: 获取rememberMe cookie ->base64 解码->AES解密(加密密钥硬编码)->反序列化(未作过滤处理)
。
但是AES加密的密钥Key被硬编码在代码里,这就意味着每个人通过源代码都能拿到AES加密的密钥。因此,攻击者可以构造一个恶意的对象,并且对其序列化、AES加密、base64编码后,作为cookie的rememberMe字段发送。shiro将rememberMe进行解密并且反序列化,最终就造成了反序列化漏洞。如果在返回包的 Set-Cookie 中存在 rememberMe=deleteMe 字段,那么就可能存在此漏洞。
影响版本
Apache Shiro <= 1.2.4
环境搭建
直接使用shiro官方的samples-web进行分析
|
|
打包前需要对./shiro/samples/web/pom.xml
进行一些修改:
|
|
导入IDEA,使用JDK1.8,然后打包成war包,丢到tomcat访问
漏洞分析
正常登录成功后,服务器返回给我们的cookie:
|
|
后端会对rememberMe的值进行base64解码然后进行AES解密,我们来跟一下源码
可以看到在shiro-core-1.2.4.jar!/org/apache/shiro/mgt/AbstractRememberMeManager.class
中看到硬编码了CIPHER_KEY
|
|
继续往下看,可以看到encrypt和decrypt方法
|
|
其中 CipherService 是个接口,而实现这个接口的是一个抽象类 JcaCipherService,继续跟进,在initNewCipher下断点,调试可以看到使用了AES/CBC/PKCS5Padding模式加密,继续调试发现random = this.ensureSecureRandom();
,使用随机数生成16字节的 iv,然后使用encrypt(plaintext, key, ivBytes, generate)
生成数据经过base64编码作为rememberMe的值
iv是随机数生成的,解密时iv值直接从密文的前16字节获取,然后利用得到的iv和硬编码的key来进行解密密文:
|
|
然后也在加密方法中看到了对应实现:
那我们只要知道了硬编码的key值,就可以构造任意数据传入了
到这里只是该漏洞利用的前提,我们继续分析漏洞点
既然我们知道了iv就是rememberMe值base64解码后的前16个字节,我们先来解码正常的rememberMe值看看:
加密解密脚本:
|
|
可以看到明显的aced
序列化流的标识,所以分析到这里可以猜测,rememberMe的值存储的是序列化数据,有序列化就一定有反序列化操作,接下来看看后端接收到rememberMe值后对其进行的操作
在shiro-core-1.2.4-sources.jar!/org/apache/shiro/mgt/AbstractRememberMeManager.java
的getRememberedPrincipals
函数,对rememberMe值进行操作,在这里下断点调试
一步步跟进,经过解密操作然后进入到了shiro-core-1.2.4-sources.jar!/org/apache/shiro/io/DefaultSerializer.java
的deserialize
方法
看见了readObject
对数据进行反序列化操作
前面我们知道加密解密过程可控,所以我们可以控制序列化数据,利用反序列化进行恶意操作
但是有了反序列化点,我们还得找到可以利用的链
无cc依赖
前文在环境搭建部分我提到了添加 commons-collections-3.2.1 库是为了方便演示有依赖的反序列化RCE,实际上原生shiro是不依赖 commons-collections 库的,但是用到了 commons-beanutils 库
把pom.xml中 commons-collections 的依赖配置去掉,重新打包环境
参考phith0n的文章可以知道一条无cc依赖的cbu链可以打原生shiro组件,原文讲的很详细
在shiro中,它的 commons-beanutils 虽然包含了一部分 commons-collections 的类,但是不全,shiro正常使用得以满足,但是我们利用反序列化链用到的类部分不存在
所以直接利用 ysoserial 里的cbu链打,会爆出org.apache.commons.collections.comparators.ComparableComparator
不存在,但是我们可以找到一个替代品,CaseInsensitiveComparator
类是java.lang.String
类下的一个内部私有类,其实现了Comparator
和Serializable
,且位于Java的核心代码中,兼容性强
构造新的cbu链,此时就可以直接打没有commons-collections库的shiro组件了
有cc依赖
另外值得我们注意的是,当shiro组件存在 commons-collections:4.0 依赖时,我们可以直接利用 ysoserial 的 CommonsCollections2 利用链,这是因为CommonsCollections2
用的是非数组形式的利用链,在该利用链上没有出现数组类型的对象,这使得在shiro的环境下,可以正确执行命令
shiro组件不能出现数组形式的利用链原因是 shiro resovleClass 使用的是ClassLoader.loadClass()
而非Class.forName()
,而ClassLoader.loadClass
不支持装载数组类型的class,具体分析可以参考wh1t3p1g的博客
因为不能使用数组形式,之前在commons-collections:3.2.1
下可以利用的链都失效了,但是我们可以想到后半段可以不使用ChainedTransformer
构造,利用cc3中分析提到的TemplatesImpl.newTransformer
函数来动态loadClass
构造好的恶意class字节码,这样可以绕过使用数组类型的对象
wh1t3p1g师傅已经详细描述了触发TemplatesImpl.newTransformer
的方法,我将会在cc链分析文章中对其进行分析,这里就不再过多叙述了,参考:https://blog.0kami.cn/2019/11/10/java/study-java-deserialized-shiro-1-2-4/
当然在有cc依赖的情况下我们还可以使用 ysoserial 里的cbu链
Reference
https://blog.knownsec.com/2016/08/apache-shiro-java/
https://blog.0kami.cn/2019/11/10/java/study-java-deserialized-shiro-1-2-4/
https://blog.zsxsoft.com/post/35
https://www.leavesongs.com/PENETRATION/commons-beanutils-without-commons-collections.html