高版本shiro仍存在反序列化漏洞(CVE-2016-4437)
1、漏洞复现
一次内部测试发现某内网应用引用的shiro版本已是1.7.1,仍存在反序列化漏洞。
于是使用shiro反序列化工具验证,确实存在反序列化漏洞,通过猜解出shiro key(即RememberMe cookie AES加密的密钥),构造恶意payload反弹shell获取服务器权限。
2、漏洞成因
该漏洞是shiro 1.2.4版本存在的漏洞,深入学习了一下该漏洞细节,该漏洞是由于默认情况下shiro使用CookieRememberMeManager,RememberMe cookie反序列化过程如下:
- 检索RememberMe cookie的值
- Base 64解码
- 使用AES解密
- 使用Java序列化(ObjectInputStream)反序列化
通过上面的反序列化过程可知,攻击者需要构造payload(恶意代码)则需要知道AES密钥对payload进行序列化,然后将其作为cookie发送。Shiro将恶意cookie解码并反序列化后执行恶意代码。
该漏洞的关键点是攻击者如何获取AES密钥,由于1.2.4版本及之前版本的AES密钥是硬编码在代码里的,1.2.4及之前版本的shiro可以通过GitHub开源的shiro代码获取AES密钥。(1.2.4版本后其实没有从本质上解决反序列化漏洞,相当于采取了随机AES密钥无法猜解的缓解措施)
1.2.5版本以后shiro提供了AES密钥的随机生成代码,但是如果仅进行shiro的版本升级,AES密钥仍硬编码在代码中,仍然会存在反序列化风险(特别是开源的项目,AES密钥通过公共代码仓库就能获取的)
3、排查思路
1、代码中遍历shiro AES key字典。
2、代码中搜索setCipherKey关键字,查看AES key是否硬编码。
4、总结与思考
通过上述分析,后续研发使用shiro框架务必注意:
1、使用最新版本的shiro框架。
2、随机生成RememberMe cookie AES加密的密钥。
3、可采用JWT token的方式进行身份校验,还能减少缓存。
随机生成RememberMe cookie AES加密的密钥参考链接及代码:https://blog.csdn.net/qq_34775355/article/details/106643678
public class GenerateCipherKey { /** * 随机生成秘钥,参考org.apache.shiro.crypto.AbstractSymmetricCipherService#generateNewKey(int) * @return */ public static byte[] generateNewKey() { KeyGenerator kg; try { kg = KeyGenerator.getInstance("AES"); } catch (NoSuchAlgorithmException var5) { String msg = "Unable to acquire AES algorithm. This is required to function."; throw new IllegalStateException(msg, var5); } kg.init(128); SecretKey key = kg.generateKey(); byte[] encoded = key.getEncoded(); return encoded; } }
rememberMeManager()
@Bean public CookieRememberMeManager rememberMeManager() { CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager(); cookieRememberMeManager.setCookie(rememberMeManager()); cookieRememberMeManager.setCipherKey(GenerateCipherKey.generateNewKey()); return cookieRememberMeManager; }