Create2指令(学习自pikachu大佬博客)

智能合约生成合约地址的第二种方式 Create2

  • Create : keccak256(rlp.encode(deployingAddress, nonce))[12:]
  • Create2 : keccak256(0xff ++ deployingAddr ++ salt ++ keccak256(bytecode))[12:]

https://learnblockchain.cn/docs/eips/eip-1014.html#%E8%A7%84%E8%8C%83

上面的链接详细介绍了Create2指令

这里有一道题目。

pragma solidity ^0.4.21;

interface IName {
    function name() external view returns (bytes32);
}

contract FuzzyIdentityChallenge {
    bool public isComplete;

    function authenticate() public {
        require(isSmarx(msg.sender));
        require(isBadCode(msg.sender));

        isComplete = true;
    }

    function isSmarx(address addr) internal view returns (bool) {
        return IName(addr).name() == bytes32("smarx");
    }

    function isBadCode(address _addr) internal pure returns (bool) {
        bytes20 addr = bytes20(_addr);
        bytes20 id = hex"000000000000000000000000000000000badc0de";
        bytes20 mask = hex"000000000000000000000000000000000fffffff";

        for (uint256 i = 0; i < 34; i++) {
            if (addr & mask == id) {
                return true;
            }
            mask <<= 4;
            id <<= 4;
        }

        return false;
    }
}

这里遇到了一个不太熟悉的关键字。

Interface

接口需要有interface关键字,并且内部只需要有函数的声明,不用实现。

只要某合约中有和词接口相同的函数声明,就可以被此合约所接受。

contract cat{

    string name;
    function eat() public returns(string){
        return "cat eat fish";

    }

    function sleep() public returns(string){
         return "sleep";
    }

}


contract dog{

    string name;
    function eat() public returns(string){
        return "dog miss you";

    }

    function swim() public returns(string){
         return "sleep";
    }

}

interface animalEat{
      function eat() public returns(string);
}

contract animal{
    function test(address _addr) returns(string){
        animalEat   generalEat =  animalEat(_addr);
        return generalEat.eat();
    }

}

这里的animap 合约中,有这个定义好的接口。

在合约animal中,调用函数test,如果传递的是部署的cat的合约地址,那么我们在调用接口的eat方法时,实则调用了cat合约的eat方法。 同理,如果传递的是部署的dog的合约地址,那么我们在调用接口的eat方法时,实则调用了dog合约的eat方法。是比较神奇的一点。


重回例题,那么这题剩下的地方就比较简单理解了。题目要求调用name返回一个 'smarx'这个很好实现,在攻击合约部署一个就可以了。

剩下的他要求了给出一个地址。里面包含badc0de即可。

比较简单。

pragma solidity ^0.5.12;
contract BadCodeSmarx is IName {
    function callAuthenticate(address _challenge) public {
       FuzzyIdentityChallenge(_challenge).authenticate(); 
    }
    function name() external view returns (bytes32) {
       return bytes32("smarx");
    }
}

利用上述代码就可以轻松解决了。

那么需要的就是找到这个合约地址了,

将上面合约的bytecode拿出来用于部署,

开启另一个合约。

contract Deployer {
    // contractBytecode是待部署合约的bytecode
    bytes contractBytecode = hex"608060405234801561001057600080fd5b5061015d806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c806306fdde031461003b5780637872ab4914610059575b600080fd5b61004361009d565b6040518082815260200191505060405180910390f35b61009b6004803603602081101561006f57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506100c5565b005b60007f736d617278000000000000000000000000000000000000000000000000000000905090565b8073ffffffffffffffffffffffffffffffffffffffff1663380c7a676040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561010d57600080fd5b505af1158015610121573d6000803e3d6000fd5b505050505056fea265627a7a72315820fb2fc7a07f0eebf799c680bb1526641d2d905c19393adf340a04e48c9b527de964736f6c634300050c0032";
 
    function deploy(bytes32 salt) public {
        bytes memory bytecode = contractBytecode;
        address addr;
      
        assembly {
          addr := create2(0, add(bytecode, 0x20), mload(bytecode), salt)
        }
    }
}

利用指令码中的create2指令生成一个满足条件的addr。

contract Deployer {
    // contractBytecode是待部署合约的bytecode
    bytes contractBytecode = hex"608060405234801561001057600080fd5b5061015d806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c806306fdde031461003b5780637872ab4914610059575b600080fd5b61004361009d565b6040518082815260200191505060405180910390f35b61009b6004803603602081101561006f57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506100c5565b005b60007f736d617278000000000000000000000000000000000000000000000000000000905090565b8073ffffffffffffffffffffffffffffffffffffffff1663380c7a676040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561010d57600080fd5b505af1158015610121573d6000803e3d6000fd5b505050505056fea265627a7a72315820fb2fc7a07f0eebf799c680bb1526641d2d905c19393adf340a04e48c9b527de964736f6c634300050c0032";
 
    function deploy(bytes32 salt) public {
        bytes memory bytecode = contractBytecode;
        address addr;
      
        assembly {
          addr := create2(0, add(bytecode, 0x20), mload(bytecode), salt)
        }
    }
}

利用脚本跑Salt即可。

from web3 import Web3

s1 = '0xffca4dfd86a86c48c5d9c228bedbeb7f218a29c94b'

s3 = '4670da3f633e838c2746ca61c370ba3dbd257b86b28b78449f4185480e2aba51'

i = 0
while(1):
    salt = hex(i)[2:].rjust(64, '0')
    s = s1+salt+s3
    hashed = Web3.sha3(hexstr=s)
    hashed_str = ''.join(['%02x' % b for b in hashed])
    if 'badc0de' in hashed_str[24:]:
        print(salt,hashed_str)
        break
    i += 1
    print(salt)

推荐文章

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注