|
| 1 | +import { Common, Hardfork, Mainnet, createCommonFromGethGenesis } from '@ethereumjs/common' |
| 2 | +import { eip4844GethGenesis } from '@ethereumjs/testdata' |
| 3 | +import { |
| 4 | + Account, |
| 5 | + Address, |
| 6 | + MAX_UINT64, |
| 7 | + bytesToBigInt, |
| 8 | + bytesToHex, |
| 9 | + bytesToUnprefixedHex, |
| 10 | + concatBytes, |
| 11 | + createAddressFromPrivateKey, |
| 12 | + createAddressFromString, |
| 13 | + createZeroAddress, |
| 14 | + hexToBytes, |
| 15 | + intToBytes, |
| 16 | + padToEven, |
| 17 | + setLengthLeft, |
| 18 | + setLengthRight, |
| 19 | + unpadBytes, |
| 20 | +} from '@ethereumjs/util' |
| 21 | +import { keccak256 } from 'ethereum-cryptography/keccak.js' |
| 22 | +import { assert, describe, it } from 'vitest' |
| 23 | + |
| 24 | +import { EVMError } from '../src/errors.ts' |
| 25 | +import { defaultBlock } from '../src/evm.ts' |
| 26 | +import { createEVM } from '../src/index.ts' |
| 27 | + |
| 28 | +import type { EVMRunCallOpts } from '../src/types.ts' |
| 29 | + |
| 30 | +// Non-protected Create2Address generator. Does not check if Uint8Arrays have the right padding. |
| 31 | +function create2address(sourceAddress: Address, codeHash: Uint8Array, salt: Uint8Array): Address { |
| 32 | + const rlp_proc_bytes = hexToBytes('0xff') |
| 33 | + const hashBytes = concatBytes(rlp_proc_bytes, sourceAddress.bytes, salt, codeHash) |
| 34 | + return new Address(keccak256(hashBytes).slice(12)) |
| 35 | +} |
| 36 | + |
| 37 | +describe('RunCall tests', () => { |
| 38 | + it('Create where FROM account nonce is 0', async () => { |
| 39 | + const common = new Common({ chain: Mainnet, hardfork: Hardfork.Prague }) |
| 40 | + const evm = await createEVM({ common }) |
| 41 | + |
| 42 | + const deployMentSizeHex = `62${bytesToUnprefixedHex(setLengthLeft(hexToBytes('0x6000'), 3))}` |
| 43 | + const deployContractCode = hexToBytes(`0x305F52${deployMentSizeHex}5FF3`) |
| 44 | + |
| 45 | + const depSize = deployContractCode.length |
| 46 | + const pushCodeSize = bytesToUnprefixedHex(new Uint8Array([0x60, depSize])) |
| 47 | + |
| 48 | + const deploymentCodeMSTORE = `7F${bytesToUnprefixedHex(setLengthRight(deployContractCode, 32))}5F52` |
| 49 | + |
| 50 | + // calldataload [0] is salt |
| 51 | + const code = hexToBytes( |
| 52 | + `0x00${deploymentCodeMSTORE}${'5F355B'}${'60010180'}${pushCodeSize}5F5F${'F5602557'}`, |
| 53 | + ) |
| 54 | + |
| 55 | + const res = await evm.runCall({ to: undefined, gasLimit: BigInt(30_000_000), data: code }) |
| 56 | + |
| 57 | + const addr = res.createdAddress!.bytes |
| 58 | + const deploymentHash = keccak256(deployContractCode) |
| 59 | + |
| 60 | + // CREATE2 layout for the hasher |
| 61 | + // [0-0] 0xff |
| 62 | + // [1-21] address [20bytes] |
| 63 | + // [22-54] salt [32 bytes] |
| 64 | + // [55-85] codeHash [32 bytes] |
| 65 | + |
| 66 | + const attackCode = `0x7FFF${bytesToUnprefixedHex(setLengthRight(addr, 31))}5F527F${bytesToUnprefixedHex(deploymentHash)}6037525F5B6001018060165260555F203B5060480056` |
| 67 | + |
| 68 | + const ctrAddress = createAddressFromString('0x' + '20'.repeat(20)) |
| 69 | + await evm.stateManager.putCode(ctrAddress, hexToBytes(<any>attackCode)) |
| 70 | + |
| 71 | + evm.events.on('step', (e) => { |
| 72 | + console.log(e.opcode.name, e.stack) |
| 73 | + }) |
| 74 | + |
| 75 | + const res2 = await evm.runCall({ to: ctrAddress, gasLimit: BigInt(30_000_000), data: code }) |
| 76 | + console.log(res2) |
| 77 | + }, 10000000) |
| 78 | +}) |
0 commit comments