You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository has been archived by the owner on Jan 7, 2024. It is now read-only.
sherlock-admin opened this issue
Jul 3, 2023
· 0 comments
Labels
DuplicateA valid issue that is a duplicate of an issue with `Has Duplicates` labelHighA valid High severity issueRewardA payout will be made for this issue
Malicious PartyA/PartyB can prevent themselves from being liquidated
Summary
Since the protocol is deployed on multiple chains, the tx on some chains is easy to be front-run. When liquidating PartyA, LibMuon.verifyPartyAUpnl(upnlSig, partyA) will be called to verify the parameter upnlSig from off-chain. This function internally uses the current partyANonces[partyA] to calculate the hash to verify the upnlSig. When this upnlSig is generated from off-chain, the partyANonces[partyA] used is obtained via [nonceOfPartyA](https://github.com/sherlock-audit/2023-06-symmetrical/blob/main/symmio-core/contracts/facets/ViewFacet.sol#L127-L129) at that time. In most cases, partyANonces[partyA] at these two moments are equal. However, a malicious PartyA can monitor the mempool and front-run LiquidationFacet.liquidatePartyA to make current partyANonces[partyA] different from the partyANonces[partyA] used when generating upnlSig, causing verifyPartyAUpnl to fail to verify upnlSig. In this way, the liquidatePartyA tx will revert. PartyB can also use a similar method to avoid being liquidated.
Vulnerability Detail
When a liquidator notices that PartyA can be liquidated, he will initiate liquidation against PartyA via LiquidationFacet.liquidatePartyA. The flow of this function is as follows:
Let's look at the code snippet of LibMuon.verifyPartyAUpnl:
File: symmio-core\contracts\libraries\LibMuon.sol
093: bytes32 hash =keccak256(
094: abi.encodePacked(
095: muonLayout.muonAppId,
096: upnlSig.reqId,
097: address(this),
098: partyA,
099:-> AccountStorage.layout().partyANonces[partyA],//this value can be changed.100: upnlSig.upnl,
101: upnlSig.timestamp,
102: getChainId()
103: )
104: );
105:->verifyTSSAndGateway(hash, upnlSig.sigs, upnlSig.gatewaySignature); //revert inside it due to wrong hash
Suppose the following scenario:
bob is PartyA, accountLayout.balances[bob]=1e18, accountLayout.allocatedBalances[bob]=1000018.
bob creates a quote via PartyAFacet.sendQuote.
As PartyB, alice locks the quote and opens the position.
As time goes by, bob can be liquidated.
As the liquidator, tom initiates liquidation against bob via LiquidationFacet.liquidatePartyA. This tx enters the mempool. Suppose partyANonces[bob] used when generating upnlSig is 10.
Bob's robot monitors this tx, and immediately initiates AccountFacet.allocate(1) to front-run it. At this time, partyANonces[bob] is increased by 1, equal to 11.
LiquidationFacet.liquidatePartyA will revert due to failure to verify upnlSig.
Why does AccountFacet.allocate(1) increase partyANonces[bob] by 1? Let's look at the code of this function:
As mentioned above, a malicious PartyA can always prevent itself from being liquidated in this way. Until the price of the symbol moves towards a profitable direction, PartyA finally makes a profit.
Similarly, a malicious PartyB can do the same. The flow of LiquidationFacet.liquidatePartyB is as follows:
As mentioned above, malicious PartyA or PartyB can make profits in the following situations:
When the price moves in profitable direction, he can close the position to realize a profit.
When the price moves in the direction of loss, they can prevent liquidation until the price moves in the opposite direction. ultimately achieve profitability.
Sign up for freeto subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Labels
DuplicateA valid issue that is a duplicate of an issue with `Has Duplicates` labelHighA valid High severity issueRewardA payout will be made for this issue
nobody2018
high
Malicious PartyA/PartyB can prevent themselves from being liquidated
Summary
Since the protocol is deployed on multiple chains, the tx on some chains is easy to be front-run. When liquidating PartyA,
LibMuon.verifyPartyAUpnl(upnlSig, partyA)
will be called to verify the parameterupnlSig
from off-chain. This function internally uses the currentpartyANonces[partyA]
to calculate the hash to verify theupnlSig
. When thisupnlSig
is generated from off-chain, thepartyANonces[partyA]
used is obtained via [nonceOfPartyA](https://github.com/sherlock-audit/2023-06-symmetrical/blob/main/symmio-core/contracts/facets/ViewFacet.sol#L127-L129) at that time. In most cases,partyANonces[partyA]
at these two moments are equal. However, a malicious PartyA can monitor the mempool and front-runLiquidationFacet.liquidatePartyA
to make currentpartyANonces[partyA]
different from thepartyANonces[partyA]
used when generatingupnlSig
, causingverifyPartyAUpnl
to fail to verifyupnlSig
. In this way, theliquidatePartyA
tx will revert. PartyB can also use a similar method to avoid being liquidated.Vulnerability Detail
When a liquidator notices that PartyA can be liquidated, he will initiate liquidation against PartyA via
LiquidationFacet.liquidatePartyA
. The flow of this function is as follows:Let's look at the code snippet of
LibMuon.verifyPartyAUpnl
:Suppose the following scenario:
bob is PartyA,
accountLayout.balances[bob]=1e18
,accountLayout.allocatedBalances[bob]=1000018
.PartyAFacet.sendQuote
.LiquidationFacet.liquidatePartyA
. This tx enters the mempool. SupposepartyANonces[bob]
used when generatingupnlSig
is 10.AccountFacet.allocate(1)
to front-run it. At this time,partyANonces[bob]
is increased by 1, equal to 11.LiquidationFacet.liquidatePartyA
will revert due to failure to verifyupnlSig
.Why does
AccountFacet.allocate(1)
increasepartyANonces[bob]
by 1? Let's look at the code of this function:As mentioned above, a malicious PartyA can always prevent itself from being liquidated in this way. Until the price of the symbol moves towards a profitable direction, PartyA finally makes a profit.
Similarly, a malicious PartyB can do the same. The flow of
LiquidationFacet.liquidatePartyB
is as follows:A similar explanation for PartyB will no longer be made here. The relevant functions are as follows:
[LiquidationFacetImpl.liquidatePartyB](https://github.com/sherlock-audit/2023-06-symmetrical/blob/main/symmio-core/contracts/facets/liquidation/LiquidationFacetImpl.sol#L249)
[LibMuon.verifyPartyBUpnl](https://github.com/sherlock-audit/2023-06-symmetrical/blob/main/symmio-core/contracts/libraries/LibMuon.sol#L152)
[AccountFacetImpl.allocateForPartyB](https://github.com/sherlock-audit/2023-06-symmetrical/blob/main/symmio-core/contracts/facets/Account/AccountFacetImpl.sol#L128) and [AccountFacetImpl.transferAllocation](https://github.com/sherlock-audit/2023-06-symmetrical/blob/main/symmio-core/contracts/facets/Account/AccountFacetImpl.sol#L101-L105)
Impact
As mentioned above, malicious PartyA or PartyB can make profits in the following situations:
Code Snippet
https://github.com/sherlock-audit/2023-06-symmetrical/blob/main/symmio-core/contracts/facets/liquidation/LiquidationFacetImpl.sol#L23
https://github.com/sherlock-audit/2023-06-symmetrical/blob/main/symmio-core/contracts/libraries/LibMuon.sol#L99
https://github.com/sherlock-audit/2023-06-symmetrical/blob/main/symmio-core/contracts/facets/Account/AccountFacetImpl.sol#L49
https://github.com/sherlock-audit/2023-06-symmetrical/blob/main/symmio-core/contracts/facets/liquidation/LiquidationFacetImpl.sol#L249
https://github.com/sherlock-audit/2023-06-symmetrical/blob/main/symmio-core/contracts/libraries/LibMuon.sol#L152
https://github.com/sherlock-audit/2023-06-symmetrical/blob/main/symmio-core/contracts/facets/Account/AccountFacetImpl.sol#L128
Tool used
Manual Review
Recommendation
This issue does not appear to be easy to fix. A simple and effective suggestion is to set a minimum allocation amount to increase the attack cost.
Duplicate of #233
The text was updated successfully, but these errors were encountered: