zkSync Era - gumgumzum's results

Future-proof zkEVM on the mission to scale freedom for all.

General Information

Platform: Code4rena

Start Date: 02/10/2023

Pot Size: $1,100,000 USDC

Total HM: 28

Participants: 64

Period: 21 days

Judge: GalloDaSballo

Total Solo HM: 13

Id: 292

League: ETH

zkSync

Findings Distribution

Researcher Performance

Rank: 43/64

Findings: 1

Award: $656.33

🌟 Selected for report: 0

šŸš€ Solo Findings: 0

Findings Information

Labels

bug
2 (Med Risk)
satisfactory
edited-by-warden
duplicate-888

Awards

656.3255 USDC - $656.33

External Links

Lines of code

https://github.com/code-423n4/2023-10-zksync/blob/main/code/system-contracts/contracts/Constants.sol#L30-L35 https://github.com/code-423n4/2023-10-zksync/blob/main/code/system-contracts/contracts/AccountCodeStorage.sol#L86-L139

Vulnerability details

Impact

New EcAdd and EcMul precompiles were added but CURRENT_MAX_PRECOMPILE_ADDRESS was not updated.

This will cause AccountCodeStorage@getCodeHash to not return EMPTY_STRING_KECCAK and AccountCodeStorage@getCodeSize to not return 0 leading to EVM invariants not being preserved.

Proof of Concept

The test below was ran on a modified era-test-node that includes EcAdd and EcMul. It also includes a test for extcodesize and extcodehash since both are translated (based on this) to AccountCodeStorage@getCodeSize and AccountCodeStorage@getCodeHash calls respectively.

Test

import { expect } from 'chai';
import { AccountCodeStorage__factory, CodeHelper } from '../typechain-types';
import { ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT, EMPTY_STRING_KECCAK } from './shared/constants';
import { Wallet } from 'zksync-web3';
import { deployContract, getWallets } from './shared/utils';

const ECADD = "0x0000000000000000000000000000000000000006";
const ECMUL = "0x0000000000000000000000000000000000000007";

describe('Precompiles', function () {
    let wallet: Wallet;

    before(async () => {
        wallet = getWallets()[0];
    });

    describe('Account Code Storage', function () {
        describe('getCodeSize', function () {
            it('should return 0 for EcAdd', async () => {
                expect(
                    (await AccountCodeStorage__factory.connect(ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT, wallet)
                        .getCodeSize(ECADD)).eq(0)
                ).to.be.true;
            });
    
            it('should return 0 for EcMul', async () => {
                expect(
                    (await AccountCodeStorage__factory.connect(ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT, wallet)
                        .getCodeSize(ECMUL)).eq(0)
                ).to.be.true;
            });
        });
    
        describe('getCodeHash', function () {
            it('should return the empty string keccak hash for EcAdd', async () => {
                expect(
                    (await AccountCodeStorage__factory.connect(ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT, wallet)
                        .getCodeHash(ECADD))
                ).to.be.eq(EMPTY_STRING_KECCAK);
            });
    
            it('should return the empty string keccak hash for EcMul', async () => {
                expect(
                    (await AccountCodeStorage__factory.connect(ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT, wallet)
                        .getCodeHash(ECMUL))
                ).to.be.eq(EMPTY_STRING_KECCAK);
            });
        });
    });

    describe('Code Helper', function () {
        let codeHelper: CodeHelper;

        before(async () => {
            codeHelper = await deployContract('CodeHelper') as CodeHelper;
        });

        describe('getCodeSize', function () {
            it('should return 0 for EcAdd', async () => {
                expect(
                    (await codeHelper
                        .getCodeSize(ECADD)).eq(0)
                ).to.be.true;
            });
    
            it('should return 0 for EcMul', async () => {
                expect(
                    (await codeHelper
                        .getCodeSize(ECMUL)).eq(0)
                ).to.be.true;
            });
        });
    
        describe('getCodeHash', function () {
            it('should return the empty string keccak hash for EcAdd', async () => {
                expect(
                    (await codeHelper
                        .getCodeHash(ECADD))
                ).to.be.eq(EMPTY_STRING_KECCAK);
            });
    
            it('should return the empty string keccak hash for EcMul', async () => {
                expect(
                    (await codeHelper
                        .getCodeHash(ECMUL))
                ).to.be.eq(EMPTY_STRING_KECCAK);
            });
        });
    });
});
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract CodeHelper {
    function getCodeSize(address of_) external view returns (uint256 s) {
        assembly {
            s := extcodesize(of_)
        }
    }

    function getCodeHash(address of_) external view returns (bytes32 h) {
        assembly {
            h := extcodehash(of_)
        }
    }
}

Results

Precompiles Account Code Storage getCodeSize 1) should return 0 for EcAdd 2) should return 0 for EcMul getCodeHash 3) should return the empty string keccak hash for EcAdd 4) should return the empty string keccak hash for EcMul Code Helper getCodeSize 5) should return 0 for EcAdd 6) should return 0 for EcMul getCodeHash 7) should return the empty string keccak hash for EcAdd 8) should return the empty string keccak hash for EcMul 0 passing (300ms) 8 failing 1) Precompiles Account Code Storage getCodeSize should return 0 for EcAdd: AssertionError: expected false to be true + expected - actual -false +true 2) Precompiles Account Code Storage getCodeSize should return 0 for EcMul: AssertionError: expected false to be true + expected - actual -false +true 3) Precompiles Account Code Storage getCodeHash should return the empty string keccak hash for EcAdd: AssertionError: expected '0x010000c56c054a0de4a36b133d3c114ec51…' to equal '0xc5d2460186f7233c927e7db2dcc703c0e50…' + expected - actual -0x010000c56c054a0de4a36b133d3c114ec514c3ce0334ad7759c202392386a913 +0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 4) Precompiles Account Code Storage getCodeHash should return the empty string keccak hash for EcMul: AssertionError: expected '0x010001378d31273c8e58caa12bcf1a5694e…' to equal '0xc5d2460186f7233c927e7db2dcc703c0e50…' + expected - actual -0x010001378d31273c8e58caa12bcf1a5694e66a0aefdba2504adb8e3eb02b21c7 +0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 5) Precompiles Code Helper getCodeSize should return 0 for EcAdd: AssertionError: expected false to be true + expected - actual -false +true 6) Precompiles Code Helper getCodeSize should return 0 for EcMul: AssertionError: expected false to be true + expected - actual -false +true 7) Precompiles Code Helper getCodeHash should return the empty string keccak hash for EcAdd: AssertionError: expected '0x010000c56c054a0de4a36b133d3c114ec51…' to equal '0xc5d2460186f7233c927e7db2dcc703c0e50…' + expected - actual -0x010000c56c054a0de4a36b133d3c114ec514c3ce0334ad7759c202392386a913 +0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 8) Precompiles Code Helper getCodeHash should return the empty string keccak hash for EcMul: AssertionError: expected '0x010001378d31273c8e58caa12bcf1a5694e…' to equal '0xc5d2460186f7233c927e7db2dcc703c0e50…' + expected - actual -0x010001378d31273c8e58caa12bcf1a5694e66a0aefdba2504adb8e3eb02b21c7 +0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470

Tools Used

Manual Review

Update CURRENT_MAX_PRECOMPILE_ADDRESS to uint256(uint160(ECMUL_SYSTEM_CONTRACT)) but this will also change the behavior for RIPEMD-160, identity and modexp addresses so the check for precompiles might need to be changed to account for gaps.

Assessed type

Other

#0 - c4-pre-sort

2023-10-31T06:51:19Z

bytes032 marked the issue as duplicate of #142

#1 - c4-judge

2023-11-23T19:31:09Z

GalloDaSballo marked the issue as satisfactory

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