凭借Scapy, radamsa工具和少量明文数据包对专有协议进行Fuzzing测试
简介
作为安全顾问,我们以客户所雇佣的枪手身份来代为执行针对应用程序的黑匣子安全测试。通常,我们必须对那些使用自己专有方案而非常规协议(如HTTP)进行通信的应用程序的安全性进行评估。
最近,我们接到了一个时间比较紧急的任务,涉及到对一个具有私有通信协议(包裹在SSL / TLS隧道内)的定制型应用程序的安全性进行测试。
本文旨在描述我们解决任务中所发生的有关技术限制及时间限制问题的过程,并通过基于基于缺陷注入的自动软件测试技术来成功测试和查找应用程序中的错误。
什么是专有协议?
大致来说,专有协议是一种未被开放标准定义或由个人或公司控制的协议。在大多数没有官方文档(关于程序内部工作原理)的情况下,使用专有协议的应用程序很难与使用封闭协议的应用程序通信。
无需多说,不同协议的复杂程度有所不同,有些协议比其他的更复杂:例如,给定的协议可能非常简单——其基于ASCII字符,易于理解,而且很容易与消息的其他元素相关联。
另一方面,存在更复杂的协议。这些协议可能涉及不同的数据表示,包括二进制或序列化数据,校验值,以及一些不是很明显的字段。
尽管有些协议是专有的,但或是因为供应商提供了官方文档(如FInancial eXchange - FIX,广泛用于股票交易),或是该协议过去曾经被发烧友和开源倡导者进行过逆向,这些协议通常配有说明文档——一个重要的例子便是AOL的即时通讯协议OSCAR。
虽然网络协议的逆向工程是可能的,但这是一项麻烦的任务,需要耐心,技术,最要紧的是还有大量时间。大多情况下很难满足以上所有这些条件,所以我们需要一个替代方案来解决我们手头上的问题。
使用fuzzing进行自动的软件安全性测试
Fuzzing在过去几年中是一个非常受重视的领域,学术界和行业中都出现了一些更先进的方法。
尽管存在如进化fuzzing(可以利用代码覆盖的反馈并利用遗传算法生成更好的输入)这样更先进和现代化的方法,以及其他依赖约束求解器,concolic和符号执行等概念的新技术,但早期的fuzzing 技术被大致分为基于突变和基于生成的两种。
基于突变的fuzzing通常被称为“dumb fuzzing”,因为它的作用是执行输入的随机突变并且吐出被破坏的数据作为结果。然而,不要被它的名字所欺骗:dumb fuzzing是非常高效的,据称应用该技术在通用流行软件中已发现了大量的错误。
另一种流行的策略被称为基于生成的fuzzing。这种技术常用于如下情况:协议或文件格式已经经历过fuzzing测试,生成的测试用例大多数符合协议,但是带有一些异常字段(包含了已知会导致意外行为的数据),这些数据包括大字符串,包含shell元字符的恶意输入,负数,非常长或低于正常值的数字等等。
利弊分析
基于突变的fuzzing具有快速建立的优点,并且实际上可以获得良好的效果; 然而,在实现高代码覆盖率(您的测试样本将在此处发挥关键作用)上此技术可能并无优势,在将校验值发送到应用程序进行处理之前需要对其进行调整的情况下也是如此——因为校验和的无效应用程序很可能会拒绝其余部分的输入,以至于测试根本没有进行到潜在的代码脆弱区域。
基于生成的更有可能具有更大的代码覆盖率,而牺牲创建时间更长。 此外,fuzzing神话般的创造力以及突变和启发式数据破坏的巧妙性将决定该技术在查找错误方面能否成功。
案列及方法
幸运的是我们面对的协议虽然是专有的,但其基于ASCII,而且似乎也并没有过于复杂。但是,考虑到时间限制,花费时间来了解协议本身并创建一个基于生成的fuzzer 来生成测试用例是不可行的。此外,当别处有很好的突变引擎,我们为什么还要花费宝贵的时间写出我们自己的呢?
同时考虑到协议本身:由于没有计算校验值及遵守其他严格的协议架构的必要,我们选择了基于突变的方法进行fuzz测试。
对于本次测试,我们手头有的仅仅是被捕获的客户端和应用程序(我们想要测试的)之间用以通信的明文数据包(PCAP)。
我们很注意确保能获得几个有关被测应用程序的不同功能和用途的PCAPs样本; 这样我们可以保证我们的fuzzer能通过极端的测试用例突出针对该应用程序的可用攻击面的不同区域,提高代码覆盖率,从而增加我们发现错误的机会。
在这种情况下,客户端和应用程序之间的所有流量都被包裹在TLS / SSL中,请求捕获非加密流量非常重要,因为我们只需要应用程序级通信,而不是传输或更上层流量。
另外,我们必须fuzz的协议以某种状态机的形式运行:在握手消息(也可能被fuzzed)之后,为了进一步处理消息,它会按某种顺序预期其他一些信息。
这意味着如果我们发送了握手信息,并在其期望时发送一个格式错误的消息(例如登录消息),我们将由于之前的拒绝而无法fuzz 任何登录以后的事情。
为了解决这个问题,我们为我们的Fuzzer增加了更多的随机性:PCAP中只有一定比例的有效载荷将突变。 这将给我们更多的排列和发送干净握手消息及N-1消息的能力,但只有最后的消息(N消息)将被fuzz; 或者之后fuzz握手和干净信息,或者清理握手和格式错误的登录信息,并清除其他消息等等。
工具
为了能够组建一个可以执行上述任务python脚本,我们使用了如下工具:
Scapy: 一个类似瑞士军刀的库(针对所有与网络相关的情况),它可以对PCAP数据包中的数据进行解析,读取,写入及重播。
radamsa:一款被许多安全研究人员选择的流行fuzzing测试工具(基于突变的)。
技术细节:将它们组合起来
在对我们想要做的事、哪些fuzzing 策略最适合我们的案例以及为了完成任务需要哪些工具做出了简要描述后,现在是时候粗略地分解一下我们针对应用程序进行的简单模糊fuzzing测试的步骤:
步骤 0:定义一个fuzz因子——例如,只有20%的数据包会发生变异
步骤 1:解析PCAP数据包,仅寻找客户端到服务器的通信流量
步骤 2:由于有些PCAP数据包有时包含的内容与我们的目标无关(例如TCP 协议的3次握手信息和其他信令),因此我们需要在捕获的数据包中找到包含实际有效载荷的那些个。
步骤 3:进入无限循环:
步骤3.1:提取有效载荷,根据fuzz测试因子随机决定是否应进行fuzz ; 如果fuzz,将有效载荷输入到突变引擎中
步骤3.2:获取突变数据
步骤3.3:向目标应用程序发送受损的有效载荷(或清洁的有效载荷,取决于是否被fuzz过)
步骤3.4:洗涤,冲洗,重复。搁置。
步骤4:观察异常并执行分流(如果适用)
事实上,由于从黑盒测试的角度来看,针对异常,我们没有监测仪器甚至都无法进行观察,所以第四步并不在我们的范围内。客户端可以自行辨别异常,我们的fuzzing脚本检测到连接到目标后发送每个被破坏的测试用例。虽然速度很慢,但是在一定程度上我们可以观察到目标应用程序是否崩溃。
后来在参与过程中,客户告知我们,fuzzer 触发了四次异常; 其中三个是独一无二的。 我们没有足够的时间进行任何类型的异常分析,但是fuzzed 的测试用例会触发未处理的异常,并可能严重影响本应始终处于联机状态的服务的可用性。
在我们的Github中可以找到上述步骤的开源实现。重要的是说这些只是为了说明这篇文章中讨论的想法。示例代码几乎不能用于实际应用程序,但经过一些修改可能适合不同的需求。
结论
即使在最简单的形式中,fuzzing也可能是发现漏洞的有力工具,它应该在每个信息安全工程师的字典中。
当对使用专有或无帮助文档的协议的应用程序进行测试时,目标应用程序使用的不同形式的样本PCAP数据包对于测试更大的攻击面及增加发现错误的可能性非常有帮助。 为了使那些可能触发微妙错误并遍布隐藏在代码逻辑之内的角落中的样本测试用例发生突变,一个具有创造性和非常规启发式的好的fuzzing 引擎也是必要的。
参考文献
1. Github link name
https://github.com/blazeinfosec/pcrappyfuzzer
2. AOL's Oscar Protocol
https://en.wikipedia.org/wiki/OSCAR_protocol
3. Babysitting an army of monkeys - presentation at CanSecWest 2010 by Charlie Miller https://fuzzinginfo.files.wordpress.com/2012/05/cmiller-csw-2010.pdf
本文由看雪翻译小组 jason龙莲 编译,来源Wildfire Labs
转载请注明来自看雪社区
热门阅读
点击阅读原文/read,还有更多干货等着你~