Shiro反序列化
参考文章
- 安全KER-Shiro反序列化漏洞详细分析
- freebuf-Apache Shiro反序列化漏洞-Shiro-550复现总结
- csdn-shiro550反序列化漏洞原理与漏洞复现(基于vulhub,保姆级的详细教程)
- bilibili-Shiro反序列化漏洞(一)-shiro550流程分析
shiro-550 介绍
shiro-550(shiro小于1.2.5)主要是由shiro的rememberMe内容反序列化导致的命令执行漏洞
造成的原因是AES密钥被硬编码在shiro源码中, 这就导致了可以通过在cookie的rememberMe字段插入payload实现任意代码执行
在这以后shiro使用随机密钥, 而不再硬编码, 这又造成padding oracle attack导致的shiro-721
特征
返回包中包含rememberMe=deleteMe字段
请求包中存在rememberMe=remember-me, 返回包中存在rememberMe=deleteMe字段以及一段很长的rememberMe=…, 可以通过base64解码
当客户端再次请求服务端时,都会带上这个服务端第一次返回设置的Set-Cookie里面的rememberMe的密文,让服务端进行身份验证
动调
¶加密
断点位置为AbstractShiroFilter.class的doFilterInternal()
尝试登录后进入onSuccessfulLogin()继续步入rememberMeSuccessfulLogin()函数
RememberMeManager参数不为空,步入AbstractRememberMeManager的onSuccessfulLogin(), 随后到达convertPrincipalsToBytes()函数
发现首先将进行序列化,之后由this.getCipherService()获取到加密服务方式不为空后,进入this.encrypt(bytes)阶段
encrypt()函数的CipherKey就是AbstractRememberMeManager.class开头的
DEFAULT_CIPHER_KEY_BYTES="kPH+bIxk5D2deZiIxcaaaA==" |
获取CipherKey返回后进入cipherService.encrypt函数中,生成初始化向量ivBytes后,进入具体的加密函数,最后return
然后就是记住身份并将信息加入到cookie中
¶解密
同样在相同位置下断点
单步到resolvePrincipals()函数, 进入this.getRememberedPrincipals(subjectContext), 其中有两个函数
第一个函数getRememberedSerializedIdentity()中, 先获取cookie中的值, 然后base64解密, 生成二进制数后返回
第二个函数convertBytesToPrincipals()中,先获取解密服务不为空后,将二进制数据传入decrypt函数进行解密,之后return this.deserialize(bytes)
在deserialize(bytes)中有readObject(),触发apache.commons利用链漏洞
¶总结
加密时:序列化转为二进制、encrypt加密、base64加密、放入cookie 解密时:从cookie中取出、base64解密、decrypt解密、反序列化 在利用时,可以根据硬编码在源码中的key构造payload
怎么打-待完善
一般都是说用commons-collections依赖(简称CC?)
但是网站正常运行时不一定会使用这个依赖, 所以我们会使用commons-beanutils
IDEA有插件可以查看有哪些依赖真正运行(仅有compile和runtime真正运行)
