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: 49/84
Findings: 2
Award: $32.91
🌟 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
https://github.com/code-423n4/2024-02-althea-liquid-infrastructure/blob/bd6ee47162368e1999a0a5b8b17b701347cf9a7d/liquid-infrastructure/contracts/LiquidInfrastructureERC20.sol#L127-L146 https://github.com/code-423n4/2024-02-althea-liquid-infrastructure/blob/bd6ee47162368e1999a0a5b8b17b701347cf9a7d/liquid-infrastructure/contracts/LiquidInfrastructureERC20.sol#L142-L145
holder
can burn ERC20 tokens which leads DOS attack.
holder
can burn ERC20 tokens via burnAndDistribute
. This triggers the _beforeTokenTransfer
hook, which increases the length of holder
array by adding 0 addresses to the array.
Attacker can burn tokens in small amounts such as 1 wei a time to accumulate and increase the array length to a very large number, which in turn will make gas very costly to execute all major functions of the contract LiquidInfrastructureERC20
such as mint
, burn
and distribute
.
Here is the foundry test file
Here is the test with main logic of the exploit:
Codefunction testHigh() public { // Owner approves attacker and mints and transfers 1 ether to attacker vm.startPrank(owner); liquidERC20.approveHolder(attacker); liquidERC20.mint(attacker, 1 ether); // holders array length is 1 assertEq(liquidERC20.holderLength(), 1); vm.stopPrank(); // attacker burns 1 wei at a time to increase the length of the holders array vm.startPrank(attacker); liquidERC20.burnAndDistribute(1); // holders array length is 2 assertEq(liquidERC20.holderLength(), 2); for (uint i = 0; i < 1000; i++) { liquidERC20.burnAndDistribute(1); } console.log("Holders Array Length: ", liquidERC20.holderLength()); vm.stopPrank(); }
Foundry
Add these lines in _beforeTokenTransfer
function of LiquidInfrastructureERC20
contract.
function _beforeTokenTransfer( address from, address to, uint256 amount ) internal virtual override { require(!LockedForDistribution, "distribution in progress"); 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) { ++ if (!exists && to != address(0)) { holders.push(to); } }
DoS
#0 - c4-pre-sort
2024-02-20T03:22:43Z
0xRobocop marked the issue as duplicate of #727
#1 - c4-pre-sort
2024-02-20T06:34:11Z
0xRobocop marked the issue as duplicate of #77
#2 - c4-judge
2024-03-03T13:30:48Z
0xA5DF marked the issue as satisfactory
#3 - c4-judge
2024-03-04T13:06:40Z
0xA5DF removed the grade
#4 - c4-judge
2024-03-04T13:06:43Z
0xA5DF marked the issue as satisfactory
🌟 Selected for report: nuthan2x
Also found by: 0x0bserver, AM, CaeraDenoir, DanielArmstrong, JrNet, Kirkeelee, KmanOfficial, Krace, Limbooo, Meera, SovaSlava, SpicyMeatball, TheSavageTeddy, agadzhalov, aslanbek, atoko, csanuragjain, d3e4, imare, jesjupyter, juancito, kartik_giri_47538, kutugu, max10afternoon, offside0011, pkqs90, turvy_fuzz, xchen1130, zhaojohnson, ziyou-
25.7286 USDC - $25.73
Owner
can make changes in distributableERC20s
while distribution is running.
Only transfers, mints, and burns functions are locked while distribution is running. Which gives Owner
opportunity to make changes such that -
Owner
can replace high value ERC20 tokens with lower value to be distributed among holders
.Owner
can rearrange distributableERC20s
such that lower erc20EntitlementPerUnit
value corresponds to higher distributableERC20s
valued ERC20 tokens. This will result in uneven distribution of tokens with everyone getting lower valued tokens.There is no Access Control in setDistributableERC20s
function to prevent owner from changing the distributableERC20s
while distribution is running.
Owner
only needs to set distributableERC20s using setDistributableERC20s
function to his desired list to target any and every holder in ditribution phase.
Foundry
Add these lines in disapproveHolder
function of LiquidInfrastructureERC20
contract.
function setDistributableERC20s( address[] memory _distributableERC20s ) public onlyOwner { ++ require(!LockedForDistribution, "cannot make changes in distributableERC20s during distribution"); distributableERC20s = _distributableERC20s; }
Access Control
#0 - c4-pre-sort
2024-02-20T06:11:01Z
0xRobocop marked the issue as duplicate of #260
#1 - c4-judge
2024-03-04T15:30:39Z
0xA5DF marked the issue as satisfactory
#2 - c4-judge
2024-03-08T15:26:18Z
0xA5DF changed the severity to 2 (Med Risk)