Closed code423n4 closed 2 years ago
Not possible as sending a message to Mainnet requires a BLS threshold signature of at least 2/3 * 16 randomly selected nodes that support the SKALE Chain conducting the transfer. See https://github.com/skalenetwork/ima-c4-audit/blob/11d6a6ae5bf16af552edd75183791375e501915f/contracts/mainnet/MessageProxyForMainnet.sol#L224-L231
Have to agree with the sponsor, this would require 2/3 of signers to collude to arbitrage the gas cost at the risk of being slashed with the added risk of needing the colluders to be selected as signers
Lines of code
https://github.com/skalenetwork/ima-c4-audit/blob/11d6a6ae5bf16af552edd75183791375e501915f/contracts/mainnet/MessageProxyForMainnet.sol#L246-L252
Vulnerability details
The contest code does a good job of preventing users from withdrawing too quickly or attempting to do things without funds for gas. The nodes themselves however are not as well-secured.
Impact
By monitoring the values of
headerMessageGasCost
andmessageGasCost
and comparing them to the actual gas cost, a malicious node can choose the most opportune time to execute an attack that drains each of the chains it is in charge of's chain wallets. By sending messages where the refund is larger than the input costs, the node is able to take money from the chain wallets. The node can layer on plausible deniability by not just doing the attack for transactions it is in charge of, but by also doing it for the other nodes that are also in charge of each chain at different time slots.Proof of Concept
The node can create a lot of separate users on multiple chains then withdraw all but the last bit of money in each user's chain's community pool. When the gas conditions are right the node can create a lot of small withdrawals in large batch transactions that take out the last bits of money for each user on each chain. Since each user doesn't have much in its account, the refund is taken from each schain wallet.
The small withdrawal will lock the user's account which will trigger the
Messages.encodeLockUserMessage
to be sent...https://github.com/skalenetwork/ima-c4-audit/blob/11d6a6ae5bf16af552edd75183791375e501915f/contracts/mainnet/CommunityPool.sol#L169-L186
...which will be reimbursed from the schain wallet
https://github.com/skalenetwork/ima-c4-audit/blob/11d6a6ae5bf16af552edd75183791375e501915f/contracts/mainnet/MessageProxyForMainnet.sol#L246-L252
There may be other ways to trigger larger messages that require a larger refund, but this example is proof of concept enough. Most of the documentation talks about slashing validator nodes if they do something visible like double-spend. This however is a case where cheating is not identifiable by on-chain metrics if the node is determined to remain anonymous while it's attacking. The system requirements for being a validator are also not very onerous so it's relatively easy for an attacker to become a validator (once this project is more widely used and needs to onboard more validators).
Tools Used
Code inspection
Recommended Mitigation Steps
Rate-limit schain wallet refunds on both a per-chain and a global level, and have a dust limit under which funds cannot be withdrawn.