URLDNS 利用鏈分析

簡介

URLDNS 這個利用鏈主要用來檢測是否存在反序列化漏洞,有如下兩個優點:

  • 使用java 內部的類進行構造,不依賴第三方庫。
  • 如果目標可以出網,在目標沒有回顯的時候,可以用來驗證是否存在反序列化漏洞。

漏洞成因

java.net.URL 這個類在進行 equals 比較和 hashCode 計算時,會調用 java.net.InetAddress 類的getByName 方法進行 dns 查詢。

下面是分析所用的測試代碼。

@Test
public void test2(){
    try{
        URL a = new URL("http://a.62b41v.dnslog.cn");
        URL b = new URL("http://b.62b41v.dnslog.cn");
        a.equals(b);
        URL c = new URL("http://c.62b41v.dnslog.cn");
        c.hashCode();
    }catch (Exception e){
        e.printStackTrace();
    }
}

URLStreamHandler 類的 getHostAddress 方法最終就會調用 InetAddress 類的 getByName 方法,所以後面的分析就截止到 getHostAddress 方法。

image-20211116210300122

equals

java 官方文檔說,如果兩個 URL 對象被認爲相等,則必須滿足條件之一就是兩個URL 的主機名可以解析到同一 ip 。

https://docs.oracle.com/javase/7/docs/api/java/net/URL.html#equals(java.lang.Object)

Two hosts are considered equivalent if both host names can be resolved into the same IP addresses;

URL.equals -> URLStreamHandler.equals -> URLStreamHandler.sameFile -> URLStreamHandler.hostsEqual -> URLStreamHandler.getHostAddress
  1. 入口

    image-20211116202948423

  2. 進入 URL 類的 equals 方法。

    image-20211116203050106

  3. 進入 URLStreamHandler 的 equals 方法。此處判斷條件是兩 ref 相等,並且 sameFile 爲 true。

    image-20211116203121982

  4. 進入 sameFile 中 hosts 比較部分。

    image-20211116203145504

  5. hosts 比較中就會解析 dns。

    image-20211116203241184

hashCode

在計算一個 URL 對象的 hash 時,一個計算因素就是 url 解析的 ip 地址。

URL.hashCode -> URLStreamHandler.hashCode -> URLStreamHandler.getHostAddress
  1. 入口

    image-20211116203515091

  2. 進入 URL 的 hashCode 方法。

    image-20211116203539015

  3. 調用 URLStreamHandler 的 hashCode 方法,發現其調用 getHostAddress 方法。

    image-20211116203618817

ysoserial payload 分析

參考 ysoserial 生成 payload 的框架。可以看到調用的對應類的 getObject 方法。然後序列化這個對象,輸出。

image-20211116210742667

那麼這裏我們就主要關注 URLDNS 這個 payload 類的 getObject 方法。

image-20211116105846039

可以看到它採取的是 hashCode 方式。從某種角度而言,hashCode 的確比 equals 更穩定,後面會探討。

我們先分析簡單的內容。再來分析複雜的。

HashMap ht = new HashMap();
URL u = new URL(null, url, handler);
ht.put(u, url);

通過調試,可以 ht.put 操作看到最終會調用 URL 對象的 hashCode 方法。

image-20211116211904621

image-20211116211826709image-20211116211846185

一些細節

一. 反序列過程

java 反序列的特性,使得會先創建 HashMap 對象,然後再創建 URL 對象並 put 到 HashMap 中,所以這樣就會觸發 URL 類的 hashCode 方法。

從這個角度來講,我們也可以使用 HashSet 來替代 HashMap 對象。類似類的有很多。

二. 生成時爲什麼不觸發

參考第一條細節,既然如此,那麼在構造 payload 時,也觸發了 URL 的 hashCode 方法,爲什麼此時不會觸發 dns 解析?

爲了不在構造 payload 時觸發,特地自定義了一個繼承 URLStreamHandler 的類,並使用這個類對象構建 URL 對象。

URLStreamHandler handler = new SilentURLStreamHandler();
URL u = new URL(null, url, handler); 

image-20211116212925368

在開始就提到過。

URLStreamHandler 類的 getHostAddress 方法最終就會調用 InetAddress 類的 getByName 方法,所以後面的分析就截止到 getHostAddress 方法。

所以此處通過重寫 getHostAddress 方法,就不會觸發 dns 解析。

另一個 openConnection 方法是抽象方法,必須實現。

三. 引入自定義類仍可反序列化

接上一條,SilentURLStreamHandler 這個類是我們自定義的類,既然引進了自定義類並用它的實例參與構建對象,那麼按道理來說反序列化應該找不到這個類。那麼序列化爲什麼不報錯呢?

主要是由於傳入的對象最終會被 transient 修飾。構造函數的內容。

image-20211116214721658

此屬性被 transient 修飾。

image-20211116214737024

而 transient 修飾的作用,簡單地說,就是讓被修飾的成員屬性變量不被序列化。這樣,序列化的 URL 對象的 handler 變量就爲 null 。也就不存在與自定義類相關聯的問題。

在反序列化的過程中,會重新創建一個 URLStreamHandler ,以便正常使用功能。

image-20211116225640628

四. 最後爲何將 hashCode 置 -1

Reflections.setFieldValue(u, "hashCode", -1);

這個代碼有什麼作用?

URL 對象 hashCode 方法只有當 hashCode 等於 -1 時纔會計算 hash,纔會觸發域名的 dns 解析。而在創建 payload 時已經計算過值,所以爲了反序列化時再次進行計算觸發就必須將其置爲 -1。

image-20211116215801863

五. 爲何選 hashCode 這條鏈

由漏洞的成因可知,有兩種觸發 dns 解析方法,爲什麼選擇 hashCode ,而不是 equals。

主要是爲了簡單與通用。

hashCode 觸發簡單,包含在 HashMap、HashSet 即可。在構建時只需要注意將第四點,通過反射將 hashCode 重設爲 -1。

而 equals 鏈想要觸發 URL 解析,對 url 有一定要求。可以看到,在走到解析域名那步,需要經過多次比對。

image-20211116221550848

image-20211116221627816

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章