Shiro 550反序列化漏洞分析

洋洋的小黑屋發表於2021-10-07

Shiro 550反序列化漏洞分析

一、漏洞簡介

影響版本:Apache Shiro < 1.2.4

特徵判斷:返回包中包含rememberMe=deleteMe欄位。

Apache Shiro框架提供了記住密碼的功能(RememberMe),使用者登入成功後會生成經過加密並編碼的cookie。在服務端對rememberMe的cookie值,先base64解碼然後AES解密再反序列化,就導致了反序列化RCE漏洞。
那麼,Payload產生的過程:

命令=>序列化=>AES加密=>base64編碼=>RememberMe Cookie值

在整個漏洞利用過程中,比較重要的是AES加密的金鑰,如果沒有修改預設的金鑰那麼就很容易就知道金鑰了,Payload構造起來也是十分的簡單。

二、環境搭建

下載後用idea配置tomcat啟動:https://github.com/Medicean/VulApps/tree/master/s/shiro/1

image-20210928220044865

利用工具:https://github.com/wyzxxz/shiro_rce_tool

image-20210930144244696

三、漏洞分析

shiro會提供rememberme功能,可以通過cookie記錄登入使用者,從而記錄登入使用者的身份認證資訊,即下次無需登入即可訪問。而其中對rememberme的cookie做了加密處理,漏洞主要原因是加密的AES金鑰是硬編碼在檔案中的,那麼對於AES加密演算法我們已知金鑰,並且IV為cookie進行base64解碼後的前16個位元組,因此我們可以構造任意的可控序列化payload。

  • 通過在cookie的rememberMe欄位中插入惡意payload,

  • 觸發shiro框架的rememberMe的反序列化功能,導致任意程式碼執行。

  • shiro 1.2.24中,提供了硬編碼的AES金鑰:kPH+bIxk5D2deZiIxcaaaA==

1)加密過程

處理rememberme的類為org.apache.shiro.web.mgt.CookieRememberMeManager,它繼承AbstractRememberMeManager類,當登入成功並且勾選了rememberme選項,那麼此時將進入onSuccessfulLogin方法

image-20210930145350773

把斷點下到rememberIdentity後,跟進rememberIdentity方法

image-20210930150030956

繼續跟進rememberIdentity方法後,可以看到呼叫了convertPrincipalsToBytes方法後得到了個bytes,然後傳入了rememberSerializedIdentity

image-20210930150117056

其實在convertPrincipalsToBytes中進行了加密操作,我們可以跟進檢視

image-20210930150327306

可以看到通過序列化拿到了個bytes,然後在362行進行了encrypt操作,這裡就是加密進行的地方了,跟進檢視

image-20210930150940274

看471行,拿到了個CipherService類,這個類就是用來進行加密的,開啟可以看到加密模式為CBC,Padding規則是PKCS5,加密方式為AES

image-20210930151207547

然後473行進行了加密操作,檢視在其引數中的getEncryptionCipherKey方法,這個方法就是用來獲取金鑰的,此金鑰硬編碼在了類中,並進行了base64編碼

image-20210930152334108

回到之前的encrypt方法中,等加密完成後,把值return給了前面說的的bytes,然後傳進了rememberSerializedIdentity方法

image-20210930152813892

rememberSerializedIdentity方法中,把加密的字串進行了Base64編碼,然後設定到了cookie中

image-20210930152858104

2)解密過程

在shiro中,解密過程就是和加密過程相反的了,解密過程在AbstractRememberMeManager#getRememberedPrincipals方法中

image-20210930154228507

首先呼叫getRememberedSerializedIdentity方法,方法中獲得了cookie中的rememberMe的值然後進行base64解碼並返回給了bytes

image-20210930154613502

第二步就是呼叫convertBytesToPrincipals方法來進行解密

image-20210930154747209

跟進convertBytesToPrincipals方法

image-20210930154814180

先進行了decrypt解密,然後再進行的deserialize反序列化。

檢視decrypt,這裡和之前加密過程步驟差不多,用的金鑰都是同一個

image-20210930155113371

檢視反序列化方法deserialize

image-20210930155502621

getSerializer()返回的是一個預設的序列化物件DefaultSerializer

image-20210930155550111

跟進DefaultSerializer#deserialize看到了熟悉的反序列化

image-20210930155831320

四、漏洞修復

Apache Shiro 1.2.5版本的原始碼,修復方法就是shiro每次啟動,都會隨機生成一個新的key:https://github.com/apache/shiro/commit/4d5bb000a7f3c02d8960b32e694a565c95976848

img

相關文章