$JAY重入攻击追踪分析
消息来源:
记录:
SunWeb3Sec/DeFiHackLabs: Reproduce DeFi hacked incidents using Foundry. (github.com)
JAY token合约代码
https://etherscan.io/address/0xf2919d1d80aff2940274014bef534f7791906ff2#code#L1
链上数据分析
首先确定代币token:0xf2919d1d80aff2940274014bef534f7791906ff2
JAY | Address 0xf2919d1d80aff2940274014bef534f7791906ff2 | Etherscan
攻击者token:0xd4fafa1261f6e4f9c8543228a67caf9d02811e4ad3058a2714323964a8db61f6
Exploiter Contract:0xed42Cb11b9D03c807ED1ba9c2eD1d3BA5Bf37340
进行追踪:
0xd4fafa1261f6e4f9c8 | Phalcon Explorer
获利15.32ETH
攻击过程:
更多详细数据可以看:
主要链路:
0xed42cb11b9d03c807ed1ba9c2ed1d3ba5bf37340 ->0x0348d20b74ddc0ac9bfc3626e06d30bb6fac213b->0xed42cb11b9d03c807ed1ba9c2ed1d3ba5bf37340
攻击利润随后通过龙卷风洗出:
漏洞代码分析
合约ABI:(适用于无合约代码交互情况,可以进行无合约代码交互)
1 | [{"inputs":[],"stateMutability":"payable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"time","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"}],"name":"Price","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"ETHtoJAY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"JAYtoETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"erc721TokenAddress","type":"address[]"},{"internalType":"uint256[]","name":"erc721Ids","type":"uint256[]"},{"internalType":"address[]","name":"erc1155TokenAddress","type":"address[]"},{"internalType":"uint256[]","name":"erc1155Ids","type":"uint256[]"},{"internalType":"uint256[]","name":"erc1155Amounts","type":"uint256[]"}],"name":"buyJay","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"buyJayNoNFT","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address[]","name":"erc721TokenAddress","type":"address[]"},{"internalType":"uint256[]","name":"erc721Ids","type":"uint256[]"},{"internalType":"address[]","name":"erc1155TokenAddress","type":"address[]"},{"internalType":"uint256[]","name":"erc1155Ids","type":"uint256[]"},{"internalType":"uint256[]","name":"erc1155Amounts","type":"uint256[]"}],"name":"buyNFTs","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"deposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"getBuyJayNFT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"getBuyJayNoNFT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLatestPrice","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotals","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lockDevWallet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"onERC1155Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"sell","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"startJay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"updateDevWallet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"updateFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}] |
根据合约代码https://remix.ethereum.org/#address=0xf2919d1d80aff2940274014bef534f7791906ff2分析:
1 | function ETHtoJAY(uint256 value) public view returns (uint256) { |
JAY代币的总供应量*JAY代币的价格 = JAY合约的ETH余额
我们来看合约代码中购买逻辑的实现–Sell和buyJay的实现
1 | // Sell Jay |
1 | function buyJay( |
1 | function buyJayWithERC721( |
JAY 合约允许用户为 buyJay 函数传递任意 ERC-721 代币。
导致攻击者可以利用此漏洞重新进入JAY合约
其中根据 进行了闪电贷
可以进行debug调试,其中关键buy-send走了2个来回
0xd4fafa1261f6e4f9c8 | Phalcon Explorer
1 | {"msg.sender":"0xed42cb11b9d03c807ed1ba9c2ed1d3ba5bf37340","func":"flashLoan","args":{"recipient":"0xed42cb11b9d03c807ed1ba9c2ed1d3ba5bf37340","tokens":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"amounts":["72500000000000000000"],"userData":"0x000000000000000000000000000000000000000000000001314fb37062980000000000000000000000000000000000000000000000000002bcd40a70853a000000000000000000000000000000000000000000000000000030927f74c9de00000000000000000000000000000000000000000000000000006f05b59d3b200000"},"return":[]} |
总结:攻击者在单笔交易中重复该过程两次,总利润为 15.32 以太币。攻击利润已通过 Tornado Cash 洗钱。
exp:
1 | // SPDX-License-Identifier: UNLICENSED |