11 - Backdoor

Make sure you take enough time to understand each contract!

// Deploy Gnosis Safe master copy and factory contracts
this.masterCopy = await (await ethers.getContractFactory('GnosisSafe', deployer)).deploy();
this.walletFactory = await (await ethers.getContractFactory('GnosisSafeProxyFactory', deployer)).deploy();
this.token = await (await ethers.getContractFactory('DamnValuableToken', deployer)).deploy();

We first deploy 3 contracts: GnosisSafe, GnosisSafeProxyFactory, DamnValuableToken.

// Deploy the registry
this.walletRegistry = await (
  await ethers.getContractFactory('WalletRegistry', deployer)
).deploy(this.masterCopy.address, this.walletFactory.address, this.token.address, users);

Then we deploy WalletRegistry contract which is provided from this challenge.

Let's see what's the success condition.

/** SUCCESS CONDITIONS */
for (let i = 0; i < users.length; i++) {
  let wallet = await this.walletRegistry.wallets(users[i]);

  // User must have registered a wallet
  expect(wallet).to.not.eq(ethers.constants.AddressZero, 'User did not register a wallet');

  // User is no longer registered as a beneficiary
  expect(await this.walletRegistry.beneficiaries(users[i])).to.be.false;
}

// Attacker must have taken all tokens
expect(await this.token.balanceOf(attacker.address)).to.eq(AMOUNT_TOKENS_DISTRIBUTED);

1) User must have a registered wallet

2) User should no longer be registered as a beneficiary

3) Attacker must take all 40 DVTs.

Solution

We will exploit the contract in the following order:

  1. Attacker contract calls createProxyWithCallback in GnosisSafeProxyFactory

  2. createProxyWithCallback will call createProxyWithNonce

  3. createProxyWithNonce calls deployProxyWithNonce

  4. createProxyWithNonce sends initializer to newly create proxy -> here, initializer will trigger setup function

  5. createProxyWithCallback calls callback(proxyCreated) -> 10 DVTs will be transfered from WalletRegistry to each user's proxy contract

This is the setup function that is triggered by initializer sent from createProxyWithNonce (at 4.)

Here, setupModules delegatecalls to the address to.

So we will pass in our malicious contract address to setupModules function.

Last updated