28943 - [SC - Medium] DoS when user want to supply repay asset using...
Submitted on Mar 2nd 2024 at 14:40:11 UTC by @savi0ur for Boost | ZeroLend
Report ID: #28943
Report type: Smart Contract
Report severity: Medium
Target: https://pacific-explorer.manta.network/address/0x2f9bB73a8e98793e26Cb2F6C4ad037BDf1C6B269
Impacts:
Griefing (e.g. no profit motive for an attacker, but damage to the users or the protocol)
Description
Bug Description
The Underlying ERC20 token of the Pool contract incorporates the EIP-2612 permit, allowing users to off-chain sign permits for gas-less transfers. However, the open Zeppelin's design choice introduces a frontrunning risk, where any entity can execute the permit() function before the original transaction, causing potential issues, especially when used within other functions.
The supplyWithPermit() function, while introducing a permit-first approach, creates vulnerability to frontrunning, resulting in a brief Denial of Service (DOS) situation.
function supplyWithPermit(
address asset,
uint256 amount,
address onBehalfOf,
uint16 referralCode,
uint256 deadline,
uint8 permitV,
bytes32 permitR,
bytes32 permitS
) public virtual override {
IERC20WithPermit(asset).permit(
msg.sender,
address(this),
amount,
deadline,
permitV,
permitR,
permitS
);
SupplyLogic.executeSupply(
_reserves,
_reservesList,
_usersConfig[onBehalfOf],
DataTypes.ExecuteSupplyParams({
asset: asset,
amount: amount,
onBehalfOf: onBehalfOf,
referralCode: referralCode
})
);
}Attack Scenario
Alice sign the tx off-chain and submit it to perform
supplyWithPermitWhile the Alice tx is in mempool, Bob
(Attacker)can see it, frontrun it, and executepermitdirectly on the underlying token with all the message and signature details of Alice.Alice's tx now executes after Bob's tx and it will get reverted as the signature is already used.
Impact
Any function call that unconditionally performs permit() can be forced to revert this way. In case there is a fallback code path (using direct user approval), the DOS is short-term, as eventually the user / dApp would switch to using an alternative. Otherwise, the DOS is long-term.
I'm marking this issue as Medium according to Immunefi's vulnerability classification system : Griefing (e.g. no profit motive for an attacker, but damage to the users or the protocol).
Griefing (e.g. no profit motive for an attacker, but damage to the users or the protocol): Griefing is when the attacker calls certain functions of the smart contract that would put it in a suboptimal state, thus blocking normal function execution for any user. This would cause the user to lose money for sending the transaction, but when the smart contract is back to normal, the user would be able to call the function once again to complete it. In this instance, the attacker damaged the user by requiring them to send another transaction. The attacker does not profit, but they do damage the users or the protocol.
NOTE: There is one more function - repayWithPermit() which is vulnerable to same attack.
Risk Breakdown
Difficulty to Exploit: Easy
Recommendation
It is recommended to use below trustlessPermit() in all the places where permit() is used within other functions.
References
Proxy - https://pacific-explorer.manta.network/address/0x2f9bB73a8e98793e26Cb2F6C4ad037BDf1C6B269
Implementation - https://pacific-explorer.manta.network/address/0x8676e39B5D2f0d6E0d78a4208a0cCBc50504972e
Proxy - https://explorer.zksync.io/address/0x4d9429246EA989C9CeE203B43F6d1C7D83e3B8F8#contract
Implementation - https://explorer.zksync.io/address/0x54d6f91be4509826559ad12e1ca6ca3a6c3811e0#contract
Proof Of Concept
Steps to Run using Foundry:
Install Foundry (https://book.getfoundry.sh/getting-started/installation)
Open terminal and run
forge init pocandcd pocPaste following foundry code in
PoC.t.solRun using
forge test -vv
Console Output:
Last updated
Was this helpful?