Platform: Code4rena
Start Date: 13/02/2024
Pot Size: $24,500 USDC
Total HM: 5
Participants: 84
Period: 6 days
Judge: 0xA5DF
Id: 331
League: ETH
Rank: 84/84
Findings: 1
Award: $7.18
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: BowTiedOriole
Also found by: 0x0bserver, 0xAadi, 0xJoyBoy03, 0xlamide, 0xlemon, 0xpiken, Babylen, Breeje, Brenzee, CodeWasp, DanielArmstrong, DarkTower, Fassi_Security, Fitro, Honour, JohnSmith, Krace, MrPotatoMagic, Myrault, ReadyPlayer2, SovaSlava, SpicyMeatball, TheSavageTeddy, Tigerfrake, atoko, cryptphi, csanuragjain, d3e4, gesha17, kinda_very_good, krikolkk, matejdb, max10afternoon, miaowu, n0kto, nuthan2x, parlayan_yildizlar_takimi, peanuts, petro_1912, pontifex, psb01, pynschon, rouhsamad, shaflow2, slippopz, spark, turvy_fuzz, web3pwn, zhaojohnson
7.1828 USDC - $7.18
An approved holder with zero balance can be added several times to holders, so it can receive rewards several times during a revenue distribution, so by exploiting it, can drain all distributableERC20s from LiquidInfrastructureERC20
.
_beforeTokenTransfer
function doesn't check the amount being received at all, so any account can send 0 tokens to approved holder
(which has zero balance), then it can be added in holders
though it has zero balance.
_afterTokenTransfer
function doesn't check the amount and updated balance of to
account too, so it exists in holders
.
Attack Scenario A, B = approved holder, C = any account
// in A = Approved Holder IERC20(liquidInfrastructureERC20).transfer(B, IERC20(liquidInfrastructureERC20).balanceOf(A));
holders
array. This process can be repeated as many as possible.// in EOA (B or C = it doesn't need to be approved holder ) for (uint256 i = 0; i < 1000; i++) { IERC20(liquidInfrastructureERC20).transfer(A, 0); }
then holders
can have many A items. but at the moment balance of A is zero, so can not receive a revenue.
// holders = [..., A, A, A, A]
// in B IERC20(liquidInfrastructureERC20).transfer(A, amount);
Manual review
Holder with zero balance should not be added to holders
and duplication should not be allowed in holders
.
function _beforeTokenTransfer( address from, address to, uint256 amount ) internal virtual override { require(!LockedForDistribution, "distribution in progress"); + require(amount != 0, "zero amount"); if (!(to == address(0))) { require( isApprovedHolder(to), "receiver not approved to hold the token" ); } if (from == address(0) || to == address(0)) { _beforeMintOrBurn(); } bool exists = (this.balanceOf(to) != 0); if (!exists) { + bool isInHolder = false; + for (uint i = 0; i < holders.length; i++) { + if (holders[i] == to) { + isInHolder = true; + break; + } + } + if (!isInHolder) + holders.push(to); - holders.push(to); } }
Invalid Validation
#0 - c4-pre-sort
2024-02-20T06:28:34Z
0xRobocop marked the issue as duplicate of #536
#1 - c4-pre-sort
2024-02-20T06:33:33Z
0xRobocop marked the issue as duplicate of #77
#2 - c4-judge
2024-03-04T13:04:37Z
0xA5DF marked the issue as satisfactory