Appearance
S2C10: CREATE2 Double Constraint
1. Problem
It is necessary to deploy a contract whose address must simultaneously satisfy two constraint conditions (such as address prefix matching certain bytes). Use CREATE2 salt grinding to find the right salt.
2. Cause
The contract uses address constraints as access control — only functions called from specific addresses can execute. Through CREATE2's deterministic deployment, the attacker can "choose" the deployment address.
3. Solution
- Analyze the address constraint conditions in the contract (which bytes must match)
- Write the attack contract
- Use salt grinding to find a salt satisfying both constraints
- Deploy the attack contract to the target address
- Call mintFlag from that address
solidity
// Salt grinding in Foundry
function findSalt() external {
bytes32 salt = 0;
while (true) {
address predicted = address(uint160(uint256(
keccak256(abi.encodePacked(bytes1(0xff), deployer, salt, initCodeHash))
)));
if (checkConstraint1(predicted) && checkConstraint2(predicted)) {
break; // Found!
}
salt = bytes32(uint256(salt) + 1);
}
}
4. Pitfalls Encountered
Double constraint grinding time: When two constraint conditions are combined, the search space can be large. Efficient computation methods are required.
5. Pitfall Causes
Each additional byte constraint shrinks the search space by a factor of 256. Two constraints combined mean a 256^2 = 65536 times larger search space (worst case).
6. How to Resolve
Use a Rust script or optimized Foundry test for grinding. For 2-3 byte constraint combinations, it can typically be found within < 10 million iterations.
7. Key Technical Points
| Point | Description |
|---|---|
| CREATE2 address calculation | Last 20 bytes of keccak256(0xff + deployer + salt + keccak256(initCode)) |
| Multi-constraint grinding | Combining multiple address match conditions increases search complexity |
| initCode hash | Same contract code produces the same hash; varying initCode (e.g., constructor parameters) changes the address |