初探shiro反序列化
一、关于shiro
shiro是一种开源的java安全框架。它提供了身份验证(Authentication)、授权(Authorization)、加密(Cryptography)和会话管理(Session Management)等安全功能,用于保护Web应用程序和非Web应用程序中的安全性。可运行在web应用和非web应用中。使用Shiro框架可以使应用程序的安全性得到提高,同时也可以使开发者更加方便地进行身份验证、授权和会话管理等操作,减少了开发的复杂度和工作量。
二、环境搭建
github有可以直接利用的环境
我们这里直接从github导入就行了
1 | git clone https://github.com/apache/shiro.git |
编辑shiro/samples/web目录下的pom.xml,将jstl的版本修改为1.2。
1 | <dependency> |
导入项目,然后配置Tomcat环境
shiro为了保持用户登录状态提供了一个rememberme选项
当我们勾选了这个选项会在cookie中生成一个字符串用户保存用户的登录状态
从而使用户再访问时不用再次登录
三、漏洞分析
加密流程分析
生成字段的位置在org.apache.shiro.mgt.DefaultSecurityManager#login
1 | public Subject login(Subject subject, AuthenticationToken token) throws AuthenticationException { |
这段代码主要实现了用户的验证和认证
在认证成功后会进入 onSuccessfulLogin()
方法
跟进 onSuccessfulLogin()
方法
继续跟进到rememberMeSuccessfulLogin
方法
我们这里在RememberMeManager rmm = getRememberMeManager();
处打上断点
然后打开调试模式,然后进行登录并勾选remember选项
然后我们的代码会直接跳到我们打断点的地方
我们打断的的地方其实就是获取remeber这个对象
然后会根据是否获取到来判读我们是否勾选了remeber选项
勾选了remeber选项这里就会对获取到的对象调用onSuccessfulLogin
方法
跟进到onSuccessfulLogin
方法
我们跟进到onSuccessfulLogin
方法发现这里调用了forgetIdentity
方法对subject进行处理,这里的subject对象表示单个用户的状态和安全操作,包含认证、授权等。
继续跟进到forgetIdentity
方法
然后继续跟进
这里的forgetIdentity
的作用是清除上次的cookie里认证值,然后又调用了removeFrom
方法
我们这里跟进这个方法,分析一下这个方法做了些什么
1 | public void removeFrom(HttpServletRequest request, HttpServletResponse response) { |
这里removeFrom
主要是在set-cookie中添加了一个rememberMe=deleteMe
通过上面的分析我们可以知道forgetIdentity
最终主要实现了消除上次登录cookie里的认证值,然后在cookie中添加rememberMe字段
那我们跳回到onSuccessfulLogin
方法
然后isRememberMe(token)
会判断我们是否设置了rememberMe字段
设置会进入到
1 | rememberIdentity(subject, token, info); |
我们这里继续跟进到rememberIdentity
方法
这里使用 getIdentityToRemember
方法从 subject
和 authcInfo
参数中获取身份信息并将其存储在 principals
中。
继续跟进到rememberIdentity
这里的accountPrincipals
就是我们上面存储的身份信息
这里调用convertPrincipalsToBytes
方法对我们存储的身份信息进行处理
继续跟进到convertPrincipalsToBytes
方法
在这个方法中调用serialize
方法对存储的身份信息进行了序列化
我们跟进到序列化方法
到这里就可以很明显的看懂对用户名进行了序列化
我们继续回到convertPrincipalsToBytes
方法
在上面对用户进行序列化处理后转化为字节数组
然后会调用encrypt对字节数组进行加密
我们跟进到这个用于加密的方法 encrypt
这里是对字符数组进行加密的具体实现
我们根据调试信息可以看到加密算法为AES,模式为CBC,填充算法为PKCS5Padding。
这里的算法是AES,这里的getEncryptionCipherKey
就是获得默认密钥进行加密的
1 | kPH+bIxk5D2deZiIxcaaaA==就是加密用的固定密钥 |
加密完成后,这里跳回到rememberIdentity
跟进到rememberSerializedIdentity
方法
在这里会对加密后的字节数组进行base64编码,然后会将生成的字符串保存在cookie中。
也就是我们cookie中rememberMe的值
那么通过上面的分析我们知道加密的过程大概就是序列化,然后进行AES加密,最后进行base64编码
那么解密的过程就和上面大概反过来
解密流程分析
对cookie中rememberMe的解密代码也是在AbstractRememberMeManager.java
中实现
我们这里直接在getRememberedPrincipals
方法打断点
我们这里跟进到getRememberedSerializedIdentity
方法
可以看到这里getRememberedSerializedIdentity对返回cookie中rememberMe的base64解码处理。
然后调用convertBytesToPrincipals
方法对解码后的字节处理
我们这里跟进去分析一下
这里调用decrypt对字节进行解密处理
然后回到convertBytesToPrincipals
对解密后的字节调用deserialize
处理
这里调用了readObject方法对字节进行反序列化
这也是我们漏洞的所在,因为通过我们上面的分析,我们知道对序列化后的字节数组的加密使用的是aes加密,aes使用的默认的固定密钥加密,那我们只需要将我们的反序列化攻击链通过aes进行加密,然后把cookie中的remember的值给替换掉,在进行到上面这一步进行反序列化的时候就会造成反序列化的利用。
产生这个漏洞的最主要原因就是因为固定key,导致攻击者可以替换掉这个rememberme字段的值为自己的攻击链,造成反序列化漏洞利用。
四、漏洞利用
在上面我们分析了shiro框架rememberme字段的加密和解密流程,然后对shiro反序列化漏洞的原因进行了分析
那么我们这里尝试通过URLDNS利用链对这个反序列化漏洞进行验证。
1 | import java.lang.reflect.Field; |
这里先使用URLDNS利用链生成一个利用payload,这里的url是在DNSlog生成的
然后通过AES加密脚本进行固定key加密
1 | import org.apache.shiro.crypto.AesCipherService; |
1 | HWChkU+6Uq102u6EwcmZwsXxpbfwTHYkfuRtp3s0xdfyYe3IVH/SV+937NDpl/PnifK3LrVG+dz4lhEgAiySHCi8zN4Ak7gD9JzMVqDhvUmgwy2nI6iEe2ayMsqNcyCUVjVlmX3cYLRLvGx+WjoCa7PQ5fPhjLMvTx7nr4hYv1UsWtIlRX5vLc0ywGvBPuc4ifnOI1CnSJd7QPBTv5PGkbWKlPySpQXKxcLPtr7EKpz+rvetwM70oRKISG1IBx4j/wRv6BOT6M40fMLBBLxXHf1NUgPYKnRyurTW4zAw0Qat0VUlRXpoO9NcMGYUmHqkrNuqP9bFpF4TJQUIoQD+OoznEpGXcBHvcfuVho7NUkAFt+emJwYiJXG7UGS8q6Lo7BkBvSQZPNBTfC89wRf/KE1u67LOY/IQIYlEdm9Ir7Mqd0uHfUuwdBTE8D1Y2GgXG7kiWVPNqWIjkS9XX015yA== |
启动环境抓包
将生成的rememberMe字段的值替换成我们攻击payload
然后我们在DNSLOG页面可以看到地址被成功解析了,说明这里存在反序列化漏洞,反序列化利于成功了。
五、总结
其实通过上面的分析,我们已经能够理解尝试shiro反序列化的原因是因为固定key加密。反过来我们要想要对这个漏洞进行利用,需要知道key才行。
Shiro≤1.2.4中默认密钥为kPH+bIxk5D2deZiIxcaaaA==。官方针对这个漏洞的修复方式是去掉了默认的Key,生成随机的Key。
我们上面只是通过URLDNS利用链对shiro反序列化这个漏洞进行了验证,但是并没有造成什么实质性的利用,后面将学习shiro配合我们前面学习CC链进行攻击利用。
- 标题: 初探shiro反序列化
- 作者: GTL-JU
- 创建于: 2023-09-12 20:14:06
- 更新于: 2023-09-12 20:15:46
- 链接: https://gtl-ju.github.io/2023/09/12/shiro反序列化初探/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。