区块链智能合约漏洞检测与自动化修复综述

2023-03-24 13:25童俊成赵波
计算机应用 2023年3期
关键词:以太调用字节

童俊成,赵波

(武汉大学 国家网络安全学院,武汉 430072)

0 引言

在信任危机困境中,涉及第三方的交易存在安全风险或成本较高的问题。区块链作为一种分散的分布式账本,帮助人们在不可信的环境中进行安全可靠的交易,得到了迅速发展和广泛应用。区块链在市场上的潜力随着比特币的流行而被重视[1-2],但现在的区块链已不再局限于数字货币,而是由于智能合约这一应用于区块链2.0 上的技术而引起了广泛关注[3]。

密码学者Szabo[4]首次提出智能合约的概念,将它定义为一套以数字形式指定的承诺,合约参与者可以在上面执行这些承诺的协议。即智能合约是一段可以在计算机上自动执行的代码。由于缺乏可信的执行环境,这一概念在当时并未得到广泛地应用。如今区块链技术为智能合约提供了一个可以达成共识从而整体可信的网络环境,使智能合约真正流行起来。因此可以认为智能合约与区块链平台相互促进,将受到学术界与工业界越来越多的重视。

随着智能合约的快速发展,近年来针对它的漏洞的攻击层出不穷。2016 年,去中心化自治组织(Decentralized Autonomous Organization,DAO)这一部署在以太网上的全球最大众筹项目遭到黑客攻击,导致超过300 万以太币脱离DAO 资源池,直接造成以太坊采取硬分叉策略,损害了以太坊的公平性[5]。2017 年,以太坊多重签名钱包Parity 出现安全漏洞,导致超过15 万以太币被侵吞。2021 年,币安智能链上的自动做市商(Automated Market Maker,AMM)合约在迁移过程中出现漏洞并遭到黑客攻击利用,导致5 000 万美元的资金被盗。

智能合约与传统程序区别很大。首先,它通过交易方式发布,一旦被部署成功,将分布式地存储到链上的每一个区块内,由矿工节点运行,而在现有的区块链系统中这些矿工节点无需具有可信的基础计算环境;其次,智能合约常常通过相互调用以实现更加复杂的功能,但如果调用了不受信任的外部合约可能会引发风险和错误,甚至当它所依赖的其他合约内存在恶意代码时,会导致每个外部调用都存在潜在的安全威胁;再者,在区块链上智能合约可以由任意用户发布或协同编制,而在这一过程中用户知识和使用工具参差不齐、选择使用的智能合约源码的安全建议也并不齐全,还有可能存在不受控制的恶意用户操作规程,无法保证智能合约部署上链后没有安全漏洞或缺陷;最后,智能合约还具有一些传统代码没有的机制,如以太坊智能合约的燃料(Gas)机制等。这些都导致区块链智能合约漏洞挖掘具有难度和挑战性。另外,区块链系统具有的两大特性也给智能合约的修复升级带来挑战:1)区块链系统具有的不可篡改性使智能合约一经部署就难以更新升级;2)区块链系统具有的透明性使普通用户获取区块链上运行的智能合约字节码更加容易,这就对智能合约修复工作提出了及时、快速的需求,因为仅挖掘、发现漏洞而不升级合约则攻击者更有可能利用漏洞对区块链平台产生威胁。

综上所述,智能合约的漏洞检测与自动化修复技术的研究在区块链安全领域十分必要也非常热门,本文从智能合约漏洞基础知识出发,重点调研了智能合约漏洞挖掘的关键技术方法以及自动化修复与升级方法,并探讨了前沿技术与未来可能的发展方向。

1 背景知识

智能合约是一种旨在提供、验证与执行合约的特殊应用程序,整个存储、读取、执行过程由区块链技术保障。首先,智能合约通过交易方式发布,一旦被部署成功,与区块链融为一体,分布存储到链上的每一个区块内,且区块链的不可篡改性使它难以更新升级,而且存储于区块链上的智能合约字节码公开透明,这会导致智能合约不可信。由于智能合约最常见的部署平台是以太坊[6],当前最广泛的智能合约漏洞挖掘工作也集中在以太坊,因此本章将重新审视它们的基本概念和执行上下文,对三个关键概念进行描述:账户、交易和以太坊虚拟机(Ethereum Virtual Machine,EVM)。

1)账户。

以太坊采用类似传统银行系统中的账户管理机制的账户模式,有两种账户类型:外部账户(Externally Owned Account,EOA)和合约账户(Contract Account,CA)。它们都由一个20 Byte 的地址唯一标识,由随机数(Nonce)、账户余额(Balance)、合约代码(Bytecode)、存储(Stored Data)组成。

EOA 由公钥/私钥对控制,主要用于管理以太(ETHereum,ETH),并通过发送交易与合约进行交互。而CA则由智能合约中的代码逻辑控制,主要用于实现各种功能需求,记录已执行的交易、余额修改等合约状态变化,但不能发送交易。CA 不能主动与外部账户交互。这两类账户将共同维护以太坊中包含变量状态信息的状态对象实体,并通过区块链的共识机制实现各节点之间的一致性。

2)交易。

以太坊中的交易指由外部账户发送的消息签名数据,其中包含了发送者签名、接收者地址、账户余额、发送币的数量、最大消耗的Gas 限制以及合约每步执行支付给矿工的费用。在以太坊中,CA 在智能合约被第一次发布时创建,它的创建过程通过合约创建交易形式完成。交易将广播到区块链上的每个矿机执行,并在达成一致共识后改变存储状态。在交易包含的信息中,Gas 机制维持以太坊生态系统正常运行的动力来源,合约中函数的计算都以Gas 进行衡量,无论是转账交易还是合约的创建与执行,都需要消耗Gas。在激励与安全上,Gas 机制也发挥着关键作用:对矿工执行和存储交易进行补偿和激励;防范恶意用户发送复杂计算等拒绝服务攻击(Denial of Service,DoS)攻击。

3)执行环境。

以太坊智能合约由EVM 执行。EVM 由一个具有自定义指令格式的虚拟机组成,该虚拟机基于栈结构实现。在EVM 中,智能合约调用的每条指令都表示为一个字节操作码,参数在数据堆栈上传递。唯一的例外是Push 指令,它将常量推送到堆栈上,这些常量被直接编码到指令字节中。EVM 的存储结构有堆栈、内存和存储。堆栈可以存储局部变量;内存用于存储参数和返回值,被函数调用后释放。堆栈和内存具有易失性,将在完成事务后清除,存储将持久地存储状态变量。

2 智能合约漏洞

以太坊智能合约漏洞按照引入原因可分为Solidity、EVM 和区块链三个层级,其中:Solidity 为智能合约编程语言,因此可以将DASP 10(Decentralized Application Security Project 10)列举的除了未知类型漏洞外的主要智能合约漏洞按表1[7]进行归类。

表1 智能合约漏洞类型与引入层级Tab.1 Smart contract vulnerability types and introduction levels

1)重入漏洞。

重入漏洞是最臭名昭著的以太坊漏洞,第一次被发现时直接导致了以太坊的硬分叉。当允许外部合约调用时,在初始执行完成之前对调用合约进行新调用时就会发生重入。对于函数而言,这意味着合约状态可能会在执行过程中由于调用不受信任的合约或使用具有外部地址的低级函数而发生变化。DAO 项目遭到重入漏洞的攻击过程如图1 所示。

图1 利用重入漏洞攻击DAO合约Fig.1 Attacking DAO contract by exploiting reentrancy vulnerability

攻击者调用DAO 合约中的splitDAO(),而SplitDAO()调用withdrawRewardFor(),这个函数调用由DAO 创建的子合约中的payOut();然后,payOu(t)调用call.value()向攻击者的智能合约发送ETH;由于call.value()将调用被调用合约中的回退函数fallback(),因此攻击合约可以再次调用splitDAO(),从而被攻击的DAO 合约可被重复执行如图1 所示的步骤2)~6),直到耗尽Gas,导致超过合理数量的ETH 被取走。

2)访问控制漏洞。

攻击者利用不安全的可见性设置访问合约私有值或逻辑。当合约使用已弃用的tx.origin 验证调用者,并在代理库或代理合约中鲁莽使用处理冗长的大型授权逻辑require 以及delegatecall 时,就会出现这类漏洞。如图2 所示,在用户A调用合约B 的内部函数并通过该内部函数再次调用合约C的过程中,会出现tx.origin 返回原始发送交易的地址,而msg.sender 返回当前交易的发送者的情况。因此当利用tx.origin 验证权限时,攻击者会利用上述差异进行攻击。

图2 tx.origin与msg.sender调用结果差异Fig.2 Differences between calling results of tx.origin and msg.sender

3)算术漏洞。

算术漏洞也被称为整数上溢和下溢,这并不是一类新的漏洞,但它们在智能合约中尤其危险,其中无符号整数导致的漏洞最常见,大多数开发人员习惯使用简单的Int 类型(通常只是有符号整数)。如果发生溢出,许多看似良性的合约代码将成为盗窃以太币或拒绝服务的源头。如图3 所示:由于高位为符号位置,若合约不检查整数上溢的函数,将导致127 加上1 得到有符号整数-128 的错误。

图3 整数上溢示例图Fig.3 Schematic diagram of integer overflow

4)拒绝服务漏洞。

与大多数分布式系统一样,拒绝服务在以太坊中是致命的攻击。导致拒绝服务的方式有很多,包括交易接收者的恶意行为、人为增加计算函数所需的Gas、滥用控制访问智能合约的私有组件、利用混淆和疏忽等。在如图4 所示的锁仓合约调用示例中,用户A、B、C 都可以通过发布在以太坊上的Lockdrop 合约进行锁仓操作,成功后会生成一份属于自己权限控制下的Lock 合约。但在Lock 合约生成中函数会进行强制判断:属于参与者的Lock 合约的金额必须等于参与者锁仓时发送的金额,如果不相等,意味着Lock 失败,此时会导致参与者的Lock 合约“瘫痪”而形成“拒绝服务”,如果攻击持续,那么锁仓机制将不再可用。

图4 锁仓合约的拒绝服务漏洞Fig.4 Denial of service vulnerability in lock contract

5)低级调用中未检查返回值。

cal(l)、callcode()、delegatecal(l)和send()为Solidity 中的低级函数。它们在计算错误方面的行为与其他Solidity 函数完全不同,因为它们不会传播并且导致当前执行的完全恢复。相反,它们将返回一个设置false 的布尔值,并且代码将继续运行。如果不检查此类低级调用的返回值,可能会导致打开失败和其他不需要的结果。在如下所示的由于调用send()而产生的该类型的漏洞合约代码2)~4)行中:如果漏洞合约提高send()函数调用将以太发送到不接受它的智能合约,EVM 将用false 替换返回值;如果漏洞合约未检查返回值,函数对合约状态的更改将不会被还原,并且etherLeft 变量最终将记录不正确的值。

6)短地址攻击。

短地址攻击是EVM 自身接受错误填充参数的副作用。攻击者通过使用特制地址,使编码不佳的客户端在将参数包含在事务中之前错误地对它进行编码。大量的以太币可能会直接受到这个问题的影响。以以太坊协议ERC-20(Ethereum Request for Comments 20)为标准的代币为例,如果调用transfer()函数给地址“0x12345678901234567890123456 7890123456700”发送2 个ETH,交易的input 数据可以分为如图5 所示的3 个部分,但如果传入的地址最后两位是“00”,合约在解析参数时,会从下一个参数的高位拿到“00”来补充,导致后面的参数不足32 Byte,从而自动在尾部补上“00”,这样则会出现只取2 个ETH,却拿到512 个ETH 的漏洞。

图5 短地址自动补齐机制Fig.5 Short address auto-completion mechanism

7)交易顺序依赖漏洞。

交易顺序依赖漏洞指一种依赖于交易执行顺序而造成执行结果差异的安全漏洞。交易打包发送出去后会先存入交易池中,区块链矿工节点按照规则从交易池中选取一批交易放入新生成的区块。此时该新生成的区块还没有被确认为最终块,不同节点选取的交易和交易放入的顺序都不固定,因此合约执行的函数顺序也不可预测。一般矿工会选择交易费高的交易放入新区块中,因此攻击者可以通过提高交易费使交易在其他交易之前被写入,进而影响合约的最终执行结果。如图6 所示是MarketPlace 合约的两种不同的被调用顺序。MarketPlace 合约是一个股票买卖合约,声明了price 和stock 两个变量,以及两个功能函数updatePrice 和buy。其中:updatePrice 用于更新price 值,只有合约所有者才能修改;buy 是用户从合约中购买股票。按照顺序1 确认交易会出现用户使用旧的价格购买股票,而顺序2 确认交易会出现用户用新的价格购买。利用这一漏洞可能导致合约所有者将用户账户余额清零的攻击行为。

图6 MarketPlace合约的两种交易确认顺序Fig.6 Two transaction confirmation orders for MarketPlace contract

8)时间戳依赖漏洞。

从锁定代币销售到在游戏的特定时间解锁资金,合约有时需要依赖当前时间,通常通过block.timestamp 实现事件约束。在如图7 所示的轮盘赌游戏合约中,如果参与用户在区块时间戳正好能被5 整除的区块中第一个向智能合约转10以太,那么他将获得之前转入合约的所有赌注。但由于区块由矿工生成,矿工可以预先知道下一个区块的时间戳是否能被5 整除,从而作恶赢得所有以太。

图7 具有时间戳依赖漏洞的轮盘赌合约Fig.7 Roulette contract with timestamp dependence vulnerability

9)错误随机漏洞。

由于以太坊是一种确定性的图灵机,因此通过区块链环境中的变量生成的随机数并不是真随机数。在如图8 所示的示例中,判断获胜合约的发布者定义了pointer 指针作为私有变量,希望通过隐藏该私有变量,让用户参与者无法获取私有种子的数值。但攻击者实际上可以通过Web3 等方法在区块链上查看到这一变量值,从而利用这一漏洞赢得游戏。

图8 具有错误随机漏洞的游戏合约Fig.8 Game contract with error random vulnerability

3 智能合约漏洞检测关键技术

3.1 符号执行

符号执行是一种重要的程序分析技术,它通过用抽象符号值替换程序本身未指定的信息来表示任何值从而伪执行程序,同时也发展出了静态符号执行与动态符号执行[8]。

在静态执行方面,Oyente[9]是第一个被提出的工具,它将智能合约的字节码和以太坊区块链的状态作为输入,通过符号执行可以检测出事务排序依赖、重入、时间戳依赖和未处理的异常四个类型的漏洞。文献[10]中针对整数漏洞提出名为Osiris 的工具。该工具通过符号执行方法,针对导致整数上溢或者整数下溢错误的算术指令,检查当前的路径条件下指令是否有可能违反边界检查要求;针对由Solidity 使用AND 和SIGNEXTEND 指令截断有符号整数和无符号整数导致的错误,检查这两条指令的输入是否大于指令的输出;针对符号错误,检查特定指令的符号限制。文献[11]中提出了一种基于符号执行的工具DefectChecker,该工具使用堆事件和特征检测器代替了SMT 求解器的使用,相较于基于符号执行方法的Oyente、Mythril[12]和Securify[13]这三种智能合约漏洞检测先驱工具,速度和准确性更优。

动态符号执行也称为混合符号执行,通过对路径谓词的识别生成有约束的程序输入,从而提高准确度。文献[14]中提出名为Manticore 的开源动态符号执行框架,该框架实现了与平台无关的通用符号执行引擎,该引擎对底层执行模型几乎没有任何假设,根据状态生命周期来操作和管理程序状态。文献[15]中提出名为MAIAN 的工具,该工具通过分析智能合约在以太坊中的多次调用(合约的每次运行被称为一次调用),给定输入的上下文,在合约代码中执行一条执行路径,系统地描述并检测出三种漏洞合约:1)贪婪合约,通过无法发送ETH 来锁定资金;2)洪泛合约,可以将ETH 泄露给从未互动过的用户;3)自杀性合约,可以杀死合约或强制合约执行自杀指令。

尽管符号执行在智能合约漏洞检测方法中被广泛使用,但是将符号执行用于智能合约仍面临着无法识别不可行路径、无法验证交互的合约等局限性[16],因此存在许多优化的符号执行漏洞检测方法。例如,文献[10]中的Osiris 工具采用污点分析方法筛选掉不能被实际利用的整数错误,以降低误报率。文献[17]中提出一种新的增量符号执行方法,该方法基于路径探索和路径后缀摘要之间的迭代循环。一方面,汇总探索的路径,以更精确地识别受影响的路径;另一方面,路径后缀摘要将路径探索引导到没有增量行为的修剪路径。文献[18]中提出名为Annotary 的混合符号执行工具,该工具在Mythril 工具的基础上,通过构建合约间以及交易间的控制流执行语义模型消除传统符号在执行无法处理的不可达状态时存在误报的问题,并且,通过支持合约开发者声明属性的可验证来实现Solidity 语言的向后兼容扩展。

3.2 形式化验证

结合静态分析的程序验证方法在智能合约安全审计中也是研究的热点。该方法基于形式化方法(Formal Method)的相关理论,通过形式化语言把合约中的概念、判断、推理转化成智能合约模型,可以消除自然语言的歧义性、不通用性,进而采用形式化工具对智能合约建模、分析和验证。智能合约形式化验证方法包括演绎验证和模型检测等方法。

演绎验证主要基于定理证明(Theorem Proving)的基本思想,采用逻辑公式描述系统及它的性质,通过一些公理或推理规则来证明系统具有某些性质。

定理证明可以验证无限状态系统与有限状态系统。虽然定理证明技术通常是半自动化的,需要人的参与和专业知识,但是学术界与工业界依旧开发了许多由定理证明支持的智能合约安全审计方法与工具,可按照定理证明方法所基于的语言级别分为以下三类。

1)对EVM 字节码这一低级语言层面进行定理证明的研究工作受到了广泛的关注:文献[19]中将智能合约字节码序列组织成直线型程序,然后在Isabelle/HOL 定理证明器中用一个字节码级别的程序逻辑对EVM 形式化进行了扩展;文献[20]中提出一种以Gas 消耗量为重点的EVM 执行抽象模型,该模型通过对EVM 调用堆栈进行度量,提供了对智能合约终止条件的通用形式化证明。

2)文献[21]中认为中间语言(Intermediate Language,IL)有助于在验证的直观性和减少底层理解所需的能力之间取得平衡,因此通过Isabelle/HOL 证明器对Yul 这一以太坊的IL 进行形式化证明,并在证明过程中利用Yul 的良好可理解性来设计合约函数的初始前置/后置条件以达到精确识别合约函数的所有假设和影响的目的。基于IL 的另一项更具代表性的工作是由文献[22]中提出的ZEUS 工具,它构建了第一个从Solidity 语言到低级虚拟机中间表示(Low Level Virtual Machine Intermediate Representation,LLVM-IR)的转换器,并进行给定策略下的形式化证明。

3)由于并不需要程序员理解Solidity 源码的编译过程,并且等价性检查对基于IL 进行形式化验证的有效性至关重要(例如ZEUS 的大多数误报正是由Solidity 与转换为LLVMIR 后的语义不一致造成的),因此对Solidity 以及生成的领域特定语言(Domain Specific Language,DSL)这样的高级语言进行形式化验证也是研究的热点。文献[23]中基于形式记忆框架完成了第一个Solidity 子集的语义形式化工作。

模型检测(Model Checking)可以根据系统的规格自动验证具有有限状态的系统模型。该方法的基本思想是通过状态空间搜索来确认合约是否具有某些性质。即给定一个智能合约P和规约ψ,生成对应的合约模型M,然后证明规约公式ψ在智能合约模型M中成立,这样就证明了智能合约P满足规约ψ。在基于模型检测方法的智能合约安全审计研究工作中,模型检测方法的流行得益于传统代码分析领域大量成熟的框架与工具的存在,比如NuSMV 和nuXmv 等模型检查器以及WebGME 等开源Web 框架。

文献[24]中提出FSolidM 工具,该工具建立在WebGME之上,能够将智能合约转为有限状态机,并通过锁定、交易计数器等插件完成对重入漏洞与交易排序依赖漏洞的检测;在此基础上,文献[25]中进一步设计并实现集成了nuXmv 验证器的VeriSolid 工具,以满足并发系统死锁和活锁等机制的验证需求;文献[26]中则基于多个智能合约交互的视角,通过引入部署图来扩展VeriSolid 系统的操作语义;文献[27]中提出一种由不同实体开发和控制的交互智能合约组成的系统的验证方法,该方法使用NuSMV 模型检测器和行为-交互-优先级(Behavior Interaction Priority,BIP)工具建模智能合约的行为及交互,从而验证它们是否符合系统的功能要求。

上述模型检测方法虽然已经从对单个智能合约的验证扩展到了对智能合约交互进行验证,但由于NuSMV 等模型检测器输入语言的限制,模型检查方法很少考虑区块链上智能合约执行的细节,比如Gas 机制或内存模型,这意味着对区块链环境进行精确建模成为了难点。文献[28]中考虑智能合约在执行环境中的执行行为因素,如合约的注册、外部交易的接收等并对此进行建模;文献[29]中通过将着色Petri网(Colored Petri Net,CPN)与EVM 字节码的程序逻辑相结合,实现了一个更现实的智能合约执行模型。

3.3 模糊测试

模糊测试(Fuzzing)是一种流行且有效的软件测试技术,通过向被测智能合约输入大量意外数据,检测异常发生情况,从而发现潜在漏洞。相较于符号执行与形式化验证等方法的复杂设计,模糊测试具有简单高效的特点,而且是在运行过程中测试,有助于挖掘出更深层的智能合约漏洞。

文献[30]中设计并实现了第一个基于模糊测试的以太坊智能合约漏洞检测工具ContractFuzzer,通过分析智能合约的应用程序二进制接口(Application Binary Interface,ABI)生成符合被测智能合约调用语法的输入。在输入用例生成过程中,该工具针对重入等7 个类型的智能合约漏洞按照固定大小输入与非固定大小输入两类将用户提供的输入种子生成输入。

后续学者在智能合约模糊测试领域的研究工作热衷于提高模糊测试中测试用例的覆盖率以提高漏洞检测的精度。文献[31]中提出一种基于属性的智能合约测试工具Echidna,它利用了基于语法的模糊测试。Echidna 首先通过智能合约静态分析框架编译合约并进行分析,确定直接处理ETH 的常量和函数;然后基于得到的常量、事务与函数生成的随机交易进行模糊测试。文献[32]中提出名为sFuzz 的方法,该方法基于传统工具AFL,采用反馈自适应模糊策略并考虑将区块编号和时间戳建模为环境信息,以提高路径覆盖率。文献[33]中结合深度学习在学习阶段通过神经网络对运行符号执行所获得的交易序列进行训练,但也增加了学习阶段的开销。文献[34]中提出了一个用于智能合约的混合模糊测试器ConFuzzius,结合了进化模糊测试和约束求解,能执行更多的智能合约代码并找出更多的bug。进化模糊测试用于测试智能合约的浅层逻辑,约束求解用于生成可以满足复杂条件的输入,从而得到更深入的测试路径,而且ConFuzzius 使用数据依赖分析高效地生成交易序列,以找出可能存在bug 的特定的合约状态。

另外,也有越来越多的学者致力于研究效率和覆盖率平衡的智能合约模糊测试方法。文献[35]中通过污点分析指导交易序列的生成,排除候选测试对象,从而实现最小化搜索空间并提高模糊测试过程效率的目的。文献[36]中提出一种用于智能合约漏洞挖掘的灰盒模糊测试方法Harvey,它在兼顾灰盒模糊测试方法轻量级特点的同时通过基于预测输入和基于需求驱动的模糊序列的方式以提高覆盖率。

4 智能合约漏洞修复与升级部署方法

虽然已经有如第3 章所示的各类方法致力于检测出智能合约的错误,以太坊社区也已经发布了许多安全编程建议与指南[37-39],但一旦智能合约部署在区块链上,区块链系统就认为它的代码不可改变,因此需要漏洞自动修复技术以升级部署无错误的指南合约,否则,智能合约安全审计方法反而会增加攻击者利用合约漏洞的可能性。

对于智能合约升级部署问题,以太坊社区已经探索了几种设计模式来支持可升级的智能合约[40-43]。其中,最简单的方法是将修补后的合约部署在新地址,并将原始合约的状态迁移到该地址。但这一过程要求合约开发者访问旧合约的所有内部状态以及新合约中接受状态转移的程序,增加了开发者的工作量。为避免状态迁移,合约修复与升级还可以由开发者使用新的合约作为数据存储合约(也称为永恒存储模式)来实现,但是这会增加外部调用带来的额外的Gas 开销问题。一种更实用的策略是使用委托调用代理模式编写合约。在该模式下,一个智能合约被拆分为两个不同的合约:1)代理合约,持有所有资金和所有内部状态,但不实现任何业务逻辑,它是所有用户交易的接入点,具有不可变的代码与合约地址。2)逻辑合约,包含管理合约动作的实际代码。代理合约使用DELEGATECALL 指令将所有函数调用转发到注册的逻辑合约。该指令用于授予逻辑合约访问代理合约中存储的所有内部状态和资金的权限。当智能合约升级时,首先需要部署一个新的逻辑合约,并在代理合约中更新相应地址;然后,代理合约将所有未来的交易转发给修补后的逻辑合约。在这一部署升级合约的过程中不需要任何数据迁移,因为所有数据都存储在不可变代理合约中,并且,由于合约地址保持不变,用户对升级过程也是可见的。

由于区块链系统的分布式特性,智能合约数量始终在线增长,合约升级模式又要求确保版本兼容,因此修补智能合约错误是一个耗时、繁琐的过程,对自动化的智能合约字节码重写技术研究成为了一项重要且具有实际意义的工作。

文献[44]中提出了智能合约字节码修复系统SMARTSHIELD,该系统的工作流程如图9 所示。该系统的工作流程主要包含以下2 部分:1)语义提取。首先分析每个智能合约的抽象语法树(Abstract Syntax Tree,AST)和未修正的EVM 字节码,以提取字节码级语义信息。2)合约修正。基于提取的字节码级语义信息通过控制流转换和DataGuard插入来修正不安全的控制流和数据操作,最后,生成修正后的EVM 字节码并向开发人员发送一份修正报告。

图9 SMARTSHIELD工作流程Fig.9 Workflow of SMARTSHIELD

SMARTSHIELD 主要分析与修正了3 种典型的不安全代码模式:1)状态变量(存储在存储器中的变量)在外部函数调用之后被更新,该系统将所有状态更改移至外部函数调用的前面来对它进行修正。2)在不事先检测数据有效性的情况下,执行算术语句。该系统通过将边界检查插入到算术运算中对它进行修正。3)在调用外部合约中的函数或发送以太币后不检查返回值,该系统在外部函数调用后,插入有效性检查来确保调用函数的返回值并进行修正。

由于SMARTSHIELD 在语义提取阶段需要完整的控制流图(Control Flow Graph,CFG)来更新跳转目标和数据引用,使这一修复策略不能很好地扩展到更大更复杂的合约中。相较之下,文献[45]中提出的EVMPatch 框架基于跳板(Trampoline)的重写策略不需要精确的CFG,在重写复杂合约时具有更好的可扩展性。EVMPatch 框架如图10 所示,主要由以下组件组成:1)由自动分析工具和公开漏洞披露组成的漏洞检测引擎;2)将补丁应用到合约的字节码重写器;3)验证先前交易补丁的补丁测试机制;4)上传合约补丁版本的合约部署组件。

图10 EVMPatch框架Fig.10 Framework of EVMPatch

在字节码重写器中,基于Trampoline 的方法将新的EVM指令添加到空白代码区域,从而在新合约代码插入合约地址时,可以保留或更新智能合约的代码地址空间中对任何代码或数据的所有基于地址的引用空间。并且该方法考虑了EVM 在代码地址空间中强制对代码和数据进行分隔,突出了EVM 字节码重写器的特殊性,以达到更适用于智能合约字节码生成的目的。

5 挑战与展望

智能合约的安全问题研究吸引了学术界和产业界的共同关注。随着区块链技术与平台的快速发展,智能合约的应用越来越广泛,其中的漏洞挖掘与自动修复技术面临着在线、多平台、自动化与智能化的挑战。

挑战1:多区块链平台智能合约漏洞挖掘与安全增强。

随着支持智能合约功能的区块链平台的迅速发展,智能合约在这些平台上也暴露出一些令人瞩目的漏洞,越来越多的研究开始关注这些非以太坊智能合约的漏洞挖掘工作。文献[46]中关注最具代表性的采用委托权益证明(Delegated Proof of Stake,DPoS)共识机制的区块链项目Enterprise Operation System(EOSIO),基于符号执行技术识别出EOSIO 智能合约中4 个最流行的漏洞的存在,并确定了48次扩展中的攻击(其中27 次已被开发人员确认),这些攻击已导致至少170 万美元的经济损失。文献[47]中则通过模糊测试技术对Hyperledger Fabric 这一联盟链的合约漏洞进行检测。

上述工作的挑战在于不同平台的智能合约从虚拟机、合约字节码到漏洞类型都不相同,因此现有的对以太坊智能合约的安全审计技术并不能直接应用于这些平台,例如EOSIO虚拟机支持的浮点运算、类型转换等指令在EVM 上不支持,并且EOSIO 智能合约还具有不开源的特点与挑战。因此未来的研究工作中在对这些非以太坊智能合约漏洞进行检测时需要更多地考虑这些区块链平台具有的特点。另外,由于在联盟链等许可链场景下,区别于以太坊区块链节点可以随意加入,智能合约往往运行在“授权”的区块链节点上,因此对这类智能合约进行安全增强时,一种可行的方案是采用可信计算技术来保障智能合约运行环境以及在上链过程中数据传输的安全可靠。考虑到可信计算环境的构建会损害区块链的去中心化特性,现有研究仅利用可信执行环境技术以保障以太坊智能合约运行过程中的数据隐私性[48-51],但针对联盟链等去中心化程度相对较低的许可链场景,对其智能合约的运行节点进行可信防护则很有意义与价值。

挑战2:在线智能合约安全审计。

智能合约具有一经部署不可变的特点,区块链平台上的智能合约数量持续增加,如何高效、实时地检测在线的智能合约近年来也吸引了学者们的关注。文献[52]中提出了Sereum 技术,利用污点分析保护现有的、已经部署的具有可重入漏洞的智能合约以向后兼容的方式免受攻击;而对于区块链上易受攻击的智能合约,特别是蜜罐类智能合约,文献[53]中基于模式匹配实时恢复交易,但是并没有透露具体的设计、实现和评估;文献[54]中则提出了一种名为SODA 的更加兼具功能与效率的在线智能检测框架,通过按需信息检索以减少信息收集的开销,并采用动态链接来消除进程间通信的开销。在这些研究中,在线智能合约安全审计技术的挑战在于对区块链运行时行为的要素建模与检测效率的平衡,并且随着智能合约漏洞类型的增多,需要考虑方法的可扩展性。

挑战3:智能化合约漏洞挖掘、利用与修复技术。

随着深度学习的快速发展,越来越多的研究开始利用人工智能技术结合智能合约静态代码分析技术以完成合约代码注释[55-56]、安全审计[57-59]等工作,尤其是文献[59]中提出基于图神经网络的漏洞挖掘工作,明显提升了检测精度。这些方法通常基于智能合约抽象语法树以及控制流图来进行语义知识的学习与训练,但存在一个较为普遍的问题:有标签的样本数量较少。现有的解决方法主要利用成熟的开源静态代码检测器标记是否存在漏洞;但这样的方法仍存在检测漏洞种类有限、难以发现新类型恶意智能合约、目标泄露导致预测偏移等诸多问题。

针对这些问题与挑战,提出如图11 所示的在线合约智能化安全检测与自动化修复升级框架,由虚拟机/Docker 层、异构区块链架构层、可信计算层组成,结合合约代码分析与区块链情景分析两个维度,并采用可信计算技术进行异构智能合约运行环境的安全增强,从而实现智能合约在线安全检测与合约漏洞自动化修复升级两大功能,达到智能合约全生命周期的安全审计与可信防护的目的。

图11 在线合约智能化安全检测与自动化修复升级框架Fig.11 Architecture of online contract intelligent security detection and automatic repair

该框架针对上述挑战,解决思路具体如下:

针对挑战1,框架的整体架构在可信计算层之上。可信计算层基于TrustZone、SGX(Software Guard eXtension)、Keystone 等异构安全机制,可分别为许可链上的智能合约构建可信的运行环境,并且保障智能合约在修复升级中上链过程的传输安全;而对非许可区块链上的智能合约,可为它的数据提供隐私保护。同时,框架提取异构区块链下的智能合约的特征,考虑到在存储机制、验证机制、共识机制等区块链情景上的不同,框架提取共识验证特征、合约执行流特征、交易输入特征与存储结构特征,并针对不同智能合约以字节码的形式读取合约数据,为接下来的数据分析作准备。

针对挑战2,框架从合约字节码分析与区块链情景分析两个角度出发:1)对于单个智能合约,采用轻量级符号执行工具基于合约字节码构造控制流图,得到合约内函数调用关系等结构信息,并利用自然语言处理(Natural Language Processing,NLP)方法中表示学习技术生成字节码指令的语义信息。2)考虑智能合约构建、存储、执行的全生命周期,分析智能合约安全威胁机理,借助机器学习算法对区块链的异常结构进行分类,再利用知识图谱方法进一步分析智能合约之间在运行时的交互关系与方式,从而得到智能合约行为信息。基于上述分析结果,进一步基于图神经网络进行训练与预测,从而实现区块链智能合约在线安全检测自动化。

针对挑战3,框架在现有基于图神经网络检测工作取得的良好精度的基础上,从智能合约字节码、交易历史、执行流及其他多元信息出发,分析了合约操作码和账户交易特征等区块链情景,有助于提升神经网络模型泛化能力以及现有方案对未知类型漏洞智能合约的检测能力。另外,在安全检测功能模块中,框架采用小样本学习等更先进的深度学习技术进行数据增强从而解决数据不平衡的问题。

6 结语

本文介绍了智能合约漏洞挖掘与自动修复技术的研究现状,重点介绍与分析了三类智能合约漏洞挖掘方法的研究趋势,并调研介绍了主流的智能合约升级方案以及较前沿的自动修复技术实现框架与思路。在总结这些关键技术的基础上分析了未来的三个重要的发展方向及所需解决的问题,并进一步提出一种在线智能合约智能化安全检测与自动化修复升级框架,有助于未来研究工作应对这些挑战。

猜你喜欢
以太调用字节
No.8 字节跳动将推出独立出口电商APP
核电项目物项调用管理的应用研究
No.10 “字节跳动手机”要来了?
LabWindows/CVI下基于ActiveX技术的Excel调用
车易链:做汽车业的“以太坊”
简谈MC7字节码
基于系统调用的恶意软件检测技术研究
A Study on the Contract Research Organization
百通推出入门级快速工业以太网络交换器系列
以太互联 高效便捷 经济、可靠、易用的小型可编程控制器