《HFContractFuzzer: Fuzzing Hyperledger Fabric Smart Contracts for Vulnerability Detection》(EASE 2021)
区块链技术以其特有的去中心化、不可变性等优点,近年来被广泛应用于各个领域。运行在区块链上的智能合约在去中心化应用场景中也扮演着越来越重要的角色。因此,自动检测智能合约中的安全漏洞成为区块链技术应用中亟待解决的问题。Hyperledger Fabric是一个基于企业级授权分布式账本技术的智能合约平台。然而,关于Hyperledger Fabric智能合约漏洞检测技术的研究还处于起步阶段。本文提出了一种基于Fuzzing技术的Hyperledger Fabric智能合约检测方法HFContractFuzzer,该方法将golang的Fuzzing工具go-fuzz与golang编写的智能合约相结合。利用HFContractFuzzer对5个典型的合约进行漏洞检测,发现其中4个合约存在安全漏洞,证明了该方法的有效性。
自2008年以来,区块链一直在公众的视线中。区块链是Satoshi Nakamoto提出的一种新的计算机技术应用模型。它不仅给虚拟货币的发展提供了一个机会,也提供了新的安全解决方案。区块链技术近年来得到了广泛的应用,也出现了各种各样的探索,智能合约就是其中的重要组成部分。智能合约极大地改善了区块链的使用场景,并将区块链平台从一个简单的分布式账户系统扩展到一个极其丰富的去中心化的操作系统。与普通程序相比,智能合约的安全问题尤其值得关注。一方面,智能合约一旦部署就不能更改。另一方面,智能合约通常具有巨大的经济价值。因此,智能合约安全漏洞的自动检测成为区块链技术应用中亟需解决的问题。
以太坊和其他基于工作量证明共识协议的区块链平台的增长令人印象深刻,这明显限制了这种方法,主要与性能有关。与此同时,Hyperledger Fabric(HF)最初是由IBM牵头的联盟链,只允许某些商业组织参与和分享。HF是一个用于部署和运营获得许可的区块链的系统,目标是商业应用。它支持模块化共识协议,这允许系统根据特定的用例和信任模型进行定制。该特性允许针对特定的业务场景更有效地定制HF,并带来更短的延迟和更高的性能。然而,与以太坊相比,对HF的研究相对较少,主要是因为HF的出现晚于以太坊,以太坊是由Linux基金会在2016年创建的。近两年来,HF在学术界得到了越来越多的关注。然而,目前几乎还没有针对HF智能合约漏洞的公开论文或工具。值得一提的是,HF智能合约中的漏洞与以太坊中的漏洞有很大的不同,这也是一个挑战。
符号执行(Symbolic Execution)、形式验证(Formal Verification)和模糊测试(Fuzzing)是智能合约漏洞检测的主要技术,已有大量的研究将这些技术应用在以太坊上。其中,Fuzzing技术可以检测出非预期的漏洞,更适合HF智能合约的漏洞检测,因为目前它的大部分漏洞都超出了我们的认识和研究范围。
基于以上背景,我们提出了一种HF智能合约模糊测试方法HFContractFuzzer,这是一种基于Go-fuzz的针对golang语言的模糊测试工具。然后,我们使用HFContractFuzzer来检测五个典型来源的合约漏洞,发现了其中4个存在安全漏洞,证明了该方法的有效性。
本文的结构安排如下:第2部分系统地总结了本文研究的技术背景和相关工作,包括HF智能合约、智能合约漏洞检测的相关研究、Fuzzing技术;第3节具体介绍了基于go-fuzz的HF智能合约模糊测试方法HFContractFuzzer;第4部分测试了五个典型的智能合约,对HFContractFuzzer方法进行了可行性分析和验证;第5部分讨论了本研究的贡献和不足;第6节总结本文的内容。
本节介绍了本文所涉及的技术背景和相关工作,包括HF智能合约的介绍、智能合约漏洞检测的研究以及Fuzzing技术。
2016年,Linux基金会发起了一个开源项目,推动区块链的发展,开启了Hyperledger时代。超级账本目前有六个技术框架。其中,HF是一个企业级授权分布式账本技术平台。HF有四个功能模块,分别是身份管理、账本管理、交易管理和智能合约。它负责开发大多数行业的通用模块和设计,创建一个由公众管理的具有企业级许可的开源账本。在系统和HF应用中,智能合约通常被称为链码。区块链网络使用链码来约束和规范键值对和其他状态数据库的读取或修改,以完成复杂的业务逻辑。链码有自己的执行逻辑,按照自定义规则对账簿数据进行逻辑处理。网络中支持背书的节点在节点服务器上安装并实例化链码,业务人员可以使用带有Fabric-SDK的客户端与节点服务通信,实现链码的调用。
目前,在智能合约漏洞挖掘和Fuzzing技术方面已经有了一定的研究工作。Fu等人对智能合约的安全问题进行了详细的分类和分析,并总结了智能合约的测试方案。文章指出了常见的智能合约安全问题,包括重入、权限控制、整数溢出、异常处理、短地址攻击、操作块时间戳、拒绝服务攻击、伪随机、委托调用、非法和交易问题。在安全性方面,Fu等人提出了四种智能合约测试方法:形式化验证、Fuzzing、符号执行和污点分析。
Mythril是针对以太坊虚拟机字节码的安全分析工具。它是基于符号执行和具体执行的。它将静态执行和动态执行相结合,提高了路径覆盖和检测精度。然而,很难发现一些更深层次的隐藏或复杂的测试用例的漏洞。Oyente是一个用于EVM字节码的静态符号执行工具,它可以检测可重入性、调用堆栈深度、时间戳依赖和交易顺序依赖漏洞,但静态执行会遭受路径爆炸的影响,导致可覆盖的漏洞类型更少。Securify基于模式匹配,分析智能合约中给定特征的漏洞。Securify比Mythril和Oyente更好,但它不能解决数字漏洞。Smartcheck是一个可扩展的静态分析工具。它可以通过特征匹配检测算法溢出漏洞,但只能在源代码级进行匹配,不提供触发漏洞的输入数据。MAIAN是一个自动工具,用于发现区块链智能合约中的漏洞,处理合约的字节码,并试图创建一系列交易来发现和确认错误。
(本节剩余部分省略)
HF智能合约可以用主流语言编写,如Go和Java。HF从项目早期就为Go提供了一个软件开发工具包。Go社区有很多工具来提高代码质量。因此,本文主要进行对Go语言编写的智能合约进行分析,挖掘智能合约的漏洞信息。与传统程序不同的是,智能合约的编写和运行依赖于区块链网络中的状态数据库。考虑到这些差异,我们首先对智能合约进行单元测试,以改进智能合约运行时环境和本地调用规则。然后我们优化go-fuzz工具。最后,我们提出了一种智能合约测试方法HFContractFuzzer来检测漏洞。
HFContractFuzzer的基础是HF智能合约单元测试。单元测试是指对被测试系统的基本组件和不同模块进行测试和评估。智能合约的读写操作依赖于区块链网络的状态数据库,因此无法在本地对其进行直接调用。在本节中,我们将使用两个场景来执行智能合约的单元测试,以获取智能合约的本地调用规则。
开发人员模式。开发人员模型需要一个简单的本地网络环境来测试智能合约接口。该组网环境与区块链组网不同,仅支持智能合约操作。测试所需的Docker镜像信息如表1所示。在配置环境时,我们需要在本地设置fabric-samples包,该包包含调试目录。调试目录包含一个排序节点、一个节点、一个智能合约容器和一个客户端容器。智能合约容器负责运行被测智能合约,客户端容器负责发送请求消息。客户端容器的script.sh文件负责创建通道和添加节点,这些节点可以在测试期间用于配置智能合约。被测试的智能合约被放置在chaincode目录中,在测试过程中,该目录被映射到智能合约容器。
测试过程需要启动三个终端,如图1所示。第一个终端负责启动网络、创建mycc通道和连接节点。此时,网络包含一个排序节点服务器、一个节点服务器、一个智能合约容器和一个客户端容器。第二个终端负责编译智能合约,输出智能合约运行日志。第三个终端负责智能合约的配置。最后,第三个终端调用接口来执行智能合约的单元测试。
MockStub类:HF为单元测试提供了MockStub类。MockStub类维护一个map[string][]字节来模拟键值对,以完成区块链网络中状态数据库的工作。当在智能合约中调用PutState和GetState函数时,它不再是状态数据库,而是内存中的映射数据。使用MockStub类对智能合约进行单元测试,不需要配置和运行网络环境,可以在本地完成智能合约接口调用的测试。MockStub类提供MockInit和MockInvoke函数来模拟来自区块链网络中背书节点的智能合约调用。调用智能合约的Init和Invoke接口,参数是一个字符串类型uuid和一个字节数组。Init负责智能合约的初始化,Invoke负责智能合约函数的选择。Invoke解析字节数组,获取函数参数,并调用不同的函数来完成不同的工作。
使用developer模式对智能合约进行单元测试可以简化网络环境,但也涉及到网络配置和启动。此外,developer模式在终端调用接口测试智能合约,并且每次调用都需要执行一条命令,指定通道名称和参数信息,这使得它难以接受大量随机数据的输入,不适合Fuzzing。但是,使用MockStub类不需要区块链网络环境或Docker映像。我们只需执行简单的命令来自动化智能合约的本地测试,并标准化智能合约接口函数调用。测试过程与传统的Go程序单元测试相同,具有简单、高效的优点。MockStub类用于设计本地调用智能合约接口的规则,这有助于使用Go语言测试工具对智能合约进行后续测试。因此,我们使用MockStub类来研究智能合约接口的调用规则。
(3.2节go-fuzz介绍省略)
目前,HF智能合约还没有专用的Fuzzing工具。基于go-fuzz工具,本节提出了一种智能合约模糊测试方法HFContractFuzzer,并概述了HFContractFuzzer方法如图3所示。HFContractFuzzer使用MockStub类实现对智能合约接口的本地调用,然后将大量随机数据输入智能合约中,检测潜在的软件漏洞。
编写初始语料库。首先,我们提供被测智能合约的单元测试用例作为初始语料库,或者我们使用G-go-fuzz库完成数据的生成。
编写测试文件。我们将智能合约中每种类型信息的发布和查询分组,并编写测试函数。然后将信息查询结果与发布的数据进行比较,检测智能合约的逻辑漏洞。如果测试函数接收到一个语料库并返回0,则表示可能存在逻辑漏洞,否则返回1表示不存在漏洞,如图4所示。
基于go-fuzz的智能合约Fuzzing。优化后的go-fuzz具有完整的异常处理模块和较高的测试效率,可用于智能合约的模糊测试。在优化的go-fuzz中,Fuzzing的主体是在fuzz.go中实现的。Fuzz函数负责识别和解析每个测试轮次的语料库,将数据传输到每组测试函数进行测试,并将每组测试函数的结果进行合并。反馈结果调整了语料库中语料的优先级,如图5所示。异常处理模块监控整个测试执行过程,获取并记录异常信息。
结果分析。终端显示Fuzzing报告,并定期打印一组检测结果。每组测试结果包含一个当前的时间戳和测试数据信息。语料存储在语料库中,异常信息存储在crashers中。通过获取异常发生时的语料库和位置信息,设计单元测试用例,我们可以确定脆弱性是否存在,防止误报的发生。最后,对已确认的漏洞进行了探讨,确定了漏洞的类型,并分析了漏洞产生的原因。
本节测试了基于HF框架的5个典型智能合约,以验证HFContractFuzzer。这些智能合约来自Fabric、Caliper和IBM,包括HF version 0.6和HF version 1.1。同时,这些智能合约整合了HF的所有功能模块:身份管理、账簿管理、交易管理、智能合约。他们还可以上传和下载信息。因此,他们可以代表大多数HF区块链项目。
食品追溯一直是区块链技术的热点领域,因此我们以五款智能合约中的食品追溯项目为例进行具体介绍。该系统利用区块链技术注册和跟踪食品的各种信息,包括食品基本信息、配料信息、物流信息。用户可根据食品号跟踪查询各类信息,确保食品的真实性。
我们根据章节3中的HFContractFuzzer流程测试了这个智能合约:
(1)我们使用单元测试用例F1、I1和L1作为对被测智能合约Fuzzing的初始语料库,如表4所示。
(2)我们将待测智能合约中基本食品信息的发布和查询划分为一组。同样的,我们将配料信息和物流信息分组。然后编写测试文件,调用各组的函数,将信息查询结果与发布的信息进行比较。
(3)我们使用优化的go-fuzz工具来测试智能合约。测试时间25h38min,执行次数233943435次,覆盖数据1525次,语料库418次,测试结果出现1次crash。
(4)我们获得了异常的详细信息,并确定了被测智能合约中的异常类型。异常消息为“addIngInfo Failed”,语料库信息为“{"FoodIngInfo":{"IngID":">"}}"。根据测试结果,我们根据异常发生时的语料库和位置设计新的测试用例,然后执行单元测试,以验证类型转换错误。测试文件中存在类型转换错误。输入数据为“>”字符串,在JSON.Marshal()的帮助下,将其转换为智能合约中的字节类型,并存储在状态数据库中。测试文件在查询期间获得状态数据库中的字节类型数据。使用string()转换为字符串,转换后的字符串为“˘003e”,与“>”不一致导致系统报错。
类似地,我们测试了来自典型来源的其他四个智能合约(example01、drm、smallbank、marbles),结果如表5所示。在测试了这五种典型的智能合约后,我们发现其中四种存在安全漏洞,包括三种漏洞:类型转换错误、逻辑漏洞和整数溢出,这在其他区块链平台(如以太坊)中也是典型和严重的,然后使用单元测试来验证这些漏洞的存在。结果一方面证明了Fuzzing应用于HF智能合约检测未知漏洞的可行性,以及HFContractFuzzer在漏洞检测中的有效性。另一方面,我们在HF智能合约中发现了三个从未发现的新漏洞,这对HF智能合约未来的进一步研究有一定的帮助。
目前,HF智能合约测试技术仍处于初步探索阶段。在此基础上,本文提出了一种模糊测试方法HFContractFuzzer,并采用HFContractFuzzer对五个典型来源的合约漏洞进行模糊测试。该方法发现其中4个合约存在安全漏洞,证明了该方法的有效性。
本工作存在一些不足和局限性:
(1)Go-fuzz工具最初是为了Go 程序中的漏洞而设计的,在检测智能合约漏洞时可能会出现性能下降的问题。本文虽然对go-fuzz进行了优化,提高了Fuzzing的性能,但仍然存在问题,需要进一步优化。
(2)对于本文所提出的Fuzzing方法HFContractFuzzer的评价,我们无法验证其优越性,因为我们在公开的论文中没有找到HF智能合约的检测方法和工具来支持比较研究。然而,我们仍然通过精心设计的评估过程,选择5个典型HF智能合约应用我们的HFContractFuzzer方法,尽我们最大的努力来展示所提方法的有效性,最终从所有选定的案例中检测出预期的漏洞。
(3)在此基础上,我们发现HF智能合约存在三种安全漏洞:类型转换错误(Type Conversion Errors)、逻辑漏洞(Logic漏洞)和整数溢出(Integer overflow)。对于已知的漏洞,其他检测方法的有效性是未知的,如符号执行、静态分析和机器学习。由于这些方法都没有被纳入到HF漏洞检测领域,所以我们的方法与这些有希望的方法的比较不在本文的研究范围之内。