UTU 2022 年 12 月 29 日 5 时(北京时间 13 时),以太坊主网上的 JayPeggers 协议遭到重入攻击,损失约 15 ETH。随后攻击者通过 Tornado.Cash 和 Aztec 转移被盗资金。
- 攻击者地址:https://etherscan.io/address/0x0348d20b74ddc0ac9bfc3626e06d30bb6fac213b
- 发起攻击的合约:https://etherscan.io/address/0xed42cb11b9d03c807ed1ba9c2ed1d3ba5bf37340
- 发起攻击的交易:https://etherscan.io/tx/0xd4fafa1261f6e4f9c8543228a67caf9d02811e4ad3058a2714323964a8db61f6
- 被攻击合约:https://etherscan.io/address/0xf2919D1D80Aff2940274014bef534f7791906FF2
- 调试交易:https://dashboard.tenderly.co/tx/mainnet/0xd4fafa1261f6e4f9c8543228a67caf9d02811e4ad3058a2714323964a8db61f6
分析
首先,攻击合约从 Vault(0xba12222222228d8ba445958a75a0704d566bf2c8) 获得借出 72.5 WETH 的代币余额,然后从 0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2 利用 withdraw
函数取出。至此,攻击者通过闪电贷获得了起始资金。
接着调用了 buyJay
,关键在于计算铸币数量的 ETHtoJAY
函数,它是用 代币总量/ETH 总量,计算代币价格的。这次只是通过 22 WETH 购买了 13584899853779845952188 Jay 代币。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
function buyJay( address[] calldata erc721TokenAddress, uint256[] calldata erc721Ids, address[] calldata erc1155TokenAddress, uint256[] calldata erc1155Ids, uint256[] calldata erc1155Amounts ) public payable { require(start, "Not started!"); uint256 total = erc721TokenAddress.length; if (total != 0) buyJayWithERC721(erc721TokenAddress, erc721Ids); if (erc1155TokenAddress.length != 0) total = total.add( buyJayWithERC1155( erc1155TokenAddress, erc1155Ids, erc1155Amounts ) ); if (total >= 100) require( msg.value >= (total).mul(sellNftFeeEth).div(2), "You need to pay ETH more" ); else require( msg.value >= (total).mul(sellNftFeeEth), "You need to pay ETH more" ); _mint(msg.sender, ETHtoJAY(msg.value).mul(97).div(100)); (bool success, ) = dev.call{value: msg.value.div(34)}(""); require(success, "ETH Transfer failed."); nftsSold += total; emit Price(block.timestamp, JAYtoETH(1 * 10**18)); } |
1 2 3 |
function ETHtoJAY(uint256 value) public view returns (uint256) { return value.mul(totalSupply()).div(address(this).balance.sub(value)); } |
攻击者第二次调用 ETHtoJAY
函数,这次用 50.5 ETH 铸造了 4313025058290613910965927 Jay 代币。
1 2 3 4 5 6 7 8 9 10 11 |
{ "erc721TokenAddress": [ "0xed42cb11b9d03c807ed1ba9c2ed1d3ba5bf37340" ], "erc721Ids": [ "0" ], "erc1155TokenAddress": [], "erc1155Ids": [], "erc1155Amounts": [] } |
可以知道,售卖的 NFT 是一个攻击者自定义的 ERC721 合约,实际上没有任何价值,只是用来通过第 10 行的 buyJayWithERC721
重入的。
在 sell
函数中,计算 eth 的逻辑如下:
1 2 3 |
function JAYtoETH(uint256 value) public view returns (uint256) { return (value * address(this).balance).div(totalSupply()); } |
这时 address(this).balance
已经因为传入了 50.5 WETH 而增大了,但是buyJay
中的 _mint
函数中的 _totalSupply
还没变化,因此造成了价格操控。
原文始发于learner L:JayPeggers 攻击分析
相关文章
暂无评论...