摘要:安全测试的目的实际上就是找漏洞,漏洞就是Bug,是违反了信息安全三原则(机密性、完整性和可用性,简称CIA)的Bug。让语句通顺一点,也可以说,只要违反了信息安全三原则的Bug都是漏洞。
安全测试的目的实际上就是找漏洞,漏洞就是Bug,是违反了信息安全三原则(机密性、完整性和可用性,简称CIA)的Bug。让语句通顺一点,也可以说,只要违反了信息安全三原则的Bug都是漏洞。
读者可以根据这个定义去公司的Bug库里面找一找,也许你已经找到了很多漏洞,如果是个全新的漏洞,你再给它起一个听起来很牛的名字,比如说跨站点脚本漏洞也被称为“会话骑行”,点击劫持漏洞根据不同的利用场景,也可以叫移形换影,简单的讲就是在目标网站上覆盖了一层透明的图层。
上面的命名不是很严谨,不过听起来很有趣。有趣很重要,现在要靠兴趣去推动学习了。
文章内容主要是讲解反序列化漏洞的测试方法。对于测试人员来说,不需要深入分析序列化漏洞在代码层面的成因,去构造相对复杂的漏洞调用链,只需要根据实际的测试环境证明漏洞存在或不存在,获得一个明确的测试结果即可。
首先,会让读者了解序列化和反序列化的概念,再通过实现java原生序列化功能,获得用于反序列化漏洞测试数据的实例,最后通过构建一个测试场景,复现第三方组件存在的反序列化漏洞。
测试场景的搭建全部用安全测试工具SafeTool-51testing实现,包括含有反序列化漏洞的靶机网站,用于“搭桥”的LDAP服务,用于“传送”测试代码触发漏洞执行的Web服务。
要理解序列化,我们先理解何为序列。序列是个数学上的概念,意为被排成一列的对象或事件,既然是排成一列就意味着顺序排列,或者说是有规则的排列,重点是序列中对象的先后关系必须一目了然。计算机的本质就是处理数据,所以计算机领域的序列化指的是数据序列化,把动词和名词调过来,称为序列化数据。
开发语言也套用了这个概念(序列化数据),把一段代码以二进制的形式保存在内存、文件或数据库中,方便存储、读取和网络传输,目的是持久化存储和多平台网络通信。而Java是面向对象编程的开发语言,那Java的序列化就是把Java对象按一定规则和顺序以二进制形式保存在内存、文件或数据库中,目的是持久化存储和多平台网络通信。
这里只是以JAVA举例,实际上第三代开发语言都存在序列化功能。
知道了序列化的含义,反序列化就好理解了,就是从内存、文件、数据库或网络传输中把这段序列化的二进制数据,按规则和顺序重新恢复成Java对象。当然了,序列化数据最常见的用途还是作为网络通信的数据发送,现在不是分布式异构系统很流行吗,当一个子系统要去调用另一个子系统实现的功能的时候,序列化数据就是解决这个问题的方法之一了,具体的实现还是需要一个协调机制的,例如,Java的RMI框架(Remote Method Invocation-远程方法调用)。
序列化对象要么包含数据,要么包含功能,要么既包含数据也包含功能。包含数据影响不大,但是一旦包含可执行相关功能的代码,且未经过滤审查,就很有可能被恶意人员利用,对目标系统造成不可控的损失。
Java的原生序列化功能实现起来非常简单,即如图1-1所示,实现java.io.Serializable接口即可。
图1-1
我们再使用图1-1所示的序列化对象,输出用于测试的序列化数据,序列化数据的功能是弹出一个计算器,如图1-2所示。
图1-2
根据图1-2所示的代码内容可知,我们可以将序列化数据写入内存,这里是直接将序列化数据输出显示在终端上,也可以将序列化数据写入文件中,便于持久化保存。
这里我们使用第一种方法,将用于测试的序列化数据写入内存,如图1-3所示。
图1-3
由此我们就得到了一段可以在目标系统上弹出计算器的序列化数据,下一步就是把这段测试数据“喂”给目标系统的反序列化功能,触发漏洞执行,如图1-4所示,为模拟目标系统的反序列化的代码。
图1-4
根据上一小节的模拟步骤,我们可以总结出测试反序列化漏洞的测试方法,一共四步,如图1-5所示。
图1-5
据笔者的了解,目前在生产环境部署的系统很少使用开发语言自带的序列化功能,通常都是使用效率和安全性更高的第三方组件,或者是公司内部自主开发的实现类似序列化功能的组件,这样的话安全性更高,也可以更好的限制序列化对象的影响域,出了问题也方便回溯。
因此,接下来演示的反序列化漏洞的复现场景,虽然是以FastJson组件为例,但是不局限于FastJson组件,你可以将任何实现了反序列化功能的待测组件部署在靶机系统中,在根据实际生产环境的调用规则,扩展用于“搭桥”的服务,或用于“传送”测试数据的服务等相关插件。
什么是搭桥?由于网络环境的安全性越来越高,漏洞利用的条件也越来越苛刻,把一个高风险的漏洞直接“喂”给系统往往需要很复杂的传递路径,这条传递路径就是桥,传递路径上经过的各种系统或服务就是在“搭桥”。
如果还不是很理解,那么通过下面的场景演示,相信能让你有一个直观的认识。
首先,我们需要在了解了待测系统是如何实现序列化功能的前提下,实现用于读取序列化功能的代码,如图1-6所示,模拟服务端实现的反序列化功能代码。
图1-6
接下来,构造含有测试代码的序列化对象,如图1-7所示。
图1-7
并将其编译成class文件,部署在安全测试工具的指定目录下,如图1-8所示。
图1-8
接下来,编写通过LDAP协议将含有测试代码的序列化数据注入到模拟服务端并触发测试代码执行的“POC”脚本,如图1-9所示。
接下来,启动安全测试工具,并在菜单栏中选择“渗透测试”-> “服务平台”,如图1-10所示。
图1-10
在服务平台中输入命令“start assist”,接着输入“ldap”,启动平台的LDAP服务,如图1-11所示。
图1-11
在服务平台中输入命令“start assist”,接着输入“target”,启动平台的靶机系统,如图1-12所示。
图1-12
在服务平台中输入命令“start assist”,接着输入“webfile”,启动用于传送测试代码的web服务,如图1-13所示。
图1-13
接下来,执行“POC”脚本,触发整个传递路径启动,即“POC”脚本 -> “靶机服务”-> “LDAP”服务 ->“Web”服务 -> “靶机服务”->成功触发测试代码执行,如图1-14所示。
图1-14
来源:贪吃的大白