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

3 stars 0 forks source link

payToTheBootloader function sends an amount of ETH to the BOOTLOADER_FORMAL_ADDRESS without any checks on the validity of the address or the amount #488

Closed c4-submissions closed 11 months ago

c4-submissions commented 1 year ago

Lines of code

https://github.com/code-423n4/2023-10-zksync/blob/1fb4649b612fac7b4ee613df6f6b7d921ddd6b0d/code/system-contracts/contracts/libraries/TransactionHelper.sol#L395

Vulnerability details

Impact

The payToTheBootloader function potentially has a vulnerability as it blindly forwards a specified amount of ETH to the BOOTLOADER_FORMAL_ADDRESS. This can pose a security risk if not properly constrained. If an attacker can control the value of _transaction.maxFeePerGas and _transaction.gasLimit, it may lead to financial vulnerabilities, including potential ETH theft or misuse.

Proof of Concept

The payToTheBootloader function sends an amount of ETH to the BOOTLOADER_FORMAL_ADDRESS without any checks on the validity of the address or the amount. Here's a simplified version of the function:

function payToTheBootloader(Transaction calldata _transaction) internal returns (bool success) {
    address bootloaderAddr = BOOTLOADER_FORMAL_ADDRESS;
    uint256 amount = _transaction.maxFeePerGas * _transaction.gasLimit;

    assembly {
        success := call(gas(), bootloaderAddr, amount, 0, 0, 0, 0)
    }
}

This code does not check if the BOOTLOADER_FORMAL_ADDRESS is a valid address, and it blindly sends the calculated amount.

Tools Used

Manual

Recommended Mitigation Steps

To enhance the security of this function, it's crucial to add checks to ensure that the destination address (BOOTLOADER_FORMAL_ADDRESS) is a valid and expected address. Additionally, it should limit the amount sent based on certain constraints, such as a maximum limit or a pre-defined cap.

function payToTheBootloader(Transaction calldata _transaction) internal returns (bool success) {
    require(BOOTLOADER_FORMAL_ADDRESS != address(0), "Invalid BOOTLOADER_FORMAL_ADDRESS");

    require(_transaction.maxFeePerGas * _transaction.gasLimit <= MAX_PAYMENT_AMOUNT, "Payment amount exceeds the maximum limit");

    address bootloaderAddr = BOOTLOADER_FORMAL_ADDRESS;
    uint256 amount = _transaction.maxFeePerGas * _transaction.gasLimit;

    assembly {
        success := call(gas(), bootloaderAddr, amount, 0, 0, 0, 0);
    }
}

Assessed type

ETH-Transfer

c4-pre-sort commented 11 months ago

141345 marked the issue as low quality report

miladpiri commented 11 months ago

Invalid - bootloader address is always hardcoded to the same address 0x8001.

c4-sponsor commented 11 months ago

miladpiri (sponsor) disputed

c4-judge commented 11 months ago

GalloDaSballo marked the issue as unsatisfactory: Invalid