<code>apache common beanutils</code>是<code>apache common</code>工具集下的另一个项目,提供了一系列对javabean的操作方法。什么是javabean:什么是javabean。
如下<code>cat</code>就是一个javabean。
<code>commons-beanutils</code>中提供了一个静态方法<code>propertyutils.getproperty</code>,让使用者可以直接调用任意javabean的<code>getter</code>方法。
此时<code>propertyutils.getproperty</code>会自动调用<code>cat</code>的<code>getname</code>方法,获取返回值。其实就是会自动调用参数1的getter方法。
其实这个利用链上半段使用的还是<code>priorityqueue</code>,而<code>priorityqueue</code>的核心就在于找可以利用的<code>java.util.comparator</code>对象。
在<code>commons-beanutils</code>包中就存在一个:<code>org.apache.commons.beanutils.beancomparator</code>。
<code>beancomparator</code>是用来比较两个javabean是否相等的两个类,实现了<code>java.util.comparator</code>接口。查看一下他的compare方法。
这个方法接收了两个对象,如果<code>this.property</code>属性值为空,则直接比较这两个对象。如果不为空,则使用<code>propertyutils.getproperty</code>获取两个对象的<code>this.property</code>的值。然后进行比较。
上面说了<code>propertyutils.getproperty</code>这个方法会自动去调用一个<code>javabean</code>的<code>getter</code>方法,这个点是任意代码执行的关键。有没有什么getter方法可以执行恶意代码呢?
当然是有的,在<code>templatesimpl#getoutputproperties()</code>方法中会调用<code>newtransformer</code>方法(后面的利用链就不说了,不明白的去了解一下templatesimpl的利用链)。并且是<code>public</code>。支持外部调用。而且<code>getoutputproperties</code>是以get开头的,符合getter的定义。
所以,<code>propertyutils.getproperty( o1, property )</code>这段代码,当<code>o1</code>是一个<code>templatesimpl</code>对象,而<code>property</code>的值为<code>outputproperties</code>时,将会自动调用getter,也就是<code>templatesimpl#getoutputproperties()</code>方法,触发代码执行。
最终代码如下
所需的maven
在shiro550的实际利用中,目标可能没有使用<code>commons-collections</code>。这就导致无法使用cc链进行rce。这个时候还有其他方法可以进行rce吗?
可以看到shiro的pom.xml中有<code>commons-beanutils</code>的依赖,版本为<code>1.8.3</code>。也就是说shiro本身自带了<code>commons-beanutils</code>依赖,只要使用了shiro组件,就必定有<code>commons-beanutils</code>。
那么是否可以利用本文提到的<code>commonsbeanutils</code>链进行利用?
当我构造好payload发送过去的时候,服务端报错了,报错如下
查看报错<code>java.io.invalidclassexception: org.apache.commons.beanutils.beancomparator; local class incompatible: stream classdesc serialversionuid = -2044202215314119608, local class serialversionuid = -3490850999041592962</code>。这个错误是什么意思?
什么是<code>serialversionuid</code>?
如果两个不同版本的库使用了同一个类,而这两个类可能有一些方法和属性有了变化,此时在序列化通信的时候就可能因为不兼容导致出现隐患。因此,java在反序列化的时候提供了一个机制,序列化时会根据固定算法计算出一个当前类的serialversionuid值,写入数据流中;反序列化时,如果发现对方的环境中这个类计算出的serialversionuid不同,则反序列化就会异常退出,避免后续的未知隐患。 当然,开发者也可以手工给类赋予一个serialversionuid值,此时就能手工控制兼容性了。
所以出现这个错误的原因就是我序列化的时候用的是<code>commons-beanutils 1.9.4版本</code>。而shiro自带的是<code>commons-beanutils 1.8.3版本</code>,出现了serialversionuid对应不上的问题。
解决方法也很简单,将<code>commons-beanutils版本</code>修改为<code>1.8.3</code>即可。
当我修改完版本之后,重新生成序列化文件的时候报错了。错误如下
提示找不到<code>comparablecomparator</code>这个类。
跟踪堆栈信息,
看到<code>org.apache.commons.collections.comparators.comparablecomparator;</code>,从包名即可看出,这个类是来自于commons-collections。
<code>commons-beanutils</code>本来依赖于<code>commons-collections</code>,但是在shiro中,它的<code>commons-beanutils</code>虽然包含了一部分<code>commons-collections</code>的类,但却不全。这就导致正常使用shiro的时候不需要依赖于<code>commons-collections</code>,但反序列化利用的时候需要依赖于<code>commons-collections</code>
难道没有<code>commons-collections</code>就无法进行反序列化利用吗?当然有。
分析<code>comparablecomparator</code>在哪里使用了,在<code>beancomparator</code>构造方法中使用了,如下图。下面那个构造方法可以指定<code>comparator</code>,就无需实例化<code>comparablecomparator</code>。
现在的问题是我们如何去寻找一个的类,这个类需要满足以下条件
1.实现java.util.comparator接口
2.实现java.io.serializable接口
3.java、shiro或commons-beanutils自带,且兼容性强。则不需要其他的依赖。
p牛找到了<code>caseinsensitivecomparator</code>类。
这个caseinsensitivecomparator类是java.lang.string类下的一个内部私有类,其实现了comparator和serializable,且位于java的核心代码中,兼容性强,是一个完美替代品。
通过<code>string.case_insensitive_order</code>即可拿到上下文中的<code>caseinsensitivecomparator</code>对象,用它来实例化<code>beancomparator</code>:
修改好代码之后,又报错了,
integer无法转换为string。那么将<code>1</code>改为<code>"1"</code>即可
发送这个利用链生成的payload,成功执行任意代码: