使用 Echidna 对链上合约进行模糊测试

Echidna 2.1.0 版本引入了直接检索链上数据的新功能,如合约代码和存储槽值。文章展示了如何使用 Echidna 复现 2022 年 Stax Finance 被攻击事件,该事件是由于 StaxLPStaking 合约中缺少验证检查,导致价值 230 万美元的 xLP 代币被盗。

随着 Echidna 2.1.0 版本的发布,我们以太坊智能合约的 Fuzzing 工具,我们引入了直接检索链上数据的新功能,例如合约代码和存储槽值。这些数据可用于 Fuzzing 已部署合约的链上状态,或测试新代码如何与现有合约集成。

Echidna 现在有能力通过 Fuzzing 合约接口和链上代码来重现真实世界的攻击。在这篇博文中,我们将演示如何仅使用 Echidna 重现 2022 年的 Stax Finance 攻击来发现并利用漏洞。该事件涉及 StaxLPStaking 合约中缺少验证检查,导致 321,154 个 xLP 代币被盗,当时价值约为 230 万美元。

Echidna 的“优化模式”将自动发现最大化或最小化自定义函数结果的交易序列。在这种情况下,我们将简单地要求它最大化攻击者的余额,然后让它完成其余的工作。

重现 Stax Finance 漏洞

要使用 Echidna 重现 Stax Finance 漏洞,我们需要:

  • 一个由 Echidna 进行 Fuzzing 的合约,该合约包装了目标 Stax 合约和相关合约(图 1)
  • 一个 Echidna 配置文件,其中包含攻击发生之前的区块号和一个 RPC 提供程序来获取链上信息(图 2)

图 1 显示了 Fuzzing 合约的简化版本,图 2 显示了配置文件。你可以在此处找到完整的合约和配置文件。

contract StaxExploit {

    IStaxLP StaxLP = IStaxLP(0xBcB8b7FC9197fEDa75C101fA69d3211b5a30dCD9);
    IStaxLPStaking StaxLPStaking =
        IStaxLPStaking(0xd2869042E12a3506100af1D192b5b04D65137941);

    ...

    constructor() {
        // Using HEVM to set the block.number and block.timestamp
        // 使用 HEVM 设置 block.number 和 block.timestamp
        hevm.warp(1665493703);
        hevm.roll(15725066);

        // setting up initial balances
        // 设置初始余额
        ...
    }

    function getBalance() internal returns (uint256) {
        return StaxLP.balanceOf(address(this));
    }

    function stake(uint256 _amount) public {
        _amount = (_amount % getBalance()) + 1;
        StaxLPStaking.stake(_amount);
    }

    // Other functions wrappers ...
    // 其他函数包装器...

    function migrateStake(
        address oldStaking,
        uint256 amount
    ) public {
        StaxLPStaking.migrateStake(oldStaking, amount);
    }

    function migrateWithdraw(
        address staker,
        uint256 amount
    ) public {
        StaxLPStaking.migrateWithdraw(staker, amount);
    }

    fallback() external payable {}

    // The optimization function
    // 优化函数
    function echidna_optimize_extracted_profit() public returns (int256) {
        return (int256(StaxLP.balanceOf(address(this))) -
            int256(initialAmount));
    }
}

图 1:攻击者合约

在 Fuzzing 合约中,我们添加了一个名为 echidna_optimize_extracted_profit() 的函数,允许 Echidna 监视当前交易序列的利润,并识别利润最高的交易序列。

testMode: optimization
testLimit: 1000000
corpusDir: corpus-stax
rpcUrl: https://.../
rpcBlock: 15725066

图 2:Echidna 配置文件

如配置文件所示,我们将 Echidna 设置为在优化模式下运行,以最大化利润函数。

接下来,我们使用图 3 中的命令在 Fuzzing 合约上运行 Echidna。

$ echidna ./StaxExploit.sol --contract StaxExploit --config echidna-config.yaml

图 3:用于执行 Echidna 的命令

Echidna 的优化器生成具有不同参数的函数调用的随机序列,计算每个序列的 echidna_optimize_extracted_profit() 函数的返回值。在运行结束时,它会丢弃交易序列中任何不必要的或恢复的调用,只留下那些最大化利润的调用。

因此,通过我们的 Fuzzing 合约和利润函数,Echidna 可以迅速发现正确的交易序列来重现攻击,而无需事先了解实际的合约漏洞。

图 4:使用本文代码运行 Echidna 的结果

详细细节

现在我们已经对 Echidna 如何重现漏洞进行了高级概述,让我们深入了解一些技术细节,以供有兴趣自己尝试的读者参考。

为了设置 Fuzzing 合约,我们使用了 Slither 的代码生成实用程序。这使我们能够从 Etherscan 获取目标合约的接口和部署地址,以及其他必要的接口和地址(例如,ERC-20 代币、其他合约和用户定义的数据类型)。我们还创建了包装器,供 Echidna 调用合约函数,并添加了我们的 echidna_optimize_extracted_profit() 函数。

我们利用了 Echidna 使用 hevm 欺骗码来操纵执行环境的能力。这涉及将区块号和区块时间戳设置为实际攻击发生之前的某个时间点。为了简化 hevm 欺骗码 的使用,我们使用了 properties 仓库 中的 helper,并导入了 HEVM.sol helper

在设置配置文件时,我们将 testMode 配置为 optimization。我们还为 Echidna 分配了 RPC 提供程序和区块号(分别由 rpcUrlrpcBlock 参数指示)以获取链上信息。为了防止 Echidna 在未找到漏洞的情况下无限期运行,我们通过 testLimit 参数设置了 100 万次测试运行的上限。生成的语料库存储在 corpus-stax 目录中,如 corpusDir 参数中指定的那样。

局限性和挑战

虽然 Echidna 是一个强大的工具,但它并非没有局限性和挑战:

  1. Echidna 可能无法找到所有漏洞。由于 Fuzz 测试无法保证完全覆盖,因此至关重要的是,要使用其他安全测试方法(如静态分析、形式验证,甚至单元测试(例如,100% 分支覆盖率、边缘情况测试、正向和负向测试等))来增强 Echidna,以进行全面分析。
  2. 复杂的合约可能需要更多时间。根据智能合约的复杂性,Echidna 可能需要更长的时间才能发现漏洞。
  3. 从网络获取合约和插槽可能很慢。API 速率限制可能会阻碍为使用大量存储插槽的合约获取链上信息的过程。目前正在讨论如何缓解此问题。
  4. 可能需要自定义。在某些情况下,你可能需要定制 Echidna 的配置或测试工具,以适应你的特定用例。

为了克服这些挑战,请遵循最佳实践,例如将 Echidna 与其他安全测试工具结合使用,彻底了解智能合约的功能,并在必要时咨询安全专家。

Echidna 提高了合约的安全性

Echidna 中新功能的引入,例如链上合约检索、数据获取和多核 Fuzzing,为在现实场景中提高代码的安全性开辟了新途径。通过将 Fuzz 测试添加到你的项目中,可以通过覆盖单元测试或集成测试可能忽略的边缘情况来提高代码的安全性。

有关使用 Echidna 的更多指导,包括详细的文档和实际示例,请访问我们的 “构建安全合约”网站。如果你喜欢视觉学习,请查看我们在 YouTube 上提供的 Echidna 直播。

立即下载 Echidna,开始探索其所有功能。请访问 我们的官方仓库 获取最新版本和安装说明。我们鼓励你重现此漏洞,以熟悉新的链上 Fuzzing 功能,并深入了解它如何帮助你使合约更安全。

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

0 条评论

请先 登录 后评论
Trail of Bits
Trail of Bits
https://www.trailofbits.com/