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; }
