[备份]反序列化漏洞的防御与拒绝服务

最近我一直在做拒绝服务漏洞相关的时间,并收获了SpringWeblogic的两个CVE(还有一些报告也许正在审核和修复中)但DoS漏洞终归是鸡肋洞,并没有太大的意义,比如之前有人说我只会水垃圾洞而已,所以在以后可能打算做其他方向

早上和pyn3rd师傅聊天,希望写一篇DoS漏洞的分享,于是写了这篇水文,算是拒绝服务漏洞的完结篇

 

基础篇

编写一个恶意的类

编写一个普通的反序列化漏洞代码,执行后会弹出计算器

以上的恶意类其实没有意义,因为目标系统中不会存在这样的恶意类,只有目标程序中存在该类才可以

于是大家开始挖掘gadget以构造恶意类用来执行代码或命令

当我将gadget替换为CC6链后,只要目标系统包含了Commons Collections依赖则可以RCE

 

黑名单修复

假设作为开发者,这时候的修复手法有两种

于是很多项目采用了黑名单的方式进行修复

这时候修改我们的漏洞代码

运行后报错:说明成功防御了Commons Collections的反序列化漏洞

类似的黑名单参考:Apache OFBIZ

commit: https://github.com/apache/ofbiz-framework/commit/af9ed4e/

 

白名单修复

在安全中,黑名单永远都是不安全的,因为总会有新的姿势和新的绕过,因此我们采用了白名单的方式进行修复

参考Spring-AMQP曾经防御反序列化漏洞的方式:添加类似的白名单

参考commit: https://github.com/spring-projects/spring-amqp/commit/36e5599/

 

readObject

当我们使用了这样白名单后,确实不存在RCE漏洞

但实际上存在拒绝服务漏洞的可能性

首先从本地白名单对象入手

假设本地白名单类的readObject方法中包含了类似以上的代码,构造出以下这样的Payload即可DoS

 

readExternal

Serializable序列化时不会调用默认的构造器而Externalizable序列化时会调用默认构造器

有时我们不希望序列化那么多,可以使用Externalizable接口

其中writeExternalreadExternal方法可以指定序列化哪些属性

假设某个白名单类包含了类似下方的代码,则存在拒绝服务漏洞

构造恶意对象Payload触发

 

反序列化炸弹

最坏的情况:如果白名单本地对象都是安全的,没有拒绝服务的可能性,还有办法吗

可以使用JDK中的反序列化炸弹实现拒绝服务漏洞

出自Effective Java的原版反序列化炸弹(原代码链接)

使用HahsMap和也可以做到类似的效果

反序列化炸弹会得到类似的数据结构,是一个100层深的图(Graph)结构

img

由于本文重点不在于反序列化炸弹,所以原理不再对原理进行分析,有兴趣可以搜索得到一些结果

关于反序列化炸弹的修复:JEP290

提交给Apache OFBIZ后认为这只是潜在的漏洞,不能直接触发,修复后给予致谢但无CVE

img

 

漏洞挖掘思路

有了以上的内容,对于如何挖掘这样的漏洞,应该有一些思路了

 

如何扫描

扫描主要是如何确认readExternal方法里存在数据初始化

例如扫某logic这样非开源的项目,难免要用到字节码相关的技术

大概的扫描逻辑如下

这里提到的某种规则,在之前一篇文章中有详细说明

跟着三梦学Java安全:半自动挖洞

这两种数组初始化的字节码是不同的

对应字节码如下,可以看到分别使用NEWARRAYANEWARRAY指令

在分析时需要注意

在分析进入方法时,首先调用到visitCode方法,在这里手动给参数上污点

处理污点的传递(如果a是污染那么b=a.func()中的b也将是污染)

上面这一串代码的作用是能够处理这样的情况

最终在NEWARRAY指令的操作数中判断污点(ANEWARRAY指令类似)