code-423n4 / 2023-10-zksync-findings

4 stars 0 forks source link

EIP-1559 transactions allow kernel space addresses as from address #381

Closed c4-submissions closed 1 year ago

c4-submissions commented 1 year ago

Lines of code

https://github.com/code-423n4/2023-10-zksync/blob/main/code/system-contracts/bootloader/bootloader.yul#L2903-L2905

Vulnerability details

Impact

The bootloader will be used in production with the proved_batch configuration. In this configuration, some checks are added during the compile time of Yul to ensure that no transaction uses a from address in the kernel space of the EraVM (address less than 2^16).

But, the EIP-1559 type transactions are able to set kernel space addresses as from address because of a misconfiguration. All others transaction types are well-configured.

Because of the misconfiguration, the checks that from > 2^16 will not be included during compilation of the Yul.

Proof of Concept

Affected code:

The bootloader supports different types of transaction. For each transaction, checks are done in the validateTypedTxStructure function based on the transaction type. For all transaction types, except type = 2 (EIP-1559), the following check is done:

                        <!-- @if BOOTLOADER_TYPE=='proved_batch' -->
                        assertEq(gt(getFrom(innerTxDataOffset), MAX_SYSTEM_CONTRACT_ADDR()), 1, "from in kernel space")
                        <!-- @endif -->

But, the check is different for the EIP-1559 transactions.

                        <!-- @if BOOTLOADER_TYPE=='proved_block' -->
                        assertEq(gt(getFrom(innerTxDataOffset), MAX_SYSTEM_CONTRACT_ADDR()), 1, "from in kernel space")
                        <!-- @endif -->

The bootloader process script show that the proved_block configuration doesn't exist. After investigation, it appears that this configuration doesn't exist anymore, proved_block has been replaced by proved_batch. Due to this misconfiguration, EIP-1559 transactions are lacking this check in the production bootloader code (stored in proved_batch.yul file after process.ts execution).

Possible exploitation

The inner working of the bootloader will call the from account's code to verify the signature. Here, the signature verification could be bypassed as the bootloader consider the Tx as valid if the verification call returns any magic that is 32-byte long (see the ensureCorrectAccountMagic from bootloader code). If a kernel space address is passed as the from value of the Tx, getting a 32-byte long returndata size when calling the verify function can be done (for example, by calling MsgValueSimulator which has a fallback function).

In practice, it appears that this vulnerability could be exploitable by the operator responsible of loading the bootloader memory. Due to a lack of time, the plausibility of an attack from an external attacker hasn't been studied enough to state this vulnerability as HIGH. But this lack of check could have some critical impacts on zkSync Era.

A working exploit could lead to DoS and theft of funds, by manipulating the L2EthToken system contract for example.

Tools Used

Static analysis, IDE

Recommended Mitigation Steps

Replace the <!-- @if BOOTLOADER_TYPE=='proved_block' --> line with <!-- @if BOOTLOADER_TYPE=='proved_batch' --> in the bootloader code to deny the kernel space address as from value of transactions.

Assessed type

Access Control

c4-pre-sort commented 1 year ago

bytes032 marked the issue as duplicate of #224

c4-pre-sort commented 1 year ago

bytes032 marked the issue as duplicate of #898

c4-pre-sort commented 1 year ago

bytes032 marked the issue as sufficient quality report

c4-judge commented 11 months ago

GalloDaSballo changed the severity to QA (Quality Assurance)