案例:TheDAO事件,最终损失360万枚ETH并导致以太坊硬分叉
本质:在调用取钱函数的时候会执行fallback回调函数(一般用于输入日志),攻击者利用该性质在fallback函数中修改逻辑,导致函数递归调用取钱函数,因此造成账户的所有ETH被转走
利用两点:程序的健壮性、fallback函数
注:合约在以下两种情况下会执行fallback函数
4种解决方法:
案例:美链BEC代币
在Solidity中uint默认为256位无符整型,可表示范围[0,2^256-1],在下面的示例代码中通过做差的方式来判断余额,如果传入的_amount大于账户余额,则balances[msg.sender]-_amount会由于整数下溢而大于0绕过了条件判断,最终提取大于用户余额的Ether,且更新后的余额可能会是一个极其大的数。
解决方案:将条件判断改为require(balances[msg.sender]>_amount),这样就不会执行算术操作进行逻辑判断,一定程度上避免了整数溢出的发生。
总之,为了防止整数溢出的发生,一方面可以在算术逻辑前后进行验证,另一方面可以直接使用OpenZeppelin维护的一套智能合约函数库中的SafeMath来处理算术逻辑。
重放攻击是指“一条链上的交易在另一条链上也往往是合法的”,所以重放攻击通常出现在区块链硬分叉的时候。由于硬分叉的两条链,它们的地址和私钥生产的算法相同,交易格式也完全相同,因此导致在其中一条链上的交易在另一条链上很可能是完全合法的。所以你在其中一条链上发起的交易,就可以到另一条链上去重新广播,可能也会得到确认。
解决方案:
这种攻击是指矿工或其他方试图通过将自己的信息插入列表(list)或映射(mapping)中来与智能合约参与者进行“竞争”,从而使攻击者有机会将自己的信息存储到合约中。
将参数传递给智能合约时,参数根据ABI规范进行编码,可以发送比预期参数长度短的编码参数(例如,发送一个只有38个十六进制字符(19个字节)而不是标准的40个十六进制字符(20个字节)的地址)。在这种情况下,EVM将在编码参数的末尾添加零以构成预期长度。
例子:
现在考虑一个持有大量代币的交易所和一个希望提取其100个代币的用户。该用户提交自己的地址0xdeaddeaddeaddeaddeaddeaddeaddeaddeaddead和需要取的代币数量100,交易所将按照transfer函数指定的顺序对这些参数进行编码;也就是address+tokens。则编码结果为:
总字节数为4(transfer函数签名)+32(合约地址)+32(代币数量)。
如果我们发送的地址缺少1个字节(2个十六进制数字),假设攻击者发送地址为0xdeaddeaddeaddeaddeaddeaddeaddeaddeadde(缺少后两位数字),代币数量不变为100,则它将被编码为:
此时整串编码末尾会补上两个0以达到预期长度4+32+32,但这时tokens将被读取为56bc75e2d6310000000,该值现在是25600tokens,而交易所认为用户只是在提取100tokens。
解决方案:在将外部应用程序中的所有输入参数发送到区块链之前,应对其长度进行验证。
注:短地址攻击通常发生在接受畸形地址的地方,如交易所提币、钱包转账,所以除了在编写合约的时候需要严格验证输入数据的正确性,而且在Off-Chain的业务功能上也要对用户所输入的地址格式进行验证,防止短地址攻击的发生。
针对智能合约的DoS攻击方式通常有3种:
解决方案:对链上数据进行加密
根本原因:未能明确或未仔细检查合约中函数的访问权限,从而允许恶意攻击者能进入本不该被其访问的函数或变量。
主要体现在2个层面:
以太坊智能合约中,有3种情况会抛出异常:
然而,智能合约中的一些底层调用函数(如send,call,delegatecall)发生异常时只返回False,而不抛出异常。因此仅仅根据有无异常抛出就判断合约执行是否成功是不安全的,在调用底层函数时必须严格检查返回值,并且对异常采用一致性的处理方式。
在智能合约部署之前,对其代码和文档进行形式化建模,然后通过数学的手段对代码的安全性和功能正确性进行严格的证明,可有效检测出智能合约是否存在安全漏洞和逻辑漏洞。该方法可以有效弥补传统的靠人工经验查找代码逻辑漏洞的缺陷。
缺点:需要交互式的验证与判断,因此自动化程度较低,并且依赖人工二次核验,导致其无法较好地兼容EVM执行层漏洞。同时,由于形式化验证手段依赖于严谨的数学推导与验证,它无法执行动态分析,并且缺少对合约中可执行路径的检测与判断,从而导致了较高的误报率和漏报率。
方案:
(1)F*framework.F是一种形式化验证方法,通过将EVM字节码的语义形式化并把EVM字节码编译成Ocaml形式,最终将智能合约源码和字节码转化成函数编程语言F,以便分析和验证合约的安全性和功能正确性,从而成功检测以太坊智能合约漏洞.
(2)KEVMframework.KEVM是一种形式化分析的框架,它利用K框架构建了基于EVM字节码栈的可执行形式化规范,提供了EVM的规范、参考解释器以及用于程序分析和验证的工具.
(3)Isabelle/HOL.Isabelle/HOL是一种EVM字节码级别的形式化验证方法,其通过将字节码序列构造成直线代码块或将合约拆分成基本块,并在此基础上创建逻辑程序进行推理验证.
(4)ZEUS.ZEUS是一种静态分析工具,其基于形式化验证的方法能够正确且公平地分析智能合约.ZEUS利用抽象解释和符号模型检查以及约束语句来快速验证合约的安全性,支持多种智能合约漏洞的检测,例如可重入漏洞、整数溢出漏洞、异常处理漏洞等.
(5)VaaS.VaaS是基于形式化验证方法的“一键式”智能合约安全检测平台,它可以自动检测智能合约中10大项32小项的常规安全漏洞,并且能够精准定位风险代码位置以及给出修改建议.
主要思想是将代码中的变量符号化。通过符号化程序输入、符号执行能够为所有的执行路径维护一组约束,执行之后,约束求解器将用于求解约束并确定导致该执行的输入,最后利用约束求解器得到新的测试输入,检测符号值是否可以产生漏洞。
符号执行法应用于智能合约漏洞检测的执行过程为:首先,将合约中的变量值符号化,然后逐条解释执行程序中的指令,在解释执行过程中更新执行状态、搜集路径约束,以完成程序中所有可执行路径的探索并发现相应的安全问题。
(1)Oyente.Oyente是最早的智能合约漏洞静态检测工具之一,其在合约控制流图的基础上利用符号执行的方法检测智能合约漏洞.Oyente以智能合约字节码和以太坊状态作为输入,模拟EVM并且遍历合约的不同执行路径,其支持检测的漏洞类型包括可重入漏洞、异常处理漏洞、交易顺序依赖漏洞等.
(2)Maian.Maian是一种基于符号分析的智能合约分析工具,它通过长序列的合约调用过程来发现安全漏洞.区别于一般的合约分析工具,Maian只专注于3种类型的合约漏洞,即资产无限期冻结的合约漏洞(Greedy),易泄露资产给陌生账户的合约漏洞(Prodigal),合约可以被任何人随意销毁的漏洞(Suicidal).
(3)Securify.Securify是一种用于以太坊智能合约的静态安全分析器,具有可伸缩、完全自动化、准确率高等特性,其通过分析合约的依赖图以及从代码中提取精确的语义信息来检查合约的合规性与安全漏洞.
(4)Mythril.Mythril是一种智能合约静态分析工具,其使用概念分析、污点分析以及控制流验证来检测以太坊智能合约中常见的漏洞类型,包括可重入漏洞、整数溢出漏洞、异常处理漏洞等.
(5)TeEther.TeEther是一种智能合约静态分析工具,区别于一般的漏洞检测工具,它考虑了智能合约漏洞自动识别以及合约生成方法,并通过分析合约字节码查找关键的执行路径以检测合约的安全问题.
(6)Sereum.Sereum是一种专注于智能合约可重入漏洞的新颖检测方案,该解决方案利用动态污点跟踪监视智能合约执行过程中的数据流,从而自动检测并防止状态不一致的情况,有效地检测了可重入攻击.
从概念上讲,模糊测试从目标应用程序中生成大量正常和异常的测试用例,尝试将生成的用例提供给目标应用程序并监视执行状态中的异常结果以发现安全问题。与其他技术相比,模糊测试具有良好的可扩展性和适用性,可以在没有源代码的情况下执行。
缺点:依赖于精心设计的测试用例,对导致漏洞的具体语义代码洞察有限,很难追踪到存在漏洞的确切代码位置,同时由于测试用例的随机性,其无法达到理想的测试路径覆盖率,很难找出所有的潜在威胁。
(1)ContractFuzzer.ContractFuzzer是第一个基于模糊测试的以太坊智能合约安全漏洞的动态分析方法,其基于智能合约ABI规范生成模糊测试用例并定义测试方案来检测安全漏洞.首先,ContractFuzzer对EVM进行配置并记录智能合约运行时的行为,然后通过分析这些日志并检测漏洞.
(2)Regurad.Regurad是一种专注于智能合约可重入漏洞的模糊测试分析器,其通过迭代生成随机且多样化的测试用例对智能合约执行模糊测试,从而在合约的执行过程中进行跟踪,进一步地动态识别可重入漏洞.
(3)ILF.ILF是基于神经网络的智能合约模糊测试器,它利用符号执行引擎生成有效的测试和调用序列,以指导神经网络模型的特征学习,从而实现有效的漏洞检测.
研究者们通过将智能合约源码或字节码转换成具有高语义表达的中间表示(intermediaryrepresentation,简称IR),然后利用控制流、数据流以及污点分析等手段对合约的中间表示进行分析以发现安全问题。
缺点:依赖于预定义的语义规则或分析列表,从而无法检测出智能合约复杂的业务逻辑问题且极易产生误报。另外,它们无法对合约中可能存在的执行路径进行遍历。
(1)Slither.Slither是一种以太坊智能合约的静态分析框架,它将智能合约Solidity源代码转换为SlithIR的中间表示,SlithIR使用静态单一分配(SSA)形式和精简指令集来简化合约分析过程,同时保留了Solidity源代码转换为EVM字节码时丢失的语义信息.
(2)Vandal.Vandal是一种EVM字节码层面的智能合约静态分析工具,它由一个分析管道和一个反编译器组成.该反编译器执行抽象解释,以逻辑关系的形式将字节码转换为更高级别的中间表示(IR),然后使用新颖的逻辑驱动方法检测合约漏洞.
(4)Ethir.Ethir是一种基于EVM字节码层面的分析工具,它基于Oyente生成控制流图(CFG),然后将CFG转换为基于规则的中间表示(RBP),从而分析和推断EVM字节码的安全属性.
(5)Smartcheck.SmartCheck是一种可扩展的智能合约静态分析工具,它将智能合约Solidity源代码转换为基于XML的中间表示,然后利用XPath的模式来检测智能合约漏洞.
(6)ContractGuard.ContractGuard是一种面向以太坊智能合约的入侵检测工具,它基于入侵检测系统(IDS)检测潜在攻击引发的异常控制流,通过有效的上下文标记(context-tagged)无环路径实现入侵检测.
缺点:其大多数情况下可解释性较差,即无法像传统的检测工具一样给出可能存在漏洞的确切位置或代码行。
(1)SaferSC.SaferSC是第一个基于深度学习的智能合约漏洞检测模型,其基于Maian划分的3类合约漏洞,实现了比Maian更高的检测准确率.此外,SaferSC在智能合约操作码(operationcode,简称opcode)层面进行分析,利用LSTM网络构建了以太坊操作码序列模型,实现了精准地智能合约漏洞检测.
(2)ReChecker.ReChecker是第一个基于深度学习的智能合约可重入漏洞检测方法,其通过将智能合约Solidity源代码转换为合约块(contractsnippet)的形式,捕获了合约中基本的语义信息和控制流依赖信息.ReChecker利用双向长短期记忆模型(BidirectionalLongShort-TermMemory,简称BLSTM)和注意力机制(Attention)实现了以太坊智能合约可重入漏洞的自动化检测.
(4)TMP.TMP通过将智能合约中的关键函数和关键变量转换成具有高语义信息的核心结点来构建合约图,关键的执行方式转换成控制流和数据流依赖的有向时序边.TMP在DR-GCN的基础上考虑了合约图中边的时序信息,并利用时序图神经网络实现了相应的智能合约漏洞检测.
ps:钱鹏,刘振广,何钦铭,黄步添,田端正,王勋.智能合约安全漏洞检测技术研究综述.软件学报,2021.