Open hats-bug-reporter[bot] opened 1 year ago
Thanks for the report. This is a great catch.
I changed the accounting so that the reward contract is stored per aToken rather than underlying, trancheId combo. See: https://github.com/VMEX-finance/vmex/pull/170/commits/9cb38421aeb501723f19d57296255773d16cf535
This way, the access control will not be a problem
Github username: @bahurum Submission hash (on-chain): 0xa2e6ee3d3cf681e9d27a8968aecea25a6ccaae3ce0addf0856ad88ecc9cff19f Severity: high severity
Description:
Description
In
IncentivesController.handleAction()
it is not checked properly thatmsg.sender
is indeed a validaToken
. This allows anyone to impersonate anaToken
and steal rewards from theIncentivesController
.Attack scenario:
The attacker will deploy a contract like this:
The attacker then:
Calls
aTokenImpersonator.steal()
aTokenImpersonator
callsIncentivesController.handleAction()
In handleAction(),
_updateIncentivizedAsset()
will execute doing nothing:The attacker just needs to send
totalSupply >= oldBalance
to make theassert
pass, and then_incentivizedAssets[asset]
is an empty struct sinceasset
is the address of the attacker contract itself, soincentivizedAsset.numRewards
is zero and the for loop will be skipped.Then
stakingExists(msg.sender)
will returntrue
for the impersonated aToken:underlying
andtrancheId
will be the ones corresponding to the impersonated aToken, sostakingData[underlying][trancheId]
will be non empty.Then
onWithdraw()
will withdraw the rewards corresponding to theunderlying
andtrancheId
, and send them to the attacker contract.The attacker calls
aTokenImpersonator.send()
to get the stolen rewards out of theaTokenImpersonator
contract.Recommendation
Check that the caller of
IncentivesController.handleAction()
is indeed an existingaToken
. This could be done inExternalRewardsDistributor.stakingExists()
for example: