Skip to content
On this page

S1C3: Empty Contract?

1. Problem

The contract appears "empty" on etherscan (no verified source code), but it actually contains logic. The goal is to call mintFlag() to obtain the NFT.

2. Root Cause

The contract's mintFlag() function is actually called automatically in the constructor. The core insight is: the contract completes its objective at deployment time, so the attacker needs to deploy an identical contract (and attack within the constructor).

3. Solution

Deploy an attack contract that, in its constructor, sets up the state required by the target contract and then calls the target contract's attack function:

solidity
contract S1C3Solution {
    constructor(address challenge) {
        // Setup logic here
        IChallenge(challenge).mintFlag();
    }
}

4. Pitfalls Encountered

Constructor attack timing: The check logic in mintFlag behaves differently when executed during construction vs. after deployment.

5. Why the Pitfall Exists

The contract's storage state differs during and after constructor execution — certain state variables (such as block.timestamp) are predictable during construction.

6. How to Resolve

Use a Foundry script to deploy the attack contract, executing all logic within the constructor.

7. Key Takeaways

PointExplanation
Constructor attackA Solidity contract's constructor executes automatically at deployment time and can be used for a one-shot attack
Deployed vs. constructorA contract can pass certain checks during construction that would fail after deployment (e.g., relying on EXTCODESIZE being zero)

Built with AiAda