一种得分导向的智能合约模糊测试方法

2022-07-01 08:17陈可欣刘嘉勇
现代计算机 2022年8期
关键词:测试用例以太调用

陈可欣,刘嘉勇,贾 鹏

(四川大学网络空间安全学院,成都 610065)

0 引言

近年来,加密货币和区块链技术在行业和学术界获得了极大的普及和关注。区块链的发展一共经过了以下两个阶段:第一个阶段主要解决不信任的情况下网络对等方之间的安全转账问题。第二个阶段出现了许多支持智能合约的增强型区块链平台,其中最受欢迎的平台之一是以太坊,它使用图灵完备的编程语言增强了区块链平台,使开发人员可以编写智能合约和去中心化应用程序。

随着以太坊的不断发展,智能合约的数量也在急速增长。智能合约的概念最早是在1995年被提出的,是一种旨在以信息化方式传播、验证或执行合同的计算机协议。智能合约将与合约相关的所有条款以及逻辑全都编写到一段代码中去。智能合约可以进行自我执行以及自我验证,在执行的过程中不需要人工进行干预。然而,智能合约不断发展的同时,其存在的安全漏洞也逐渐显露。近年来,利用以太坊智能合约中的安全漏洞进行攻击的新闻报道越来越多。一个著名的事件就是针对去中心化的自 治 组 织 DAO (decentralized autonomous organization,DAO)的攻击,造成了6000 万美元的损失。智能合约易受攻击的原因主要有以下几个方面:

(1)智能合约的运行依赖于底层的区块链平台以及其他的协作合约,合约开发者没能完全理解这些合约之间以及合约与底层区块链平台之间隐含的关系。

(2)智能合约的编程语言与运行环境对于合约开发者来说都是全新的,这些工具本身也还不够成熟,合约开发者没能很好地处理这些工具自身的不足。

(3)区块链具有不可篡改的性质,智能合约在被部署至区块链平台之后难以更新。模糊测试是一种发现软件漏洞的有效方法,其基本原理是,在很少或根本不知道文件的底层语法结构的情况下,随机地改变输入文件的某些部分生成变异文件,通过变异文件尝试触发目标程序的异常和安全漏洞。该技术自出现以来得到了广泛的应用,并发现了大量的软件漏洞。

因为模糊测试技术在挖掘漏洞方面的高效性,开始有研究者将模糊测试技术应用在智能合约的漏洞挖掘场景中,并且提出了一些针对智能合约的漏洞挖掘工具,如Nguyen 等提出的sFuzz、Jiang 等提出 的ContractFuzzer、Luu 等提出的Oyente 等。然而,现有的智能合约漏洞挖掘工具还存在着一些不足之处:sFuzz 结合了AFL(american fuzzy lop)模糊器中的策略,是一个覆盖率引导的智能合约模糊测试工具,虽然其在实现高代码覆盖率和发现漏洞方面是有效的,但并没有考虑到种子的优劣,均等对待每个种子,会导致花费很多时间在低质量的种子上。Oyente 将需要分析的合约的字节码和当前以太坊的全局状态作为输入,检测合约是否存在安全问题,并向用户输入有问题的符号路径。但是,由于符号执行的路径深度限制,验证所有可能的路径会遇到路径爆炸问题,当路径约束复杂且难以解决时,符号执行可能无法探索深层路径,并且具有较差的可伸缩性。ContractFuzzer 使用预先部署的合约构建网络并生成事务以运行智能合约,基于一组预定义的参数值生成测试用例,并以一组特定于智能合约的测试用例来判断是否存在某种漏洞。但ContractFuzzer 只是简单地通过输入大量的参数来发现漏洞,并不能有效地触发更深层次的路径。

针对上述智能合约模糊测试工具存在的不足,本文提出了一种效率导向的智能合约模糊测试工具ConFuzz。根据测试用例的执行速度、到达的路径深度等因素给测试用例进行打分,基于分值来调整测试用例在havoc 阶段的用时。实验结果表明,ConFuzz 可以在更短的时间里检测出更多的漏洞,有效提高了针对智能合约的模糊测试的效率。

本文的组织结构如下:第一节介绍智能合约的一些常见漏洞。第二节对ConFuzz的实现方式进行详细介绍。第三节给出了实验结果,并与其他方法进行了比较。最后,在第四节中进行了总结并对未来工作进行了展望。

1 智能合约漏洞

在本节中,将详细介绍智能合约几种常见漏洞。

1.1 可重入漏洞

当存在重入漏洞的合约将以太币发送给恶意的合约地址时(恶意合约地址来源于输入或者是调用者地址),攻击者可以通过重入漏洞重新进入存在漏洞的合约。此时漏洞合约虽然已经发送了以太币完成交易,但合约状态还未更新,攻击者可以执行一些开发人员不希望执行的合约逻辑,比如利用漏洞合约中的转账操作向攻击者账户进行非法转账。

1.2 无燃气发送

以太坊中的每一笔交易都是按照智能合约的规定一步一步执行命令的,每执行一个命令都会产生一定的消耗,这个消耗用燃气(gas)作为单位。另外,不同命令消耗的燃气(gas)数量也不相同。每一笔交易都被要求包含一个燃气上限(gas limit),该上限代表是这笔交易允许消耗的燃气的最大值,可以理解为交易服务本身的服务费。当合约使用send 函数发送以太币到某一合约时,接收合约中的回退函数将会被调用,如果回退函数执行过程中消耗的燃气大于2300,就会触发一个异常,导致转账失败,但是原有合约会继续执行。该漏洞产生的根本原因是使用send 调用其他合约函数时,在执行期间触发的异常不会影响原有函数的执行。

1.3 异常无序

智能合约间的相互调用除了直接调用以外还有通过函数的嵌套调用方式。如果每一个调用都是对合约函数的直接调用,当异常发生时,包括以太币转账在内的所有交易都会被还原,并返回false。但是,当合约间以函数的方式嵌套调用其他合约时,由于solidity语言中没有一个一致的方法去处理异常,交易的fallback 便会在该调用函数处停止并返回false。发起调用的合约可能无法获取被调用的合约中的异常信息。这种处理异常的不一致性会影响到合约的安全性。比如,如果仅仅根据没有异常抛出就认为转账是成功的,这是很不安全的。

1.4 DelegateCall受控漏洞

DelegateCall 函数的目的是用于实现类似于代码库的调用。它可以让合约在不用传输自身状态的情况下使用其他合约的代码。但是当函数的参数是由当前调用者指定时,攻击者便可以用合约拥有者的身份执行其他合约的任意函数。利用这个漏洞进行攻击的典型事件是对钱包(wallet)合约的攻击,该攻击导致合约的拥有者损失了3000万美元。

1.5 块依赖和时间戳依赖

当一个智能合约使用区块状态变量作为发送以太币等关键操作的执行条件,或者作为生成随机数的来源时,就有可能存在此类型漏洞。区块状态变量包括时间戳、深度、燃气上限等,由于一个区块的时间戳是由矿工挖矿时的系统决定的,矿工可以事先计算出对自己有利的时间戳,并且在挖矿时将时间设置成对自己有利的时间。因此一个恶意的矿工能够通过修改区块的时间戳获取利益。

1.6 以太冻结

以太冻结漏洞产生的原因是有些合约用于接受以太币,并转账给其他地址,但是,这些合约本身并没有实现一个转账函数,而是通过调用其他合约中的转账函数实现转账的功能。如果这些提供转账功能的合约执行了销毁操作的话,那么,调用了这个转账功能的合约就有可能发生以太币被冻结的情况。当以太币被冻结后,因为合约的代码无法被修改,也就无法进行转出操作。

1.7 算术上溢/下溢

与其他的编程语言一样,在solidity 语言中,合约余额的检查中如果直接使用了加减乘除而没做额外的判断时,就会存在算术溢出隐患,攻击者可以通过传入超大数字导致溢出绕过判断,这样就可以转走巨额代币。

2 智能合约模糊测试实现

在本节中,首先定义智能合约模糊测试中存在的问题,然后逐步详细介绍本文的方法。

2.1 问题描述

在AFL 的变异机制中,维护了一个种子队列,每次把种子队列中的文件取出来后,对其进行变异然后投送给目标程序。如表1 所示,AFL 的文件变异方法主要有6 种,其中前4 种变异方式由于不存在随机性,所以也叫作确定性变异,后2种因为存在随机性,称为非确定性变异。当种子队列中的所有文件变异结束后,代表完成了一个cycle,进入下一轮变异。现有智能合约模糊测试工具没有考虑种子的重要程度,所有的种子都会得到相同的变异时间,这一定程度上会影响Fuzz的效率。

表1 AFL文件变异方法

2.2 ConFuzz整体结构

ConFuzz的整体结构如图1所示。

图1 ConFuzz的整体结构

ConFuzz 从初始种子集中选取种子,根据表1 所示的种子变异算法对种子进行变异以生成fuzz智能合约的测试用例。同时其监视测试用例的执行,将fuzz 过程中的覆盖率、分支数、每秒执行的变异种子数、种子到达的路径深度等信息记录在执行日志中。如果发现了程序崩溃,ConFuzz 就检查执行日志并报告漏洞类型。如果发现了新的路径,那么把到达该路径的测试用例添加到种子池中做进一步的变异。在种子变异算法上,ConFuzz 根据种子的执行速度、到达的路径深度等因素给种子进行打分,根据分值,来调整在非确定性变异阶段havoc 方法的用时。换而言之,打分机制的根本目的使得执行时间短、代码覆盖高、到达更深路径深度的种子执行的时间更长,拥有更多的havoc变异机会。

2.3 ConFuzz打分机制

如2.1 节所述,为了解决sFuzz 在非确定性变异阶段没有考虑种子重要程度的问题,ConFuzz 提出了一种打分机制,来实现对种子重要性的评估,并且给予重要程度高的种子更多的变异时间。打分机制被广泛地应用于衡量候选种子质量,在AFL、Li 等提出的vFuzz等著名模糊测试框架中,都有运用。许多实践表明,通过打分机制,能让质量更高的种子优先变异,显著提高fuzz过程的效率。

ConFuzz 构造了一个名为calculate_score 的函数对种子进行打分,调整havoc 阶段用时,如算法1 所示。第2 行从种子样本池中选择种子,遍历池中的所有种子。第3 到4 行是第一个打分判断条件,首先计算出一个速度的平均值,并以这个平均值作为后续打分的标准,即,将每个种子的执行速度乘以某个(0,4]之间的数,并将结果与平均值比较。运行快速种子的成本更低,所以ConFuzz给它们更多的时间,如果结果大于平均值,乘的数越小的种子,代表该种子的运行速度越快,给的分就越高;反之,如果小于平均值,那么乘的数越大的种子,代表该种子的运行速度越慢,得分就越低。第5 到8行是第二个打分判断条件,根据测试用例到达的深度来进行打分,能够到达更深层次的测试用例更可能揭示无法发现的漏洞,到达的深度越深,也就是覆盖率越高,得分就越高。值得注意的是,在第7行,增加了一个判断条件,如果最大深度小于3,就不给该种子打分。这样做有两个原因:一是因为深度浅的待测的合约小,分支少,对小合约用大量的样本进行fuzz 并不能提高发现漏洞的机会;二是因为随机性变异过于盲目,变异出到达更深路径的种子概率过低。通过加入打分机制,能够保证执行速度快、覆盖深度深的种子具有更多的变异次数、更长的havoc 变异时间,进而就有更大的几率发现更多的漏洞。

3 实验与结果分析

在本节中,通过实验将ConFuzz 与Contract Fuzzer 和sFuzz 这两个智能合约模糊测试工具进行比较。

3.1 实验准备

本文的实验是在配有8GB 内存的Ubuntu18.04.1 LTS 上运行的。测试合约一共有381 个,都 是 从EtherScan网 站 上 爬 取 的。EtherScan 是2015年推出的一个以太坊区块探索和分析的分布式智能合约平台, 作为探索以太坊的窗口,可以查看合约信息、交易信息等。

3.2 结果分析

ConFuzz 一共测试了381 个合约,共有两种类型的账户去调用这些合约,包括一个普通账户和一个专门测试可重入漏洞的账户。每个合约测试时间为1 min,共测试了三次,计算三次的平均值,结果如表2所示。其中表格第一列列出了ConFuzz测出的漏洞类型,第二、三列分别列出了该类型漏洞的数量以及占漏洞总数的百分比,第四列是该类型漏洞的真阳性率,即ConFuzz 检测出来的存在该漏洞的合约数除以经验证所有存在该漏洞的合约数。

表2 ConFuzz漏洞测试结果

可以看到,对于可重入漏洞、无气发送、Delegatecall 受控漏洞、异常无序、算术上溢、算数下溢这六种类型的漏洞来说,每一个被Confuzz 测出来的漏洞经过人工检测都是真实存在的,不存在误报。而对于块依赖和时间戳依赖漏洞,ConFuzz 报告的漏洞中,分别有2 个和4个是误报,这两类漏洞产生漏报的原因是相同的,都是因为将区块编号或时间戳分配给全局变量,但它们与以太发送过程无关。

为了对比三个工具在速度上的差异,在381个合约中随机抽样100个合约,三个工具的执行速度比较如图2所示。

图2 三种工具的速度比较

图2三种工具的速度比较。横轴代表不同的合约,纵轴代表变异样本执行的速度,即一分钟内生成和执行的变异样本的平均数。为了直观清晰地看出结果,将合约样本数量进行递增排序。由于ContractFuzzer 平均每秒只生成和执行0.1 个测试用例,所以没有在图上表现出来。ContractFuzzer 速度明显偏慢的原因主要有两个:

(1)ContractFuzzer 维护了一个庞大又复杂的系统,包括一个线上的模糊测试工具和线下的以太坊虚拟机(ethereumvirtual machine,EVM)插桩工具,而Confuzz 不用维护和模拟整个区块链网络。

(2)ContractFuzzer 的大部分时间花费在对合约的静态分析构建合约池方面,而Confuzz 不需要进行静态分析提取函数选择器。

从图2 可以看出,对随机抽样的100 个合约中的大部分合约来说,ConFuzz 的执行速度比sFuzz快。但是对于某些合约,sFuzz的执行速度比ConFuzz更快。这是因为存在一些小合约,在第一轮的确定性变异阶段就可以fuzz 完成,无法进入第二轮的非确定性变异阶段。

同时,实验计算381 个合约的平均执行速度,结果表明,ConFuzz 比sFuzz 执行的速度提高了8.03%。ConFuzz 速度提高的原因主要有两个方面。

(1)增加了打分机制,使得执行速度快的样本拥有了更多的havoc 时间,可以变异出更多的执行速度快的样本。

(2)由于速度慢、代码覆盖深度浅的样本得分低,所以对这些样本花费的时间更少,就有更多的时间进行有效的样本变异,执行更多效果好的样本。

实验结果表明,Confuzz 在漏洞挖掘方面相较ContractFuzzer 测出的漏洞数量更多、准确率更高、更可靠;在速度上Confuzz 比sFuzz 更快,在相同的时间内可以执行更多的有效种子样本,更高效。

4 结语

随着区块链和智能合约技术的发展,数百万智能合约被部署在区块链平台上,以实现分散应用的构建。然而,智能合约存在的安全漏洞对其未来的发展构成了巨大威胁。本文提出了一个基于打分机制的智能合约模糊测试工具ConFuzz。实验结果表明,ConFuzz 能有效地发现智能合约存在的8种类型的漏洞,是高效、快速、准确度高的智能合约模糊测试工具。

由于ConFuzz 是根据合约的jumpi 指令计算合约分支的,如果一个简单的合约不含有jumpi指令,ConFuzz 就会跳过而不去测试它,从而无法发现其存在的安全漏洞。未来还会进一步考虑这种情况,使得ConFuzz也能有效地测试简单的合约。区块链和智能合约仍在不断地发展中,越来越多的智能合约被部署。因此,智能合约的安全漏洞问题不容忽视,智能合约的未来将专注于解决这些挑战。

猜你喜欢
测试用例以太调用
探索太空奥秘 还原宇宙本真
以太万物理论概述
以太坊又爆漏洞黑客大战一触即发
基于Android Broadcast的短信安全监听系统的设计和实现
面向多目标测试用例优先排序的蚁群算法信息素更新策略
利用RFC技术实现SAP系统接口通信
基于TestLink的测试管理系统研究
测试用例集的优化技术分析与改进
C++语言中函数参数传递方式剖析