【加密社】一行代码的漏洞,就蒸发了280亿美金!

加密社

2018年2月24日新闻,美图公司推出的第一个和区块链技术有关的项目叫做美链(英文缩写是BEC,全名叫做Beauty Chain)

这个项目发行的数字货币开始在一家叫OKEX的全球数字资产交易平台上可以买卖了。这个BEC币一共发了70亿个,价格曾经涨到了每个超过4美元,使得BEC的总价值一度超过了280亿美元。

不过,在同年4月22日的时候,因为BEC出现了一个很严重的安全问题,导致这个项目的市场价值几乎变成了零。

接下来我们来看具体是怎么回事

前言:在这里我们不过多的分析漏洞带来的经济损失及行业影响,纯技术角度来分析下漏洞本身。

1. 合约代码分析

在这里如果我们要分析代码,需要刨析合约代码的本身,至于BEC的合约代码,这在区块链上是开源的,所以我们可以看到。(在这里我对合约代码进行了消息注释,以防小白看不懂)

pragma solidity ^0.4.16;

/**
 * @title SafeMath
 * @dev 包含安全检查的数学运算函数,错误时会抛出异常
 */
library SafeMath {
  function mul(uint256 a, uint256 b) internal constant returns (uint256) {
    uint256 c = a * b;
    assert(a == 0 || c / a == b); // 防止乘法溢出
    return c;
  }

  function div(uint256 a, uint256 b) internal constant returns (uint256) {
    // assert(b > 0); // 当除数为0时,Solidity自动抛出异常
    uint256 c = a / b;
    // assert(a == b * c + a % b); // 这里不会有不成立的情况
    return c;
  }

  function sub(uint256 a, uint256 b) internal constant returns (uint256) {
    assert(b <= a); // 防止减法溢出
    return a - b;
  }

  function add(uint256 a, uint256 b) internal constant returns (uint256) {
    uint256 c = a + b;
    assert(c >= a); // 防止加法溢出
    return c;
  }
}

/**
 * @title ERC20Basic
 * @dev ERC20接口的简化版本
 * @dev 参见 https://github.com/ethereum/EIPs/issues/179
 */
contract ERC20Basic {
  uint256 public totalSupply;
  function balanceOf(address who) public constant returns (uint256);
  function transfer(address to, uint256 value) public returns (bool);
  event Transfer(address indexed from, address indexed to, uint256 value);
}

/**
 * @title Basic token
 * @dev 标准代币的基本版本,不包含授权功能
 */
contract BasicToken is ERC20Basic {
  using SafeMath for uint256;

  mapping(address => uint256) balances;

  /**
  * @dev 向指定地址转移代币
  * @param _to 转移目标地址
  * @param _value 转移的数量
  */
  function transfer(address _to, uint256 _value) public returns (bool) {
    require(_to != address(0)); // 验证目标地址不是零地址
    require(_value > 0 && _value <= balances[msg.sender]); // 验证转移数量合法

    // SafeMath.sub 在余额不足时会抛出异常
    balances[msg.sender] = balances[msg.sender].sub(_value);
    balances[_to] = balances[_to].add(_value);
    Transfer(msg.sender, _to, _value);
    return true;
  }

  /**
  * @dev 获取指定地址的余额
  * @param _owner 查询余额的地址
  * @return 返回该地址拥有的代币数量
  */
  function balanceOf(address _owner) public constant returns (uint256 balance) {
    return balances[_owner];
  }
}

/**
 * @title ERC20 interface
 * @dev 参见 https://github.com/ethereum/EIPs/issues/20
 */
contract ERC20 is ERC20Basic {
  function allowance(address owner, address spender) public constant returns (uint256);
  function transferFrom(address from, address to, uint256 value) public returns (bool);
  function approve(address spender, uint256 value) public returns (bool);
  event Approval(address indexed owner, address indexed spender, uint256 value);
}

/**
 * @title Standard ERC20 token
 *
 * @dev 基本标准代币的实现
 * @dev 基于 FirstBlood 的代码:https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
 */
contract StandardToken is ERC20, BasicToken {
  mapping (address => mapping (address => uint256)) internal allowed;

  /**
   * @dev 从一个地址向另一个地址转移代币
   * @param _from 转出地址
   * @param _to 转入地址
   * @param _value 转移的数量
   */
  function transferFrom(address _from, address _to, uint256 _value) public returns (bool) {
    require(_to != address(0)); // 验证目标地址不是零地址
    require(_value > 0 && _value <= balances[_from]); // 验证转移数量合法
    require(_value <= allowed[_from][msg.sender]); // 检查授权数量是否足够

    balances[_from] = balances[_from].sub(_value);
    balances[_to] = balances[_to].add(_value);
    allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
    Transfer(_from, _to, _value);
    return true;
  }

  /**
   * @dev 授权指定地址代表发送者花费指定数量的代币
   *
   * 注意:使用此方法修改授权金额时,应注意交易顺序风险。一种缓解方案是先将授权金额减少到0,

猜你喜欢

转载自blog.csdn.net/qq_16712551/article/details/142052143