讯晨财经

xuncen.com

慢雾:YFValue,一行代码如何锁定上亿资产

发布时间: 2020-09-21 23:05:34
序言 据链闻信息,DeFi 新项目 YFValue (YFV)发布消息称,精英团队于昨天在 YFV 质押贷款池里发觉一个系统漏洞,故意参加者借此机会系统漏洞对质押贷款中的 YFV 记时器独立重设。目......
序言

据链闻信息,DeFi 新项目 YFValue (YFV)发布消息称,精英团队于昨天在 YFV 质押贷款池里发觉一个系统漏洞,故意参加者借此机会系统漏洞对质押贷款中的 YFV 记时器独立重设。现阶段现有一个故意参加者正在尝试借此机会敲诈勒索精英团队。慢雾安全性精英团队对于此事开展了详细分析,下列是有关关键技术。

关键点剖析

之上是 YFValue 的官方网表明 (来源于:https://medium.com/@yfv.finance/yfv-update-staking-pool-exploit-713cb353ff7d),从申明中我们可以获知是 YFV 质押池出現了难题,故意的客户可重设 YFV 质押者的记时器,对 YFV 的质押者导致麻烦,但这并不会造成 资产损害。

根据登录 YFValue 的官网 ,(https://yfv.finance/staking),能够 发觉在 YFValue 的管理体系中,客户可根据质押贷款有关的代币总获得相匹配的奖赏,现阶段 YFValue 适用的质押贷款代币总池有下列好多个:

能够 见到,现阶段因为系统漏洞的缘故,YFV 的质押池早已在 UI 页面关掉了质押作用,可是合同上现阶段还没有关掉代币总质押的作用,大家必须追踪编码来剖析实际的关键点点。

依据官方网站出示的 Github 详细地址,大家追溯来到有关的代码仓库(https://github.com/yfv-finance/audit),有关 YFV 质押的有关逻辑性在YFV_Stake.sol 合同中,合同中有关质押的涵数有 2 个,分别是 stake 涵数和 stakeOnBehalf 涵数,下列是实际的编码:

 function stake(uint256 amount, address referrer) public updateReward(msg.sender) checkNextEpoch {
        require(amount > 0, "Cannot stake 0");
        require(referrer != msg.sender, "You cannot refer yourself.");
        super.tokenStake(amount);
        lastStakeTimes[msg.sender] = block.timestamp;
        emit Staked(msg.sender, amount);
        if (rewardReferral != address(0) && referrer != address(0)) {
            IYFVReferral(rewardReferral).setReferrer(msg.sender, referrer);
        }
    }

    function stakeOnBehalf(address stakeFor, uint256 amount) public updateReward(stakeFor) checkNextEpoch {
        require(amount > 0, "Cannot stake 0");
        super.tokenStakeOnBehalf(stakeFor, amount);
        lastStakeTimes[stakeFor] = block.timestamp;
      & nbsp; emit Staked(stakeFor, amount);
    }

根据编码不会太难发觉,不论是 stake 涵数還是 stakeOnBehalf 涵数,逻辑性基础是一样的,最先是校检了质押额度不可以为0,然后各自启用顶层的 tokenStake 和 tokenStakeOnBehalf 涵数。随后升级客户的质押時间。只不过是 stakeOnBehalf 涵数能够 用以为别人质押。tokenStake 和 tokenStakeOnBehalf 的编码以下:

function tokenStake(uint256 amount) internal {
        _totalSupply = _totalSupply.add(amount);
        _balances[msg.sender] = _balances[msg.sender].add(amount);
        yfv.safeTransferFrom(msg.sender, address(this), amount);
    }

    function tokenStakeOnBehalf(address stakeFor, uint256 amount) internal {
        _totalSupply = _totalSupply.add(amount);
        _balances[stakeFor] = _balances[stakeFor].add(amount);
        yfv.safeTransferFrom(msg.sender, address(this), amount);
    }

能够 见到这儿仅仅简易的把相匹配的 token 用 transferFrom 的方法转到到合同中,没什么非常的逻辑性点。到这儿全部抵押流程就很清楚了,接下去是盈利的全过程。测算客户盈利的是 stakeReward 涵数,领到盈利的为 withdraw 涵数,编码各自以下:

function stakeReward() public updateReward(msg.sender) checkNextEpoch {
        uint256 reward = getReward();
        require(reward > 0, "Earned too little");
        super.tokenStake(reward);
        lastStakeTimes[msg.sender] = block.timestamp;
        emit Staked(msg.sender, reward);
    }
    
    function withdraw(uint256 amount) public updateReward(msg.sender) checkNextEpoch {
        require(amount > 0, "Cannot withdraw 0");
        require(block.timestamp >= unfrozenStakeTime(msg.sender), "Coin is still frozen");
        super.tokenWithdraw(amount);
        emit Withdrawn(msg.sender, amount);
    }

根据剖析测算盈利和领到盈利的编码,发觉逻辑性也非常简单,stake 涵数最先是根据 updateReward 装饰器升级了客户的奖赏,随后应用 getReward 函数计算了客户的奖赏,并把质押時间设成当今区块链時间。最终,客户在获取奖赏的情况下,withdraw 涵数会最先测算当今的区块链時间,再与 unfrozenStakeTime 涵数中测算出的時间开展比照,仅有当今区块链時间超过 unfrozenStakeTime 测算出的時间,才容许取现。unfrozenStakeTime 的编码以下:

 function unfrozenStakeTime(address account) public view returns (uint256) {
        return lastStakeTimes[account] FROZEN_STAKING_TIME;
    }

从编码中获知,unfrozenStakeTime 是应用客户的之前质押時间再加 FROZEN_STAKING_TIME 变量定义得到锁住時间,要是超出時间,就能根据 withdraw 涵数取现盈利。全部质押和领到盈利的简单化步骤以下:

剖析了一大堆,返回大家最开始的难题,故意的客户是怎么锁住别的用户的财产的呢?

返回客户质押的逻辑性,能够 发觉质押逻辑性中的 stakeOnBehalf 涵数原意是协助开展质押,可是这儿有一个难题,假如这一客户此前早已有质押了呢?那根据对早已质押的客户再度开展质押,比如说质押 1 个 YFV,是否就能以非常低的成本费重设已质押的客户的记时器,导致用户在 withdraw 时没法取得成功启用。更进一步,假定 YFV 质押客户早已取得成功启用了 stakeReward 涵数,在即将做到 unfrozenStakeTime 所要求的時间时,故意的客户能够 根据 stakeOnBehalf 涵数给这一客户质押小量财产,就可以再度对质押奖赏开展锁住,理论上那样往复式循环系统,就可以使客户没法取下自身的财产,但这个问题并不会造成 资产损害。进攻步骤以下:

前车可鉴

它是当月出現的第二个沒有历经财务审计的 DeFi 新项目所显现出的风险性,依据 YFValue 的官方网申明(https://medium.com/@yfv.finance/yfv-bringing-true-value-to-yield-farming-bddc4edf889a),新项目编码是由远见卓识的开发人员开展开发设计的,另外效仿了别的取得成功的新项目的编码,可是仍在所难免的出現了风险性。术有专攻,网络安全审计一方面必须新项目方的正向思维,另一方面,還是必须技术专业的安全性精英团队的发散思维,从技术专业的网络黑客视角开展仿真模拟抵抗,发现问题。

修补计划方案

根据剖析编码和系统漏洞关键点,对于此次系统漏洞,修补计划方案也非常简单,要是在质押的情况下检查用户的质押情况是不是为早已质押,假如早已质押,则不允许再度质押。或是对每一次的质押开展独立的解决,不可以对此前的质押情况造成危害。