说在前面
本系列博客是博主对《模糊测试:强制发掘安全漏洞的利器》(Fuzzing:Brute Force Vulnerability Discovery)所做的读书笔记。
安全漏洞发现方法
安全漏洞的发现方法可以分为以下几种:
- 白盒测试:对源代码进行分析
- 黑盒测试:仅通过外部观测来测试系统,只需要测试者能够进行输入和观测输出就可进行
- 灰盒测试:介于黑盒测试和白盒测试之间,通过对二进制文件进行逆向工程获得比黑盒分析更多的信息
模糊测试(Fuzzing)
定义
通过向应用提供非预期的输入并监控输出中的异常来发现软件中的故障的方法。模糊测试利用自动化或非自动化的方法重复地向应用提供输入。
模糊测试器(fuzzer)
用于模糊测试的模糊测试器分为两类:
- 基于变异的模糊测试器(mutation-based fuzzer):对已有的数据样本进行变异来创建测试用例
- 基于生成的模糊测试器(generation-based fuzzer):该类测试器为被测系统使用的协议或是文件格式建模,基于模型生成输入并据此创建测试用例
模糊测试各阶段
1、确定测试目标
如果要决定第三方应用模糊测试的测试目标,首先需要参考第三方应用的供应商历史上曾出现过的安全漏洞。除应用程序外,应用包含的特定文件或库也可以是测试目标(优先测试多个应用程序之间共享的二进制代码,因为这些代码影响的用户更多,风险更大)
2、确定输入向量(input vector)
几乎所有可被利用的安全漏洞都是因为应用没有对用户的输入进行校验或是进行必要的非法输入处理。是否能找到所有的输入向量是模糊测试能否成功的关键。寻找输入向量的原则是:从客户端向目标应用发送的任何东西,包括头headers,文件名file name,环境变量environment variables,注册表键registry key,以及其他信息,都应该被看作是输入向量。
3、生成模糊测试数据
使用自动化过程来生成数据
4、执行模糊测试数据
在该步骤中,一般会向被测目标发送数据包、打开文件或是执行被测应用,同3,这个步骤必须是自动化的
5、监视异常
模糊测试需要根据被测应用和所决定采用的模糊测试类型来设置各种形式的监视。
6、判定被发现的漏洞是否可被利用
如果在模糊测试过程中发现了一个错误,依据审计的目的,可能需要判定这个给被发现的错误是否是一个可被利用的安全漏洞,这种判定过程是典型的手工过程。
模糊测试的局限性
模糊测试适用于找到特定被测系统中的特定弱点,因此,模糊测试能够发现的安全漏洞也是有一定局限性的。以下是模糊测试器难以发现的典型安全性漏洞:
访问控制漏洞
模糊测试器并不理解程序逻辑,它并不知道普通用户并不能访问管理员区域。
糟糕的设计逻辑
模糊测试器不适合发现程序中的设计缺陷
后门
如果一个模糊测试器对被测应用的结构只有很少的了解,后门看上去与其他正常的逻辑没有什么不同。比如在对口令域进行模糊测试时,如果某个输入导致应用发生崩溃,这种漏洞通常可以被发现;但一个通过随机猜测可以被发现的,能进入系统的硬编码口令就不会被发现
破坏
内存破坏问题通常会导致被测应用的崩溃,这类问题可以根据与拒绝服务攻击类似的情况来加以识别。然而,有些内存错误问题会被被测应用所掩盖,因此简单的模糊测试器永远都发现不了这类问题。
多阶段漏洞(MuliStage Vulnerability)
模糊测试对识别单独的漏洞很有用,但通常而言,模糊测试对那些小的漏洞链构成的漏洞或是让人不感兴趣的事件构成的多向量攻击的识别作用不大。
模糊测试方法
模糊测试方法分为五大类:
1、预生成测试用例
该方法要求研究特定的规约,理解该规约支持的数据结构和可接受的值的范围,然后依据这些理解生成用于测似乎边界条件或是违反规约 的测试用例。
- 优点:用例一旦被创建,很容易被复用,用于测试某种协议或文件格式的不同实现
- 缺点:缺乏随机生成,一旦测试用例列表中的用例被执行完,测试就只能结束
2、随机生成输入
随机方法简单地向目标应用发送伪随机数据,查看结果输出。
- 优点:快速识别目标应用中是否有非常糟糕的代码
- 缺点:低效、很难找到导致系统崩溃的数据
3、手工协议变异测试
在此种测试方法中,在加载了目标应用后,测试者仅仅通过输入不正确的数据,试图使服务器崩溃,或是诱发一些不正常行为。
- 优点:分析中能够在安全审计中充分发挥自己的经验
- 缺点:较初级
4、变异或强制性测试
指模糊测试器从一个有效的协议样本或是数据格式样本开始,持续不断的打乱数据包或是文件中的每一个字节、字、双字或是字符串。
- 优点:整个强制性模糊测试的过程都可以完全自动化
- 缺点:低效,因为许多CPU的周期会被浪费在生成完全不可解析的数据上
5、自动协议生成测试
在此种方法中,首先要做的是对被测应用进行研究,理解和解释协议规约或文件定义,这种方法基于创建一个描述协议规约如何工作的文法(grammar)。采用这种方法,可以识别出数据包或是文件中静态或动态的部分,动态的部分就是可以被模糊化变量替代的部分。随后,模糊测试器动态分析包含了静态和动态部分的模板,生成模糊测试数据,将结果数据包或是文件发送给被测应用。
优点:是一种更高级的强制性方法
缺点:需要花较多时间在生成文法或是数据格式的定义上
模糊测试器类型
本地模糊测试器
命令行模糊测试器、环境变量模糊测试器、文件格式模糊测试器
远程模糊测试器
1、网络协议模糊测试器
网络协议模糊测试器主要分为两个类别:面向简单协议的模糊测试器和面向复杂协议的模糊测试器
简单协议
简单协议通常仅有简单的认证或根本没有认证。这类协议通常基于可打印的ASCII字符而不是二进制数据,简单协议不会包含长度或是校验域。比如FTP协议,在FTP协议中,所有控制信道上的通信都使用ASCII文本,对认证来说,只需要简单文本形式的用户名和口令就可以完成认证。
复杂协议
复杂协议通常由二进制数据和偶尔包含的人可读的ASCII字符串构成。认证可能需要通过加密或是某种形式的混淆来实现,比如微软远程过程调用(MSRPC)协议就是一个复杂的协议,它是一种二进制协议,在数据传输之前需要经过好几个步骤才能建立通信信道,协议需要长度描述域和分解域。
2、Web应用模糊测试器
3、Web浏览器模糊测试器
内存模糊测试器
内存模糊测试器的一种实现方法是对进程执行一次快照,在生成快照后迅速向该进程的输入处理子例程中注入故障数据。当执行完一个测试用例后,恢复上次的快照并注入新的数据,重复以上所有过程直到所有测试用例都执行完成。
优点
- 快速:这种方法不需要带宽,甚至在测试过程中不需要执行从网络上接收数据包到实际解析数据包之间的代码,由此提升了测试性能
- 捷径:如果一个协议使用了定制的加密或是压缩算法,或是程序内到处都是数据校验代码,在这种情况下,内存模糊测试器能够在解压,解密或是数据校验完成后的某个时间点创建一个快照,这样就避免了花费时间创建一个能够处理加密、压缩或是数据校验的模糊测试器
缺点
- 假相:内存模糊测试是直接将数据注入进程的地址空间,因此有可能被注入的数据根本不可能通过从外部源输入的数据来产生
- 可重现性:虽然一个异常可能预示着一个可被利用的漏洞,但就算通过内存模糊测试发现了这样的异常,测试者仍需要从外部输入找到重现这个异常的外部数据,而找到外部数据可能非常耗时。
- 复杂性:实现内存模糊测试非常复杂
模糊测试框架
模糊测试框架可用于对多种目标进行模糊测试。模糊测试框架就是一个通用的模糊测试器或是通用的模糊测试库,它简化了多种不同类型的测试目标需要的数据格式,如SPIKE和Peach工具。
优点
- 可重用性:在模糊测试不同目标时,该框架可以被反复使用
- 社区介入:多个社区开发者共同开发
缺点
- 局限性
- 负责性
- 开发时间:开发极其耗时
常用的协议元素
名字-值对
无论是二进制协议还是简单文本协议,其中的数据经常以名字-值对(如size=11)的形式表示。一个一般性规则是,通过对名字-值对中的值进行模糊测试,通常可以发现潜在的安全漏洞。
块识别符
块识别符是用来标识二进制数据块的数据类型。模糊测试可以发现一些文档中没有记录的块识别符,这些文档中没有记录的块识别符可能会接受额外的数据类型,并带来安全风险,因此需要进行模糊测试
块大小
块通常由诸如名字-值对这样的数据,以及紧挨着数据的一个或多个字节组成。紧挨着数据前方的这些字节用于说明块中的数据类型、块的大小。如果要替换块中的数据进行模糊测试,一定要根据实际数据的大小调整块大小的值,只有这样,被测应用才能准确识别数据块中的数据。
缓冲区溢出和缓冲区下溢发现
修改数据包中表示块大小的值,使其比实际数据块的大小稍大或稍小一些,然后观察结果输出。
校验和
如果文件包含校验和,应用程序通常会在发现校验和不正确后放弃对文件的处理,因此会影响模糊测试。PNG图像格式采用了校验和,在对带校验和的文件格式进行模糊测试时,务必要让模糊测试器把校验和考虑在内,模糊测试器可以自行计算校验和并将其写入文件,这样就可以保证被测应用能够正常处理用于模糊测试的文件。