Closed howlbot-integration[bot] closed 1 month ago
In EVM assembly, the and operator evaluates both operands before performing the operation, and there is no guaranteed order of evaluation. Consequently, the check eq(returndatasize(), 0x20) is evaluated before the staticcall or call is executed.
This is incorrect. All binary operators evaluate right to left in yul.
Right to left seems the way to go indeed. A coded PoC would've saved the warden some precious time
3docSec marked the issue as unsatisfactory: Invalid
Lines of code
https://github.com/code-423n4/2024-08-wildcat/blob/fe746cc0fbedc4447a981a50e6ba4c95f98b9fe1/src/market/WildcatMarketBase.sol#L254-L273 https://github.com/code-423n4/2024-08-wildcat/blob/fe746cc0fbedc4447a981a50e6ba4c95f98b9fe1/src/market/WildcatMarketBase.sol#L769-L792
Vulnerability details
The
WildcatMarketBase
contract includes critical functions that rely on low-level assembly code to enforce compliance checks, particularly to prevent sanctioned addresses from interacting with the contract. Two primary functions involved are_isSanctioned()
and_createEscrowForUnderlyingAsset()
. These functions interact with thesentinel
contract to verify if an address is sanctioned and to manage escrow creation for underlying assets._isSanctioned()
FunctionThe
_isSanctioned()
function is intended to determine if a givenaccount
is sanctioned by calling thesentinel.isSanctioned(borrower, account)
function. It uses inline assembly to perform astaticcall
and then checks thereturndatasize()
to ensure that the call returned the expected 32 bytes.The relevant portion of the code is:
_createEscrowForUnderlyingAsset()
FunctionSimilarly, the
_createEscrowForUnderlyingAsset()
function is designed to create an escrow for the underlying asset by callingsentinel.createEscrow(borrower, accountAddress, tokenAddress)
. It also uses inline assembly to perform acall
and checks thereturndatasize()
.The code snippet is:
The flaw lies in the use of the logical
and
operator within theif
statement in both functions. In EVM assembly, theand
operator evaluates both operands before performing the operation, and there is no guaranteed order of evaluation. Consequently, the checkeq(returndatasize(), 0x20)
is evaluated before thestaticcall
orcall
is executed.This incorrect order leads to
returndatasize()
being zero (since no call has been made yet), causing the equality check to fail. As a result, the entireif
condition may evaluate incorrectly, leading to one of two undesired outcomes:False Negatives: The function might incorrectly determine that an address is not sanctioned because it does not properly process the return data from the
sentinel
contract.Unexpected Reverts: The function might revert unexpectedly, even when interacting with non-sanctioned addresses, due to the premature check of
returndatasize()
.Impact
Sanctioned addresses can bypass compliance checks and interact with the contract, violating regulatory requirements and exposing the system to legal and reputational risks. Additionally, legitimate users may experience unexpected transaction failures, disrupting normal contract operations.
Proof of Concept
Scenario Setup:
sentinel
contract is responsible for identifying sanctioned addresses.attacker
, attempts to interact with theWildcatMarketBase
contract.Function Call:
_isSanctioned(attacker)
to check if theattacker
is sanctioned.Execution Flow:
_isSanctioned()
, the assembly code attempts to perform astaticcall
tosentinel.isSanctioned(borrower, attacker)
.eq(returndatasize(), 0x20)
is evaluated before thestaticcall
occurs.returndatasize()
is zero at this point, the equality check fails.and
operation does not short-circuit in EVM assembly; both operands are evaluated regardless.staticcall
might not be executed properly, or its result is not correctly processed.Outcome:
result
to false, indicating that theattacker
is not sanctioned.attacker
proceeds to interact with the contract without being blocked.Alternate Outcome (Legitimate User):
returndatasize()
check, the function may revert unexpectedly.Tools Used
Manual review
Recommended Mitigation Steps
To resolve the issue, restructure the assembly code to ensure that the
staticcall
orcall
is executed before checkingreturndatasize()
. Store the success status of the call in a variable and perform the checks afterward.Assessed type
Other