廣州市住房建設(shè)部網(wǎng)站管理微信軟件
1. 漏洞原理
Apache Shiro框架提供了記住密碼的功能(RememberMe),用戶登錄成功后會(huì)生成經(jīng)過加密并編碼的cookie。在服務(wù)端對rememberMe的cookie值,先base64解碼然后AES解密再反序列化,就導(dǎo)致了反序列化RCE漏洞。
那么,Payload產(chǎn)生的過程:
命令 -> 序列化 -> AES加密 -> base64編碼 -> RememberMe Cookie值
在整個(gè)漏洞利用過程中,比較重要的是AES加密的密鑰,如果沒有修改默認(rèn)的密鑰那么就很容易就知道密鑰了,Payload構(gòu)造起來也是十分的簡單。
2. 環(huán)境搭建
直接從github上clone代碼到本地。
git clone https://github.com/apache/shiro.git
cd shiro
git checkout shiro-root-1.2.4
編輯shiro/samples/web目錄下的pom.xml,加一個(gè)jstl的版本,否則默認(rèn)版本解析jsp會(huì)報(bào)500錯(cuò)誤。
<dependency><groupId>javax.servlet</groupId><artifactId>jstl</artifactId><version>1.2</version><scope>provided</scope>
</dependency>
搭建tomcat。
下載shiro war包
https://github.com/jas502n/SHIRO-550
加載war包。
點(diǎn)擊運(yùn)行項(xiàng)目,打了一下,能打。
3. 漏洞流程分析
1、嘗試登錄shiro,把rememberMe勾上,會(huì)返回一大串Cookie,之后的請求都會(huì)帶著這串Cookie。
這時(shí)候我們思考Cookie里面的內(nèi)容是什么,一般都是用來存放一些認(rèn)證信息,比如序列化好的一些認(rèn)證數(shù)據(jù)等等。
2、在idea里面找一下數(shù)據(jù)是怎么處理的,兩下shift,快速查找shiro包里面與cookie相關(guān)的類名。
3、CookieRememberMeManager類中和序列化相關(guān)的方法:rememberSerializedIdentity
CookieRememberMeManager類中和反序列化相關(guān)的方法:getRememberedSerializedIdentity()
getRememberedSerializedIdentity()的作用是獲取序列化加密數(shù)據(jù),像是只做了一層base64解密。
4、找哪里調(diào)用了getRememberedSerializedIdentity()。
AbstractRememberMeManager.getRememberedPrincipals()調(diào)用了getRememberedSerializedIdentity()
可以看到獲取bytes以后調(diào)用了convertBytesToPrincipals()方法,該方法作用是把解密后的Cookie數(shù)據(jù)轉(zhuǎn)換成認(rèn)證信息。
跟一下convertBytesToPrincipals()方法,該方法作用是解密數(shù)據(jù)和反序列化數(shù)據(jù)。
跟decrypt()。
發(fā)現(xiàn)下列代碼傳入值分別是"加密的字段"和"加密key"。
cipherService.decrypt(encrypted, getDecryptionCipherKey());
找一下加密key是什么。
繼續(xù)跟getDecryptionCipherKey(),發(fā)現(xiàn)返回decryptionCipherKey的值。
Find Usage decryptionCipherKey值,找哪里write了decryptionCipherKey,找到了setDecryptionCipherKey()方法。
繼續(xù)找誰調(diào)用了setDecryptionCipherKey()方法,找到了setCipherKey()方法。
找誰調(diào)用了setCipherKey()方法,找到了AbstractRememberMeManager()方法。
發(fā)現(xiàn)常量DEFAULT_CIPHER_KEY_BYTES
發(fā)現(xiàn)是一個(gè)固定的key來做的aes加密。
跟deserialize()。
按住shift一直找,知道找尋到如下代碼,可以看到調(diào)用了反序列化readObject(),這里如果有依賴的話就可以直接打CC了。
5、嘗試找利用鏈,看起來java庫里是帶有有漏洞的CC的。
但是實(shí)際上用Maven Helper插件來看是沒有真正運(yùn)行到程序中的,都是存在于test包中。
程序?qū)嶋H運(yùn)行只會(huì)把compile、runtime的包打進(jìn)去,test打不進(jìn)去。
真正能打的就這個(gè)CB。
6、這里就打URLDNS那個(gè)自帶的鏈。
序列化數(shù)據(jù) -> key固定aes加密 -> base64
生成URLDNS序列化數(shù)據(jù),填寫自定義dnslog地址。
使用腳本將序列化數(shù)據(jù)先aes加密,再base64。
生成加密的序列化數(shù)據(jù)后在發(fā)包利用的時(shí)候不能攜帶已登錄的JSESSIONID,如果存在JSESSIONID就不會(huì)讀取rememberMe了。直接發(fā)包,Cookie: rememberMe=[加密后序列化數(shù)據(jù)]
成功觸發(fā)dnslog請求。
4. 參考
https://www.bilibili.com/video/BV1iF411b7bD/?spm_id_from=333.999.0.0&vd_source=04a73463f80a726a1d35327bd426fa6e
http://changxia3.com/2020/09/03/Shiro%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E%E7%AC%94%E8%AE%B0%E4%B8%80%EF%BC%88%E5%8E%9F%E7%90%86%E7%AF%87%EF%BC%89/