Skip to content

Release 2.1.1

Compare
Choose a tag to compare
@marcocastignoli marcocastignoli released this 19 Apr 16:23
· 1539 commits to staging since this release
ddb3cbb

What's Changed

Removed verification through simulation because of the potential vulnerability to "hijack" a contract verification by embedding the deployed bytecode inside the constructor in assembly.

Thanks to @Hellobloc and @samczsun for reporting the following vulnerabilities.

Fixed vulnerability

Summary

Given a partial or unverified contract, it is possible to "fully verify" any contract by just returning the deployed (onchain) bytecode of the contract inside the constructor in assembly. The verified source file would then not contain the original source file but just a few lines of code with the raw deployed bytecode.

Example

  1. Given a partial match on Sourcify (you can use Import from Etherscan for 0x345a7c9325E7145CA7E8aafabf474361E6c674D5 on Goerli)
  2. Download this repo: https://github.com/Hellobloc/verify
  3. Edit the file final2.sol as follows
pragma solidity ^0.5.10;
contract Deployer {
    constructor() public {
        bytes memory bytecode = hex'6080604052348015600f57600080fd5b506004361060285760003560e01c8063d1524f7414602d575b600080fd5b60336075565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff168156fea265627a7a72315820b59b9ccfbe01c3596a27c9bf3fc5728c39c25d61c263777e6e6a96dbb69a677a64736f6c63430005110032';
        assembly {
            return (add(bytecode, 0x20), mload(bytecode))
        }
    }
}
  1. Generate the keccak256 of that file and update the keccak256 field of final2.sol in the metadata.json
  2. Use Sourcify's API to verify the contract

Explanation

The function verifyDeployed tries to verify the contract with different methods, in order:

  1. matchWithDeployedBytecode: compare the deployed runtime bytecode with the recompiled runtime bytecode
  2. matchWithSimulation: execute the recompiled creation bytecode on an EVM (hence "simulation"), which will produce a runtime bytecode and compare it with the deployed one
  3. matchWithCreationTx

When using Sourcify's API to verify the ´Hellobloc/verify´ contract:

  • matchWithDeployedBytecode fails because recompiled runtime bytecode and the onchain runtime bytecode differ:

recompiled runtime bytecode:

0x6080604052600080fdfea265627a7a72315820ff612b856b9428c30f2fecfa6f13c7a7ee8d459a3c22f6c8a900e7a0459aba5f64736f6c63430005110032

onchain runtime bytecode:

0x6080604052348015600f57600080fd5b506004361060285760003560e01c8063d1524f7414602d575b600080fd5b60336075565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff168156fea265627a7a72315820b59b9ccfbe01c3596a27c9bf3fc5728c39c25d61c263777e6e6a96dbb69a677a64736f6c63430005110032
  • matchWithSimulation succeed because it actually produces the same runtime bytecode as the deployed runtime bytecode

Solution

We've considered several solutions:

  1. If during matchWithDeployedBytecode we find that the length of the “trimmed” part of runtime bytecode differs then we are probably sure that the contract is neither a partial or a perfect match.
    • We don’t solve the issue because a malicious code could force the length to be the same.
  2. Checking the equivalence of the metadata hash after a perfect match.
  • This case makes use of this fact: the malicious file that generated a "perfect bytecode" needs a fake metadata (recall we modified the keccak256 above). Till now we assumed that if the compiler generated a "perfect runtime bytecode" then it was also true that the provided metadata was the correct one, but that's not the case. In this case, because assembly code is utilized, the "simulation" returns a "perfect runtime bytecode" but in fact the metadata hash of the metadata JSON, output from the recompilation is different than what's in the onchain CBOR encoded part.
  • However this method is not resolved for partial matches.
  1. **Remove matchWithSimulation**
    The vulnerability comes from this functionality. We were already considering removing this verification as with the recent addition of immutableRefences to verification, we wouldn't need alternative verifications for contracts with immutables.

We decided to comment out matchWithSimulation type verification and eventually remove it from the codebase.

Full Changelog: v2.1.0...v2.1.1