智能合约中的溢出和下溢攻击10 Apr 2025 | 7 分钟阅读 引言在区块链网络上运行的程序称为智能合约。为了在没有可靠第三方的情况下进行分布式系统中的金融交易,它们通过明确定义的接口进行通信。然而,这些接口也为攻击者提供了一个有利的环境,让他们可以利用智能合约中的安全漏洞来获利。 - 智能合约最简单的定义是,一段对所有网络用户透明且可在区块链上公开查看的代码。
- 当满足特定时间的要求时,合约将被触发以执行数字交易。
- 由于合约的条款经过加密保护,任何一方都无法更改。
- 合约的备份副本得到了保护,因为区块链的不可变性保证了连接到网络的所有设备都拥有合约副本。
本教程重点介绍智能合约中的溢出和下溢威胁。下溢和溢出攻击都属于整数溢出的范畴。 什么是整数溢出?Solidity 中有两种整数: - 无符号整数 (uint): 介于 0 和 2^256-1 之间的正值称为无符号整数或 uint。
- 有符号整数 (int): 包括正数和负数,范围从 -2^255 到 (2^255 - 1)。
当执行一个需要固定大小的 变量 来存储操作结果的操作时,就会发生溢出或下溢。 溢出情况令 uint8 a 为一个无符号 8 位 整数 变量。此变量的范围是 0 到 255。 由于变量 a 的值介于 0 和 255 之间,这会导致溢出错误。值增加 1 就会导致溢出。 下溢情况令 uint8 a 为一个无符号 8 位整数变量。此变量的范围是 0 到 255。 由于变量 a 的值介于 0 和 255 之间,如果值减 1 就会发生代码崩溃,这会导致下溢错误。 在以太坊中识别整数溢出的过程和挑战- 无指示: 与其他编程语言不同,EVM 不会显示整数溢出的指示。交易后保存的值可用于推断是否发生了溢出。重新运行交易是确定是否存在溢出情况的最常用方法。
- 算术运算: 整数溢出或下溢也可能在两个整数相加或相减时发生。由于指数运算依赖于乘法,而乘法过程又基于加法,因此这两种过程都容易受到溢出攻击。
- 误报: 在某些情况下,可以确定导致整数溢出的运算以及操作数的符号或无符号状态。将溢出情况视为基本错误还是故意产生的情况可能很难确定,因为某些编译器会故意产生溢出情况来执行某些函数。
- 字节码级别缺乏类型: 有符号和无符号整数类型仅在高层编程语言中定义。因此,当智能合约缺少 Solidity 源代码时,很难估算整数的类型。
智能合约中的溢出错误攻击当提供的值超过最大值时,智能合约会遭受溢出错误攻击。通过连续使用增加值的函数,人们可以利用当它循环回到零的事实。开发人员应意识到此问题,并确保他们的代码考虑到这些潜在的错误,因为 Solidity 缺乏本地溢出检测。可以使用安全数学库或合适的类型(如 uint256 用于整数运算)来完成此操作。 示例 1说明- 此示例演示了恶意用户如何向合约发送比单个单元可存储的以太更多的以太。
- 如果 amount 变量的值达到 uint 的最大值 (2^256),它会循环回来并将其设置为 0,这可能有点难以管理。
- 这可能允许攻击者从合约中提取资金,并产生意想不到的影响,例如整个余额变为负数。
解决方案说明在这种情况下,通过确定收件人账户中的总金额以及需要转移的金额是否超过或等于收件人账户余额来验证溢出情况。这保证了即使允许用户一次增加一个值,也没有实际方法可以超过此限制。 开发人员应使用带有溢出检测的正确类型或安全数学库来避免此类攻击。 示例 2为了利用此漏洞,攻击者可以传入参数调用此函数。例如,以下代码将检查移至 balances[msg.sender] > = total。为了使代币智能合约向两个地址发送以太,攻击者可以在 receivers 函数中输入两个地址。 该行存在错误。 说明- 攻击者向受害者合约发送 1 Wei 以启动攻击。
- 对于发送的资金,发送者在合约下记账。
- 他们再次要求提取相同的 1 Wei。
- 当合约从发送者信用中扣除 1 Wei 时,余额再次为零。
- 由于攻击者从目标合约接收以太,攻击者的 fallback 函数也会被激活,从而导致另一次提款请求。
- 提款 1 Wei 被记录。
- 攻击者的合约余额已更新两次,第一次为零,第二次为 -1。
- 攻击者的余额已恢复到 2^256。
- 通过提取目标合约中的所有资金,攻击者完成了攻击。
智能合约中的下溢错误攻击与溢出错误不同,这种错误攻击的工作方式完全相反。下溢错误发生在您低于最小金额而不是超过最大值时。这不会导致系统返回到零,而是会立即将您的值提高到最大值。然而,由于攻击者通常很难获得必要的代币来产生溢出,因此下溢攻击更容易执行。这些漏洞出现在允许未经授权的输入数据或值的交易中,并且非常容易开始。 示例如以下示例所示,该函数未能检查整数下溢,从而允许提取大量代币。 说明由于在这种情况下没有检查整数下溢,攻击者可能会利用该代码并提取大量代币。验证修改后的整数是否在字节限制内是避免成为下溢攻击目标的最佳方法。 溢出和下溢攻击的影响与溢出相比,下溢问题更容易发生,并且可能导致灾难性后果。 - 如果软件未配备用于检查下溢和溢出的函数,攻击者就可以获得比他们拥有的更多的代币。此外,他们可以获得最大余额,这相当于盗窃。
- 由于最大化代币的数量因系统中代币的数量而异,因此这些错误有潜力导致整个系统崩溃。
防止溢出和下溢攻击以下是一些减少溢出和下溢攻击的策略: - SafeMath 库: 开发人员应使用提供溢出检测的安全数学库或合适的类型来防范整数溢出或下溢攻击。除了提供基本的算术运算外,该库还可以验证前提条件和后置条件,以查看是否发生了溢出。如果存在错误,该库将拒绝交易并将其状态更改为“已回滚”。
- 编译器版本: 可以使用 Solidity >= 0.8 来阻止攻击。使用更新的 编译器 版本来编译智能合约。因此,生成的代码包含来自 SafeMath 等外部库的预防代码。
- 使用“onlyOwner”修饰符: 为了进一步提高安全性,他们还可以使用“onlyOwner”等修饰符,或在其代码中包含测试以确保值永远不会超出预期范围。
- 定期更新代码: 最后,为了防止任何潜在的漏洞,定期更新代码也很重要。
溢出和下溢攻击的实际示例- Coinstar (CSTR) 智能合约实现中的 mintToken 函数中的整数溢出允许智能合约所有者将任何意外用户的余额更改为任意数字。
- 4chan 团队使用 Solidity 创建了名为 Proof of Weak Hands Coin (PoWHC) 的以太坊庞氏骗局。由于其创建者未能注意到下溢或溢出问题,从智能合约中释放了 866 个以太。
- 一个例子是 BeautyChain 合约,攻击者利用整数溢出的行为,绕过了安全措施,窃取了大量的 BEC 代币。
结论本教程详细介绍了区块链中的溢出和下溢攻击以及如何防止这些攻击。
|