Shiro550流程分析
好久没写了, 写一个Shiro550的加密分析
参考
https://blog.csdn.net/xhy18634297976/article/details/122794612
shiro的安装等步骤根据白日梦组长的视频来, 这里直接分析
shiro 1.2.4项目结构如下

直接从头审计不太可能, 我们根据shiro550的漏洞触发点来自Cookie中的rememberme字段, 我们搜索项目中的cookie

找到了第二个class, 进去看看结构和方法, 并大致看一遍, 可以找到其中比较关键的rememberSerializedIdentity和getRememberedSerializedIdentity这两个方法, 前一个将数据进行了base64并赋给cookie , 另一个则是从cookie中取出数据并base64解码
我们需要知道base64上一步是什么, 所以我们向上查找rememberSerializedIdentity的用法, 也就是哪里调用了它, 找到了rememberIdentity方法, 继续查找用法找到另一个重载的rememberIdentity方法中, 里面调用getPrincipals方法给principals赋了值

rememberIdentity方法
principals身份,即主体的标识属性, 这里应该表示的就是cookie中存放的身份识别

重载的rememberIdentity方法
继续向上查找, 在onSuccessfulLogin中调用了rememberIdentity, 如果isRememberMe(token)成立, 则继续调用, 这里判断的就是是否选择了remenberme, 之后就会按照上面倒过来的顺序一步步进入序列化

摸清楚调用顺序后, 我们回过头来在寻找其中的加密的地方
跟进rememberIdentity中的convertPrincipalsToBytes, 这个方法将身份认证序列化后进行了加密getCipherService最后指向了AbstractRememberMeManager类的构造函数, 在里面对cipherService赋值了AesCipherService
AesCipherService类里面有一些aes加密的参数, 可以猜测shiro的加密方式是将认证序列化后进行了aes加密, 最后base64一下放在了cookie中, 后面验证猜想正确



看完条件, 继续跟进encrypt

重点看这一句, 第二个参数明显是加密的密钥
1 | ByteSource byteSource = cipherService.encrypt(serialized, getEncryptionCipherKey()); |
第二个参数重点关注, 我们跟进去发现是一个返回的变量, 查找用法, 在写入里面发现了对其赋值的setEncryptionCipherKey方法, 继续查找用法找到setCipherKey方法, 继续查找, 最终找到
1 | setCipherKey(DEFAULT_CIPHER_KEY_BYTES); |
而这个DEFAULT_CIPHER_KEY_BYTES是一个常量
最后关注encrept方法, 我点击进去发现是个接口, 看不了具体方法, 所以开了调试, 这样就可以跟进了, 进入JcaCipherService类, 代码如下

iv在aes加密中是初始向量, 一般是随机生成, 这里跟进最后得到ivBytes的生成为一个随机数

最后得到一个16位长的数组

一直跟进, 可以得到加密类型, 确实是AES加密, 使用iv作为初始向量, CBC方法

参数已知, 加密算法已知, 剩下的就是复刻一个算法了
这里补充一嘴, iv作为随机数, 每次的值都不是一样的, 那么解密过程应该用不到iv
然后注意一下, shiro中的加密不是单纯的aes加密, 在encrypt方法中, 我们可以发现其返回结果不止是加密后的密文, 还包括了16位的iv, 也就是base64(iv+encrypted)

这样的话, 我们对一般的aes加密程序做一下修改, 在base64里面的前面多加一个iv就行了(因为iv的值会被去掉, 留下后面的那部分进去aes的解密)
我尝试了加入16位的其他数据, 利用失败了, 说明还是会检测一下前面16位和iv的对应关系
使用urldns的链子打一下
生成反序列化数据
1 | package exp; |
对数据加密
1 | from Crypto.Cipher import AES |
这里没打cb链子, 主要是我还没学, 可以用来检测是否存在shiro550
总结下来用到的只有加密和解密的分析, 反序列化入口就在Deserializatie那里, 后续就是常规反序列化链子, 比cc链分析都简单



