claimRedemption allows a redeemer to claim the collateral from the verified redemption candidates after the dispute period has passed. It takes the following parameter:
asset: The market that will be impacted.
As can be seen, the function performs the following key steps:
Retrieves the redeemer's asset user and vault user structs.
Checks if the redeemer has a valid redemption proposal and if the dispute period has elapsed.
Reads the redemption proposal data using SSTORE2.
Iterates through the redemption proposal data and calls the _claimRemainingCollateral function for each verified redemption candidate.
Updates the redeemer's vault user struct with the total redeemed collateral.
Deletes the redeemer's asset user struct's SSTORE2 pointer.
Had it been there are proper reentrancy guards in the claimRedemption function. Although the function is marked with the nonReentrant modifier, it still calls an external function (_claimRemainingCollateral) before updating the redeemer's vault user struct and deleting the asset user struct's SSTORE2 pointer.
If the _claimRemainingCollateral function or any other function called within the loop is malicious or can be controlled by an attacker, it could potentially exploit the reentrancy vulnerability by recursively calling the claimRedemption function before the state is fully updated.
By recursively calling the claimRedemption function within the _claimRemainingCollateral function or any other function called in the loop. This can lead to unexpected behavior and potential manipulation of the redemption outcomes.
For example, an attacker can create a malicious contract that implements a fallback function or a specific function that is called by _claimRemainingCollateral. Inside this function, the attacker can recursively call claimRedemption with the same or different parameters, leading to multiple redemptions before the state is fully updated.
Impact
By exploiting the reentrancy vulnerability, attackers can potentially claim more collateral than intended or disrupt the redemption process for other users.
Tools Used
Vs
Recommended Mitigation Steps
a. Apply the checks-effects-interactions pattern:
Perform all necessary checks and validations first.
Update the state variables and perform internal actions.
Interact with external contracts or functions last.
b. Use a reentrancy guard modifier:
Implement a reentrancy guard modifier that prevents recursive calls to the function.
Apply the modifier to the claimRedemption function.
bool private locked;
modifier noReentrant() {
require(!locked, "Reentrancy detected");
locked = true;
_;
locked = false;
}
function claimRedemption(address asset) external isNotFrozen(asset) noReentrant {
uint256 vault = s.asset[asset].vault;
STypes.AssetUser storage redeemerAssetUser = s.assetUser[asset][msg.sender];
STypes.VaultUser storage redeemerVaultUser = s.vaultUser[vault][msg.sender];
if (redeemerAssetUser.SSTORE2Pointer == address(0)) revert Errors.InvalidRedemption();
if (LibOrders.getOffsetTime() < redeemerAssetUser.timeToDispute) revert Errors.TimeToDisputeHasNotElapsed();
MTypes.ProposalData[] memory decodedProposalData =
LibBytes.readProposalData(redeemerAssetUser.SSTORE2Pointer, redeemerAssetUser.slateLength);
uint88 totalColRedeemed;
for (uint256 i = 0; i < decodedProposalData.length; i++) {
MTypes.ProposalData memory currentProposal = decodedProposalData[i];
totalColRedeemed += currentProposal.colRedeemed;
}
// Update state variables first
redeemerVaultUser.ethEscrowed += totalColRedeemed;
delete redeemerAssetUser.SSTORE2Pointer;
// Interact with external contracts last
for (uint256 i = 0; i < decodedProposalData.length; i++) {
MTypes.ProposalData memory currentProposal = decodedProposalData[i];
_claimRemainingCollateral({
asset: asset,
vault: vault,
shorter: currentProposal.shorter,
shortId: currentProposal.shortId
});
}
emit Events.ClaimRedemption(asset, msg.sender);
}
In this modified version:
The noReentrant modifier is added to prevent recursive calls to the function.
The state variables (redeemerVaultUser.ethEscrowed and redeemerAssetUser.SSTORE2Pointer) are updated before interacting with external contracts.
The _claimRemainingCollateral function is called after updating the state variables.
Lines of code
https://github.com/code-423n4/2024-03-dittoeth/blob/91faf46078bb6fe8ce9f55bcb717e5d2d302d22e/contracts/facets/RedemptionFacet.sol#L310-L334 https://github.com/code-423n4/2024-03-dittoeth/blob/91faf46078bb6fe8ce9f55bcb717e5d2d302d22e/contracts/facets/RedemptionFacet.sol#L324-L329
Vulnerability details
Summary & Impact
claimRedemption
allows a redeemer to claim the collateral from the verified redemption candidates after the dispute period has passed. It takes the following parameter:asset
: The market that will be impacted.As can be seen, the function performs the following key steps:
_claimRemainingCollateral
function for each verified redemption candidate.RedemptionFacet.sol::claimRedemption
RedemptionFacet.sol::L324-L329
By recursively calling the
claimRedemption
function within the_claimRemainingCollateral
function or any other function called in the loop. This can lead to unexpected behavior and potential manipulation of the redemption outcomes.For example, an attacker can create a malicious contract that implements a fallback function or a specific function that is called by
_claimRemainingCollateral
. Inside this function, the attacker can recursively callclaimRedemption
with the same or different parameters, leading to multiple redemptions before the state is fully updated.Impact
By exploiting the reentrancy vulnerability, attackers can potentially claim more collateral than intended or disrupt the redemption process for other users.
Tools Used
Vs
Recommended Mitigation Steps
a. Apply the checks-effects-interactions pattern:
b. Use a reentrancy guard modifier:
claimRedemption
function.In this modified version:
noReentrant
modifier is added to prevent recursive calls to the function.redeemerVaultUser.ethEscrowed
andredeemerAssetUser.SSTORE2Pointer
) are updated before interacting with external contracts._claimRemainingCollateral
function is called after updating the state variables.Assessed type
Reentrancy