✅Greyhats Dollar
Codebase walkthrough
The code implements a customized ERC20-like token, but it is more like ERC4626: it computes share for each user, just like a vault. Player can claim 1000e18 grey token for free from Setup.sol.
transfer()
is a wrapper of transferFrom()
, and transferFrom()
looks like the longest function at first glance, so it is natural to focus on it.
Bug description
First thing I would check is the classic “transfer token to yourself” bug:
Say from == to == you
uint256 fromShares = shares[from] - _shares
→uint256 fromShares = shares[you] - _shares
uint256 toShares = shares[to] + _shares
→uint256 toShares = shares[you] + _shares
shares[from] = fromShares
→shares[you] = fromShares
shares[to] = toShares
→shares[you] = toShares
In the last step, you see that shares[you]
is being overwritten by a larger number, equivalently it means you get money for free.
Next question is how much money you can get for free by calling transfer()
once. It is easy: to make sure that uint256 fromShares = shares[you] - _shares
does not revert, you must have shares[you] - _shares >= 0
⇒ shares[you] >= _shares
⇒ _shares <= shares[you]
. Therefore the best choice is to transfer balanceOf(player)
in each call to transfer()
, and repeat many times. Since balanceOf(player)
doubles for each iteration, this attack will finish quickly.
Recall that player can claim 1000e18 grey token for free from Setup.sol, so this attack works.
PoC
Claim 1000e18 grey token from Setup.sol, call transfer()
in a for loop or while loop.
Last updated