Shiro Padding Oracle無key的艱難實戰利用過程
? Part1 前言
大家好,上期分享了銀行站的一個Java 的SSRF組合洞案例,這期講講分享一個Shiro Padding Oracle漏洞利用過程。
Shiro反序列化漏洞自16年公布以來,至今已經有6年了,每次攻防比賽都還能遇到,其攻擊大致可分為2種方式:
1 一種就是平時攻擊隊最常用的Shiro-550,對應CVE-2016-4437,影響范圍Apache shiro<=1.2.4。漏洞成因是AES的秘鑰是硬編碼的,漏洞利用的前提是需要猜到加密key。
2 另外一種就是Shiro-721,對應CVE-2019-12422,影響范圍Apache Shiro < 1.4.2。后期Shiro組件的加密key是系統隨機產生的,無法猜到key。但是安全專家很快發現,Shiro的加密方式是AES-128-CBC,CBC加密方式存在一個 Padding Oracle Attack漏洞,可以得到一個存在反序列化數據的AES加密密文,發送給服務端后,shiro組件會解密然后觸發反序列化代碼執行漏洞。這種攻擊方式的前提是需要登錄后臺獲取一個合法Cookie。
一次成功的Shiro Padding Oracle需要一直向服務器不斷發包,判斷服務器返回,攻擊時間通常需要幾個小時。由于此漏洞利用起來耗時時間特別長,很容易被waf封禁,因此在真實的紅隊項目中,極少有此漏洞的攻擊成功案例,大家多數都是在虛擬機環境下測試。
但是有一個紅隊項目,在真實的生產環境中,硬逼著我把這個攻擊給弄成功了,因為現在外圍打點越來越難了,好不容易找到一個口子,也不愿意放棄。期間踩了不少坑,只能說一句:虛擬機環境下和生產環境下漏洞利用是有很大不同的。接下來分享一下具體實戰過程。
Part2 研究過程
虛擬機下測試
首先看一下虛擬機下的漏洞測試過程:
本地搭建一個環境,勾選網頁的Remember Me選項,首先burpsuite抓到一個登陸后的Cookie。

使用ysoserial反序列化工具包生成一個URLDNS的payload java -jar ysoserial-9-echo-all.jar URLDNS http://www.ddd.com > payload.ser
使用工具PaddingOracleAttack來測試 :
java -jar PaddingOracleAttack-1.0-SNAPSHOT.jar http://192.168.237.128:8080/samples-web-1.2.42/ TsXEGDoadwH9nWC3g7WmdN1Ntzbw0kqQMx3ZEaPqL3+++wXZW7jsgImQp8tJi/SDMWjlsWAljJ1bwbyhps/Kf1kK2uu0B5XfyeuAQ7SwO8wGPRcO3u++CW0D5XgSrxJZNI2iQK1sGV4z/hRxyVpXf1unsUUISmNaNiP1o0hULvu3vEgqLaSI435iliJiiarLKh2+UOlAE/lpyJEWgjZvNWFtNHCuIZvBfcJheJ4Thy8OvPytDyASaEwsZtFq2883t8awu9N1wdR2a7g7ONJsVU1yX7d7S8wnrov4PheKVQhiBwLfLa2iMq2MBXrpWtGec8oH7bf48ZD8e2Bbtqu9rV8JKeVbVSjfqYBlUzeLajoboQWtXlNzDtJtbfooqnrgC8BiLvLfElcY8bMiRsmcMovkOxR7Yt5lCVhvfFpUnr3Z7y94lSK3lLUPJ2JxjAzGK45iP5WKreEaQ4S8PyggTmR3dkLtmRfJ4jk4PmbpNDx8BaQAxJIuwjGX2G92JavY 16 payload.ser
配置好后,開始攻擊過程:

大約過了1個小時,工具會返回一個rememberMe Cookies值

使用burpsuite發包后,dns出現記錄,證明漏洞利用成功。


虛擬機下測試,基本上按照上述步驟一步步操作,就能攻擊成功,但是在生產環境中實戰,各種各樣的奇葩問題都出來了,主要遇到了4個坑:
第1個坑:網絡超時問題
在真實實戰環境中,我們的攻擊對象是外網應用系統,持續幾個小時的發包過程,免不了會出現網絡超時的情況。我發現,現有的相關漏洞利用工具或者腳本,只要網絡超時一次,程序就會報錯,整個攻擊過程就會停止掉。因為這些程序沒有對發包失敗拋出異常的情況做出處理,從而導致工具停止工作。
接下來沒辦法只能自己改工具了,因為我用java寫程序習慣了。于是我從github上看了幾個Java寫的Shiro Padding Oracle工具,找到了longofo這個作者寫的工具,看起來不錯。于是下載源碼,使用idea載入,對代碼做了一下修改,代碼很low,但是快速解決問題即可。
如下圖所示:一旦發包失敗,程序會重新發包,可以重試不超過20次,一旦發包成功,就跳出循環,進行下一次發包。待會兒講講為啥要重試20次,哎,太難了。。。
為了便于實時查看攻擊過程中出現了哪些問題,我在異常處理流程中,加了幾行代碼,一旦發包失敗,輸出錯誤提示。

第2個坑:GET請求變HEAD
網絡超時問題解決了,后續我發現工具速度還可以提升,作者的工具發的是GET請求,于是果斷把GET請求換成了HEAD請求,速度提升不少。。。如下圖所示:我把HttpGet方法,換成了自己寫的HttpHead方法。

第3個坑:封IP及代理池問題
持續發包快半個小時的時候,程序一直網絡超時,把我嚇了一跳,我以為把網站跑掛了,結果發現我的IP被封了。后期我發現,大概每攻擊30分鐘左右,IP會被封禁一次,原因是多種多樣的。于是我掛了一個付費的代理池,結果代理池有的代理ip不穩定,經常報錯,而且嚴重拖慢攻擊速度,顯然對于Shiro Padding Oracle 攻擊不適用。哎,真是太難了。。。沒辦法,我把超時重試次數改為了20次,因為20次重試時間足夠長,一旦發現被封IP,我就撥號換一次IP就行了,還是自己寬帶撥號換IP穩定。
第4個坑:payload過長
攻擊時間的長短,取決于ysoserial生成的payload的大小,payload越長,攻擊時間就越長。于是我各種測試,發現Ysoserial工具中的URLDNS及JRMPClient這兩個payload足夠短,比較適合用來做shiro padding oracle攻擊。尤其是JRMPClient這個payload,如果目標系統能出網,就可以在服務端不斷地更換利用鏈去嘗試,利用成功的概率是非常大的。
最終,攻擊成功了,我虛擬機下花了不到1小時共計完成,但是在真實生產環境測試,攻擊成功一次DNS或者JRMPClient攻擊,程序需要跑大約4個小時左右,2次攻擊加起來近9個小時。所以,真是太難了。。。
Part3 總結
1. 沒有0day的時候,就把Nday用到極致吧。
2. 反序列化攻擊的exp,往往都需要視不同的生產環境去做修改,不能生搬硬套。
3. 對于本次案例,由于攻擊過程太長,真正有價值的是URLDNS、JRMPClient,其它的CC鏈 CB鏈的payload長度過長,想要攻擊成功,需要好幾天的時間,那基本上是很難的。
4. Shiro Padding Oracle最好是在下班點之后進行測試,避開業務高峰期,減少對生產環境的業務影響。