IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 区块链 -> 实战例子:Solidity代码小失误导致池子里60万U被盗空 -> 正文阅读

[区块链]实战例子:Solidity代码小失误导致池子里60万U被盗空

实战例子:Solidity代码小失误导致池子里60万USDT被盗空
被盗原因:利用token的漏洞

查看合约地址
一、先看这笔交易:黑客用0.04个eth换了112个USDT
再用112个USDT换了101个TCR
关键这步:101个TCR换了63.9万USDT(价值400万RMB),如下图
在这里插入图片描述

第1步,点击这里
第2步,点address
在这里插入图片描述

第3步,点contract,就可以看合约源码了
在这里插入图片描述

/**
 *Submitted for verification at Etherscan.io on 2021-04-13
*/

// SPDX-License-Identifier: Unlicense
pragma solidity 0.8.2;

// interface need to claim rouge tokens from contract and handle upgraded functions
abstract contract IERC20 {
    function balanceOf(address owner) public view virtual returns (uint256);

    function transfer(address to, uint256 amount) public virtual;

    function allowance(address owner, address spender)
        public
        view
        virtual
        returns (uint256);

    function totalSupply() public view virtual returns (uint256);
}

// interface to potential future upgraded contract,
// only essential write functions that need check that this contract is caller
abstract contract IUpgradedToken {
    function transferByLegacy(
        address sender,
        address to,
        uint256 amount
    ) public virtual returns (bool);

    function transferFromByLegacy(
        address sender,
        address from,
        address to,
        uint256 amount
    ) public virtual returns (bool);

    function approveByLegacy(
        address sender,
        address spender,
        uint256 amount
    ) public virtual;
}

//
// The ultimate ERC20 token contract for TecraCoin project
//
contract TcrToken {
    //
    // ERC20 basic information
    //
    uint8 public constant decimals = 8;
    string public constant name = "TecraCoin";
    string public constant symbol = "TCR";
    uint256 private _totalSupply;
    uint256 public constant maxSupply = 21000000000000000;

    string public constant version = "1";
    uint256 public immutable getChainId;

    //
    // other flags, data and constants
    //
    address public owner;
    address public newOwner;

    bool public paused;

    bool public deprecated;
    address public upgradedAddress;

    bytes32 public immutable DOMAIN_SEPARATOR;

    // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
    bytes32 public constant PERMIT_TYPEHASH =
        0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;

    string private constant ERROR_DAS = "Different array sizes";
    string private constant ERROR_BTL = "Balance too low";
    string private constant ERROR_ATL = "Allowance too low";
    string private constant ERROR_OO = "Only Owner";

    //
    // events
    //
    event Transfer(address indexed from, address indexed to, uint256 value);

    event Paused();
    event Unpaused();

    event Approval(
        address indexed owner,
        address indexed spender,
        uint256 value
    );

    event AddedToBlacklist(address indexed account);
    event RemovedFromBlacklist(address indexed account);

    //
    // data stores
    //
    mapping(address => mapping(address => uint256)) private _allowances;
    mapping(address => uint256) private _balances;

    mapping(address => bool) public isBlacklisted;

    mapping(address => bool) public isBlacklistAdmin;
    mapping(address => bool) public isMinter;
    mapping(address => bool) public isPauser;

    mapping(address => uint256) public nonces;

    //
    // contract constructor
    //
    constructor() {
        owner = msg.sender;
        getChainId = block.chainid;
        // EIP712 Domain
        DOMAIN_SEPARATOR = keccak256(
            abi.encode(
                keccak256(
                    "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
                ),
                keccak256(bytes(name)),
                keccak256(bytes(version)),
                block.chainid,
                address(this)
            )
        );
    }

    //
    // "approve"
    //
    function approve(address spender, uint256 amount) external {
        if (deprecated) {
            return
                IUpgradedToken(upgradedAddress).approveByLegacy(
                    msg.sender,
                    spender,
                    amount
                );
        }
        _approve(msg.sender, spender, amount);
    }

    //
    // "burnable"
    //
    function burn(uint256 amount) external {
        require(_balances[msg.sender] >= amount, ERROR_BTL);
        _burn(msg.sender, amount);
    }

    function burnFrom(address from, uint256 amount) external {
        require(_allowances[msg.sender][from] >= amount, ERROR_ATL);
        require(_balances[from] >= amount, ERROR_BTL);
        _approve(msg.sender, from, _allowances[msg.sender][from] - amount);
        _burn(from, amount);
    }

    //
    // "transfer"
    //
    function transfer(address to, uint256 amount) external returns (bool) {
        if (deprecated) {
            return
                IUpgradedToken(upgradedAddress).transferByLegacy(
                    msg.sender,
                    to,
                    amount
                );
        }
        require(_balances[msg.sender] >= amount, ERROR_BTL);
        _transfer(msg.sender, to, amount);
        return true;
    }

    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) external returns (bool) {
        if (deprecated) {
            return
                IUpgradedToken(upgradedAddress).transferFromByLegacy(
                    msg.sender,
                    from,
                    to,
                    amount
                );
        }
        _allowanceTransfer(msg.sender, from, to, amount);
        return true;
    }

    //
    // non-ERC20 functionality
    //
    // Rouge tokens and ETH withdrawal
    function acquire(address token) external onlyOwner {
        if (token == address(0)) {
            payable(owner).transfer(address(this).balance);
        } else {
            uint256 amount = IERC20(token).balanceOf(address(this));
            require(amount > 0, ERROR_BTL);
            IERC20(token).transfer(owner, amount);
        }
    }

    //
    // "blacklist"
    //
    function addBlacklister(address user) external onlyOwner {
        isBlacklistAdmin[user] = true;
    }

    function removeBlacklister(address user) external onlyOwner {
        isBlacklistAdmin[user] = false;
    }

    modifier onlyBlacklister {
        require(isBlacklistAdmin[msg.sender], "Not a Blacklister");
        _;
    }

    modifier notOnBlacklist(address user) {
        require(!isBlacklisted[user], "Address on blacklist");
        _;
    }

    function addBlacklist(address user) external onlyBlacklister {
        isBlacklisted[user] = true;
        emit AddedToBlacklist(user);
    }

    function removeBlacklist(address user) external onlyBlacklister {
        isBlacklisted[user] = false;
        emit RemovedFromBlacklist(user);
    }

    function burnBlackFunds(address user) external onlyOwner {
        require(isBlacklisted[user], "Address not on blacklist");
        _burn(user, _balances[user]);
    }

    //
    // "bulk transfer"
    //
    // transfer to list of address-amount
    function bulkTransfer(address[] calldata to, uint256[] calldata amount)
        external
        returns (bool)
    {
        require(to.length == amount.length, ERROR_DAS);
        for (uint256 i = 0; i < to.length; i++) {
            require(_balances[msg.sender] >= amount[i], ERROR_BTL);
            _transfer(msg.sender, to[i], amount[i]);
        }
        return true;
    }

    // transferFrom to list of address-amount
    function bulkTransferFrom(
        address from,
        address[] calldata to,
        uint256[] calldata amount
    ) external returns (bool) {
        require(to.length == amount.length, ERROR_DAS);
        for (uint256 i = 0; i < to.length; i++) {
            _allowanceTransfer(msg.sender, from, to[i], amount[i]);
        }
        return true;
    }

    // send same amount to multiple addresses
    function bulkTransfer(address[] calldata to, uint256 amount)
        external
        returns (bool)
    {
        require(_balances[msg.sender] >= amount * to.length, ERROR_BTL);
        for (uint256 i = 0; i < to.length; i++) {
            _transfer(msg.sender, to[i], amount);
        }
        return true;
    }

    // send same amount to multiple addresses by allowance
    function bulkTransferFrom(
        address from,
        address[] calldata to,
        uint256 amount
    ) external returns (bool) {
        require(_balances[from] >= amount * to.length, ERROR_BTL);
        for (uint256 i = 0; i < to.length; i++) {
            _allowanceTransfer(msg.sender, from, to[i], amount);
        }
        return true;
    }

    //
    // "mint"
    //
    modifier onlyMinter {
        require(isMinter[msg.sender], "Not a Minter");
        _;
    }

    function addMinter(address user) external onlyOwner {
        isMinter[user] = true;
    }

    function removeMinter(address user) external onlyOwner {
        isMinter[user] = false;
    }

    function mint(address to, uint256 amount) external onlyMinter {
        _balances[to] += amount;
        _totalSupply += amount;
        require(_totalSupply < maxSupply, "You can not mine that much");
        emit Transfer(address(0), to, amount);
    }

    //
    // "ownable"
    //
    modifier onlyOwner {
        require(msg.sender == owner, ERROR_OO);
        _;
    }

    function giveOwnership(address _newOwner) external onlyOwner {
        newOwner = _newOwner;
    }

    function acceptOwnership() external {
        require(msg.sender == newOwner, ERROR_OO);
        newOwner = address(0);
        owner = msg.sender;
    }

    //
    // "pausable"
    //
    function addPauser(address user) external onlyOwner {
        isPauser[user] = true;
    }

    function removePauser(address user) external onlyOwner {
        isPauser[user] = false;
    }

    modifier onlyPauser {
        require(isPauser[msg.sender], "Not a Pauser");
        _;
    }

    modifier notPaused {
        require(!paused, "Contract is paused");
        _;
    }

    function pause() external onlyPauser notPaused {
        paused = true;
        emit Paused();
    }

    function unpause() external onlyPauser {
        require(paused, "Contract not paused");
        paused = false;
        emit Unpaused();
    }

    //
    // "permit"
    // Uniswap integration EIP-2612
    //
    function permit(
        address user,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external {
        require(deadline >= block.timestamp, "permit: EXPIRED");
        bytes32 digest =
            keccak256(
                abi.encodePacked(
                    "\x19\x01",
                    DOMAIN_SEPARATOR,
                    keccak256(
                        abi.encode(
                            PERMIT_TYPEHASH,
                            user,
                            spender,
                            value,
                            nonces[user]++,
                            deadline
                        )
                    )
                )
            );
        address recoveredAddress = ecrecover(digest, v, r, s);
        require(
            recoveredAddress != address(0) && recoveredAddress == user,
            "permit: INVALID_SIGNATURE"
        );
        _approve(user, spender, value);
    }

    //
    // upgrade contract
    //
    function upgrade(address token) external onlyOwner {
        deprecated = true;
        upgradedAddress = token;
    }

    //
    // ERC20 view functions
    //
    function balanceOf(address account) external view returns (uint256) {
        if (deprecated) {
            return IERC20(upgradedAddress).balanceOf(account);
        }
        return _balances[account];
    }

    function allowance(address account, address spender)
        external
        view
        returns (uint256)
    {
        if (deprecated) {
            return IERC20(upgradedAddress).allowance(account, spender);
        }
        return _allowances[account][spender];
    }

    function totalSupply() external view returns (uint256) {
        if (deprecated) {
            return IERC20(upgradedAddress).totalSupply();
        }
        return _totalSupply;
    }

    //
    // internal functions
    //
    function _approve(
        address account,
        address spender,
        uint256 amount
    ) private notOnBlacklist(account) notOnBlacklist(spender) notPaused {
        _allowances[account][spender] = amount;
        emit Approval(account, spender, amount);
    }

    function _allowanceTransfer(
        address spender,
        address from,
        address to,
        uint256 amount
    ) private {
        require(_allowances[from][spender] >= amount, ERROR_ATL);
        require(_balances[from] >= amount, ERROR_BTL);

        // exception for Uniswap "approve forever"
        if (_allowances[from][spender] != type(uint256).max) {
            _approve(from, spender, _allowances[from][spender] - amount);
        }

        _transfer(from, to, amount);
    }

    function _burn(address from, uint256 amount) private notPaused {
        _balances[from] -= amount;
        _totalSupply -= amount;
        emit Transfer(from, address(0), amount);
    }

    function _transfer(
        address from,
        address to,
        uint256 amount
    ) private notOnBlacklist(from) notOnBlacklist(to) notPaused {
        require(to != address(0), "Use burn instead");
        require(from != address(0), "What a Terrible Failure");
        _balances[from] -= amount;
        _balances[to] += amount;
        emit Transfer(from, to, amount);
    }
}

// rav3n_pl was here

部署一个合约,然后在合约里面进行很多交易,然后把USDT转走了
在这里插入图片描述

第4步,查看合约创建时间

在这里插入图片描述
合约创建300多天了,在这里插入图片描述
但是黑客是Feb-04-2022 10:54:37 AM交易的,说明上线很久,才发行漏洞。
在这里插入图片描述

而且合约没有经过安全校验。
在这里插入图片描述
二、分析合约代码
tenderly.co上分析合约操作步骤

让池子里的TCR币突然就燃烧掉很多,池子里的TCR变少了,价格自然变高。所以101个TCR换了
63.9万个USDT
错误代码:
require(_allowances[msg.sender][from] >= amount, ERROR_ATL);
应该是:require(_allowances[from] [msg.sender]>= amount, ERROR_ATL);
写反了,导致任何人都可以燃烧任何人的token
在这里插入图片描述

  区块链 最新文章
盘点具备盈利潜力的几大加密板块,以及潜在
阅读笔记|让区块空间成为商品,打造Web3云
区块链1.0-比特币的数据结构
Team Finance被黑分析|黑客自建Token“瞒天
区块链≠绿色?波卡或成 Web3“生态环保”标
期货从入门到高深之手动交易系列D1课
以太坊基础---区块验证
进入以太坊合并的五个数字
经典同态加密算法Paillier解读 - 原理、实现
IPFS/Filecoin学习知识科普(四)
上一篇文章      下一篇文章      查看所有文章
加:2022-03-16 22:27:08  更:2022-03-16 22:27:13 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 22:27:33-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码