zkSync Era System Contracts contest - Jeiwan's results

Rely on math, not validators.

General Information

Platform: Code4rena

Start Date: 10/03/2023

Pot Size: $180,500 USDC

Total HM: 6

Participants: 19

Period: 9 days

Judge: GalloDaSballo

Total Solo HM: 2

Id: 221

League: ETH

zkSync

Findings Distribution

Researcher Performance

Rank: 4/19

Findings: 1

Award: $8,774.78

🌟 Selected for report: 1

πŸš€ Solo Findings: 0

Findings Information

🌟 Selected for report: Jeiwan

Also found by: ronnyx2017

Labels

bug
2 (Med Risk)
primary issue
selected for report
sponsor confirmed
M-02

Awards

8774.7813 USDC - $8,774.78

External Links

Lines of code

https://github.com/code-423n4/2023-03-zksync/blob/21d9a364a4a75adfa6f1e038232d8c0f39858a64/contracts/libraries/EfficientCall.sol#L141-L144

Vulnerability details

Impact

User transaction can call system contracts directly, which shouldn't be allowed to not invoke potentially dangerous operations.

Proof of Concept

The DefaultAccount.executeTransaction executes a user transaction after it was validated. The function calls _execute under the hood. The _execute function makes two different calls depending on the destination address of a transaction:

  1. if the ContractDeployer is called, it'll pass the call to the contract via the system call (ContractDeployer is a system contract and can be executed only via system calls);
  2. if any other contract is called, it'll execute the call via EfficientCall.rawCall.

EfficientCall.rawCall in its turn also makes two different calls:

  1. If msg.value of the transaction is 0, it'll make a regular call.
  2. If there's some ETH sent with the transaction (i.e. msg.value is positive), it'll pass the call to the MsgValueSimulator contract. MsgValueSimulator is a system contract, thus the isSystem flag will be set in the far call ABI (notice the true in the last argument of _loadFarCallABIIntoActivePtr). However, it'll also set the forward mask to 1 (the value of MSG_VALUE_SIMULATOR_IS_SYSTEM_BIT). MsgValueSimulator will extract the mask and will set the isSystemCall flag to true–it'll then pass the isSystemCall flag to the subsequent call, making the call a system one.

To sum it up, if a transaction calls a contract that's not ContractDeployer and sends ETH, the call will be a system one, which will let it call the system contracts. However, users shouldn't be allowed to call system contracts directly to not invoke potentially dangerous operations. As per the documentation:

Some of the system contracts can act on behalf of the user or have a very important impact on the behavior of the account. That's why we wanted to make it clear that users can not invoke potentially dangerous operations by doing a simple EVM-like call. Whenever a user wants to invoke some of the operations which we considered dangerous, they must explicitly provide isSystem flag with them.

However, since most system contracts are harmless, there's no direct high severity impact on the system, thus I think the issue is a medium severity.

Tools Used

Manual review

In the EfficientCall.rawCall function, consider setting the forward mask to 0. The behaviour of the function is similar to that of the msgValueSimulatorMimicCall function from the bootloader:

  1. since the MsgValueSimulator contract is called, the isSystemCall flag should be set only for this call;
  2. the isSystemCall flag should be forwarded by MsgValueSimulator only if the destination contract is ContractDeployer.

It looks that the second part of the EfficientCall.rawCall function was copied from the SystemContractsCaller.systemCall function, which is intended to call system contracts and which sets the forward mask to 1 when calling MsgValueSimulator. However, rawCall shouldn't forward the isSystemCall flag.

#0 - c4-judge

2023-03-23T13:48:20Z

GalloDaSballo marked the issue as primary issue

#1 - GalloDaSballo

2023-03-23T13:48:23Z

More detailed, making primary

#2 - miladpiri

2023-03-27T11:13:00Z

It is an issue, though realisticially most of the methods are non-payable.

#3 - c4-sponsor

2023-03-27T11:13:06Z

miladpiri marked the issue as sponsor confirmed

#4 - GalloDaSballo

2023-04-05T12:07:24Z

The Warden has shown a way to bypass the security checks that would prevent a end user to be able to call system contracts.

In lack of a loss of deposits, I agree with Medium Severity

#5 - c4-judge

2023-04-05T12:07:30Z

GalloDaSballo marked the issue as selected for report

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax Β© 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter