重入漏洞完全实战指南

  • Ackee
  • 发布于 7小时前
  • 阅读 87

本文全面分析了重入漏洞,并通过可执行的示例介绍了各种攻击类型。

本指南提供了重入漏洞的全面分析,并为每种攻击类型提供了实用的、可执行的示例。了解不同的重入模式如何工作,以及如何在实际协议中识别它们。

什么是重入?

当外部合约调用在完成执行之前递归地回调到调用函数时,就会发生重入。在外部调用期间,控制权传递给接收者合约,该合约可以执行任意代码。如果在外部调用之后发生状态更新,攻击者可以重新进入该函数并耗尽资金。

重入攻击今天仍然在发生。有关历史重入漏洞利用的完整列表,请参阅 pcaversaccio 的重入攻击仓库

任何进行外部调用的合约都可能存在漏洞,尤其是那些与提款机制、DeFi 协议和跨链 相关的合约。

如何预防重入?

遵循 Checks-Effects-Interactions (CEI) 模式:执行检查,更新状态,然后才进行外部调用。这种排序可以防止不一致状态的利用。

ReentrancyGuard 可以防止单合约重入,但不能防止跨合约攻击。使用 拉取支付(pull payment) 模式并最小化外部调用以获得更好的安全性。

Wake 基于 Python 的框架包括通过静态分析和测试模式进行重入检测,在部署之前识别漏洞。

识别重入漏洞

关键攻击向量包括:

  • 在状态更新之前进行外部调用的函数
  • 带有 Hook(hooks)代币标准(token standards) (ERC-777, ERC-1155)
  • 闪电贷(Flash loan) 实现
  • 跨链消息传递系统

每个外部调用都是潜在的漏洞点。

重入攻击的类型

重入的范围从简单的递归调用到复杂的多合约漏洞利用。每种类型都需要不同的防御策略。开发人员必须在开发过程中考虑所有攻击的可能性。让我们仔细看看这些关键漏洞的机制。

单函数重入

单函数重入中,攻击者在外部调用期间递归地调用同一个函数。它在提款函数中最常见,这些函数在更新余额之前发送 ETH。

漏洞示例:

function withdraw() public {
        uint256 amount = balances[msg.sender];
        (bool success, ) = msg.sender.call{value: amount}("");
        require(success, "Failed to send Ether");
        balances[msg.sender] = 0; // 在外部调用后更新状态
}

攻击步骤:

  1. 攻击者存入资金并调用 withdraw()
  2. 在外部调用期间,攻击者的合约重新进入 withdraw()
  3. 余额尚未重置,因此提款再次成功
  4. 重复该过程,直到合约被耗尽

预防: 遵循 CEI 模式,在外部调用之前更新状态。

跨函数重入

跨函数重入 利用一个合约中的多个函数。当开发人员保护单个函数但忽略它们的交互时,它会变得危险。

漏洞示例:

contract Vault is ReentrancyGuard {
        function transfer(address to, uint256 amount) public {
                // 此处没有重入保护
                if (balances[msg.sender] >= amount) {
                        balances[to] += amount;
                        balances[msg.sender] -= amount;
                }
        }
        function withdraw() public nonReentrant {
                uint256 amount = balances[msg.sender];
                (bool success, ) = msg.sender.call{value: amount}("");
                require(success, "Failed to send Ether");
                balances[msg.sender] = 0;
        }
}

攻击向量: 攻击者通过 withdraw() 外部调用期间未受保护的 transfer() 重新进入,在提款完成之前操纵 余额(balances)

预防: 将重入保护应用于所有修改状态的函数,或始终如一地使用 CEI 模式。

跨链重入

顾名思义,跨链重入 操纵跨链消息传递以跨链 铸造(mint) 重复 代币(tokens) 。这使得它对于桥的实现至关重要。

漏洞模式: 跨链合约通常在外部调用(如 _safeMint())之后递增计数器或更新状态。如果攻击者在外部调用期间重新进入,他们可以在状态更新之前多次触发相同的跨链事件。

实际影响: 相同的 tokenId 在多个链上铸造,破坏了桥的核算并创建了 幽灵代币(phantom tokens)

预防:

  • 在外部调用之前更新跨链状态变量
  • 实现对关键变量的 后调用验证(post-call verification)
  • 在跨链函数上使用重入保护

跨合约重入

跨合约重入 跨越多个合约,绕过 ReentrancyGuard。这意味着它需要全面的交互分析。

攻击模式: 受 ReentrancyGuard 保护的合约 A 调用合约 B。在合约 A 的外部调用期间,攻击者通过合约 B 未受保护的函数重新进入,操纵共享状态。

示例场景: 带有 ReentrancyGuard 的 Vault 合约使用单独的 Token 合约。攻击者在 Vault 合约的提款过程中通过 Token 合约的 转账(transfer) 函数重新进入。

预防: 在所有交互的合约中实施一致的重入保护,并在合约交互中遵循 CEI 模式。

只读重入

只读重入 在状态转换期间利用 视图函数(view functions)。这使得它在依赖价格 预言机(oracles) 的 DeFi 协议中至关重要。

漏洞机制: 视图函数看起来是安全的,但可以在状态转换期间返回不一致的数据。攻击者利用此窗口来获得不正确的价格计算。

示例场景:

function getCurrentPrice() public view returns (uint256) {
        if (totalTokens == 0) return 10e18;
        return (totalTokens * 10e18) / totalStake;
}

在外部调用期间, totalStake 可能会更新,而 totalTokens 保持不变,从而创造了价格操纵的机会。

预防: 避免在外部调用期间依赖可变状态的视图函数。实施状态一致性检查。

协议特定的漏洞

闪电贷重入

闪电贷重入中,攻击者通过利用不正确的余额验证来操纵 贷款(loan) 执行期间的 代币余额(token balances)。 创建“ 侧门(side entrance) ”攻击,攻击者使用闪电贷暂时抬高余额,绕过检查,然后通过不同的提款机制提取资金。

常见模式: 闪电贷增加 用户(user) 的余额,触发未考虑 临时余额膨胀(temporary balance inflation) 的提款逻辑。

ERC-721 重入

onERC721Received 回调(callback) 启用了 NFT 转移(transfer) 期间的攻击。对于市场和 质押(staking) 合约至关重要,其中 NFT 转移触发状态更改或支付。

攻击向量: 恶意合约可以在 _safeMintsafeTransferFrom 调用期间重新进入,在 NFT 转移完成之前操纵合约状态。

ERC-777 重入

ERC-777 重入 中, 转账Hook(transfer hooks) 打破 CEI 模式,从而实现价格操纵。高级 代币(token) 功能增加了 漏洞面(vulnerability surface)

机制: tokensReceived Hook在转账期间执行,允许攻击者重新进入 发送合约(sending contracts) 并在转账过程中操纵状态。

ERC-1155 重入

代币(token) 回调(onERC1155Received, onERC1155BatchReceived)在 区块链协议(blockchain protocols) 中创建攻击向量。

复杂性因素: 批量(Batch) 操作在单个 交易(transactions) 中创建多个重入机会,需要仔细的状态管理。

结论

每个外部调用都是潜在的重入漏洞。遵循 CEI 模式,了解 ReentrancyGuard 的局限性,并分析所有合约交互。

随着 协议(protocols) 变得越来越复杂,包括跨链 和高级 代币标准(token standards) ,新的攻击模式不断涌现。安全第一的开发至关重要。

现代 DeFi 协议需要超越单个合约范围的全面重入分析。在设计安全系统时,请考虑跨合约交互、 代币Hook(token hooks) 和只读函数依赖项。

我们希望本概述能帮助你编写更安全的代码。上面提到的每个重入攻击在其各自的部分中都有一个深入的文章链接,因此请继续阅读以了解更多信息。

  • 原文链接: ackee.xyz/blog/complete-...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 1
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
Ackee
Ackee
Cybersecurity experts | We audit Ethereum and Solana | Creators of @WakeFramework , Solidity (Wake) & @TridentSolana | Educational partner of Solana Foundation