前言
学习shiro反序列化
是什么
Apache Shiro是一种功能强大且易于使用的Java安全框架,它执行身份验证、授权、加密和会话管理,可用于保护任何应用程序的安全。
Shiro提供了应用程序安全性API来执行以下方面:
身份验证:证明用户身份,通常称为用户登录
授权:访问控制
密码术:保护或隐藏数据以防窥视;
会话管理:每个用户的时间敏感状态。
Shiro还支持一些辅助功能,例如Web应用程序安全性,单元测试和多线程支持,它们的存在也是为了加强上述四个方面。
简介
当 shiro 版本 <1.2.5时,主要是由shiro 的 rememberMe 内容 反序列化 导致的命令执行漏洞,造成的原因是 AES密钥被硬编码在shiro源码中,这就导致了可以通过在cookie的rememberMe字段插入payload实现任意代码执行
在我们勾选rememberme登陆后,刷新,抓包,将其 JSESSIONID 删除,使 shiro 验证cookie中rememberme的值是否正确(如果不删除JSESSIONID,shiro则直接以JSESSIONID为登陆凭证了,就不会验证rememberme中的值了)
环境准备
JavaThings/shirodemo at master · phith0n/JavaThings (github.com),p神的shiro的demo 然后导入idea
添加tomcat
部署war包
这样就行了
漏洞利用
admin :secret 选择remember me登录,当访问其他资源时cookie中会携带rememberme,shiro会进行反序列化导致漏洞发生
利用工具,爆破内置密钥
分析
加密过程
账号密码登录,选择 remerberMe,入口是在 AbstractRememberMeManager.java 中的 onSuccessfulLogin 方法中,判断token是否为true,然后调用 rememberIdentity
getIdentityToRemember 作用是获取 用户名 赋值给 principals,然后再次调用重构的 rememberIdentity 方法
发现调用了 convertPrincipalsToBytes
先是将用户名序列化处理 然后如果存在 getCipherService 看名字应该是获取某种加密方式 ,就进行加密操作 encrypt
看一下 getCipherService 确实是返回了一种aes的加密方式
看一下 encrypt ,看注释就知道,通过用设置好的加密方式,对传进来的已经序列化过的byte数组进行加密,然后返回加密的value
这里这个地方 getEncryptionCipherKey()
看到getEncryptionCipherKey() 直接返回一个常量,向上看看 encryptionCipherKey产生的过程
AbstractRememberMeManager() |
看到最后 用到了 DEFAULT_CIPHER_KEY_BYTES
而 DEFAULT_CIPHER_KEY_BYTES 是一个特定的值
接下来就进入到了 cipherService.encrypt(),最后的encrypt就是具体的加密过程
一路向上返回到重构的 rememberIdentity 方法,然后进入到 rememberSerializedIdentity 方法
在 CookieRememberMeManager.java 中 有一个 CookieRememberMeManager 类,看一下里面的方法,把刚才加密的byte进行base64加密,然后放到cookie中
此时,经过server返回登录响应,就可以看到rememberMe的值了
解密过程
了解了加密过程,如果使用了特定的key进行加密,如果在解密过程中有危险的点,就可以伪造cookie进行触发危险方法
getRememberedPrincipals 下断点
getRememberedSerializedIdentity 方法从名称来看是获取remember中的序列化的值,往下看看还有什么其他的操作
通过getCookie读取cookie的值,判断符不符合base64格式,最后解码后返回
返回到 getRememberedPrincipals 中 调用 convertBytesToPrincipals
可以看到就进行了两个操作 decrypt 和 deserialize
decrypt 就不跟进了,就是获取key解密,重点看一下反序列化的操作
最后走到 DefaultSerializer.java 中的 deserialize 最后 readObject() 这里打CC依赖
细节
onSuccessfulLogin -> rememberMeSuccessfulLogin -> onSuccessfulLogin -> |
当存在JSESSIONID时,会忽略rememberMe,所以在攻击时需要将JSESSIONID删掉
Shiro反序列化漏洞目前为止有两个,Shiro-550(Apache Shiro < 1.2.5)和 Shiro-721( Apache Shiro < 1.4.2 )
主要区别在于
Shiro550使用已知密钥撞
Shiro721是使用登录后rememberMe={value}去爆破正确的key值进而反序列化,
对比Shiro550条件只要有足够密钥库(条件比较低)、Shiro721需要登录(要求比较高鸡肋)
Apache Shiro < 1.4.2默认使用AES/CBC/PKCS5Padding模式
Apache Shiro >= 1.4.2默认使用AES/GCM/PKCS5Padding模式