Shiro550
shiro550和fastjson作為攻防演練的利器,前面學習了fastjson的相關利用和回顯,本篇主要來學習一下shiro550的漏洞原理。
1、漏洞原因
在 Shiro <= 1.2.4 中,AES 加密演算法的key是硬編碼在原始碼中,當我們勾選remember me 的時候 shiro 會將我們的 cookie 資訊序列化並且加密儲存在 Cookie 的 rememberMe欄位中,這樣在下次請求時會讀取 Cookie 中的 rememberMe欄位並且進行解密然後反序列化,且AES的key 為固定的。
2、環境搭建及復現
https://codeload.github.com/apache/shiro/zip/shiro-root-1.2.4
jdk1.7
Tomcat8
idea
坑點
原有版本的jstl會報錯修改為1.2
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- 依賴cc鏈 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.0</version>
</dependency>
toolchains的錯誤
<?xml version="1.0" encoding="UTF8"?>
<toolchains>
<toolchain>
<type>jdk</type>
<provides>
<version>1.6</version>
<vendor>sun</vendor>
</provides>
<configuration>
<jdkHome>/Library/Java/JavaVirtualMachines/jdk1.8.0_161.jdk</jdkHome>
</configuration>
</toolchain>
</toolchains>
然後啟動即可
漏洞復現
3、漏洞分析
3.1、生成cookie
3.1.1、原理解析
shiro會提供rememberme功能,可以通過cookie記錄登入使用者,從而記錄登入使用者的身份認證資訊,即下次無需登入即可訪問。而其中對rememberme的cookie做了加密處理,漏洞主要原因是加密的AES金鑰是硬編碼在檔案中的,那麼對於AES加密演算法我們已知金鑰,並且IV為cookie進行base64解碼後的前16個位元組,因此我們可以構造任意的可控序列化payload。
cookie的處理類org.apache.shiro.web.mgt.CookieRememberMeManager
類出現了漏洞,而它繼承了AbstractRememberMeManager類。
處理rememberme的cookie的類為org.apache.shiro.web.mgt.CookieRememberMeManager
,其中的rememberSerializedIdentity
方法,主要就是設定使用者的cookie的值,這個值是通過base64解密serialized獲取的。
我們繼續看看父類
首先定義預設的祕鑰通過base64固定解碼得到,這個就是我們上門工具爆破出來的祕鑰
還有就是方法 onSuccessfulLogin
,這方法就是登入成功的意思,判斷isRememberMe
,該方法就是判斷token中是夠含rememberMe。所以當我們成功登入時,如果勾選了rememberme選項,那麼此時將進入onSuccessfulLogin方法
我們繼續往下走,跟進rememberIdentity方法,這三個引數上面有解釋我,我的理解是
subject:就是rememberMe欄位的主體
token:成功的身份令牌
authcInfo:成功的身份驗證資訊
然後進入方法體,獲取驗證身份的主體,繼續呼叫過載方法,再跟進去看看
進入後我看到,把accountPrincipals(身份驗證資訊)轉成了byte位元組,然後就是呼叫我們一開始分析的rememberSerializedIdentity
方法設定cookie的值了。
這就是生成cookie的過程,但是還是有些疑惑,convertPrincipalsToBytes
是怎麼實現的和預設祕鑰在哪裡使用了,我們在org.apache.shiro.mgt.AbstractRememberMeManager
的onSuccessfulLogin方法打下斷點看看。
3.1.1、idea除錯
首先我們idea除錯啟動,然後勾選Rememberme,登入。
成功捕獲斷點,跟進去
跟我們上面分析的一樣,我們直接跟進convertPrincipalsToBytes
方法
我們先跟進serialize
,看他怎麼序列化資料的
獲取序列化物件繼續呼叫serialize
,跟進去
看到這我們就能很清晰的看到他是怎麼序列化資料的了。我們繼續回到convertPrincipalsToBytes
方法
接著判斷getCipherService
是否為空,字面意思就是獲取密碼演算法服務,我們也跟進去看看
直接返回了加密演算法服務,在註解中也可以看到,為CBC模式的AES演算法。那他在哪裡定義的呢
我們看到在構造方法中,建立了AES加密服務,並且設定了加密服務的key,這個key就是我們上面定義的。
我們繼續返回convertPrincipalsToBytes
方法中。看到其使用了encrypt
方法對序列化後的principals進行加密,我們也跟進去看看。
首先還是獲取了加密演算法服務(AES),呼叫該演算法的加密方法encrypt
,這個演算法有兩個引數,第一個我們知道就是序列化的位元組碼,我們看第二個,英文意思是獲取加密演算法的key,我們繼續跟進去
我們看到直接返回了加密key,這個key是通過setEncryptionCipherKey
設定的,而setCipherKey
呼叫了setEncryptionCipherKey
,也就是我們在encrypt
方法中的getCipherService
方法設定的.
我們繼續回到encrypt
方法,引數是 bytes和key繼續跟進
判斷是夠建立初始化載體,我們跟進generateInitializationVector
他會呼叫父類的generateInitializationVector
,繼續跟進
我們可以看到,size為128(定義的靜態字串),然後新建長度為16的位元組陣列,呼叫了ensureSecureRandom,跟進看看
就是獲取一個隨機值,nextBytes方法用於生成隨機位元組並將其置於使用者提供的位元組陣列
然後返回,所以ivBytes就是一個隨機的16位位元組陣列
我們繼續回到encrypt
,然後呼叫過載方法,引數為byte陣列、key,16為的隨機位元組陣列ivBytes和布林true。我們繼續跟進
此encrypt
就是我們最終的加密實現演算法。把ivbytes和encrypted一起放入output,然後返回
最後通過rememberSerializedIdentity設定cookie值
上面都是序列的過程,那麼在那裡反序列化呢
3.3、解析cookie
在org.apache.shiro.mgt.AbstractRememberMeManager#getRememberedPrincipals
的方法中,會從cookie中獲取身份資訊,我們在此打下斷點,然後重新整理web頁面,成功捕獲,會通過org.apache.shiro.web.mgt.CookieRememberMeManager
類的getRememberedSerializedIdentity方法獲取bytes,我們也跟進去看看
可以看到該類會獲取cookie,然後解密base64加密的欄位,獲取位元組陣列返回。
我們繼續返回其父類org.apache.shiro.mgt.AbstractRememberMeManager#getRememberedPrincipals
的方法中,會呼叫convertBytesToPrincipals方法,跟生成cookie相反,我們也跟進去看看。
重複程式碼不再一一解釋,直接進入decrypt方法
發現跟加密一樣,通過decrypt解密AES。然後返回
然後反序列化解密的字串
最後呼叫readObject方法,造成反序列化。
值得注意的是該readObejct方法,是shiro重寫過的,重寫了resolveClass
函式,呼叫了ClassUtils.forName(),而原生的則是Class.forName().所以導致很多鏈用不了 ,也是為什麼要匯入cc4的元件了。我們來看看ClassUtils.forName()
看到org.apache.shiro.util.ClassUtils
的forName()方法,他是呼叫了而ClassLoader.loadClass,該方法不支援裝載陣列型別的class,也就是cc1、cc3等用的Transform
陣列類都不行了,但是cc2和cc4是可以的 ,其利用的是javassist的TemplateImpl類實現的,所以不影響。
還有就是通過改造利用鏈實現shiro原生的命令執行,具體檢視https://www.anquanke.com/post/id/192619#h2-3。
參考
https://y4er.com/post/shiro-rememberme-rce/