实战例子: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)publicviewvirtualreturns (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 DomainDOMAIN_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) {returnIUpgradedToken(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) {returnIUpgradedToken(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) {returnIUpgradedToken(upgradedAddress).transferFromByLegacy(msg.sender,from,to,amount);}_allowanceTransfer(msg.sender, from, to, amount);return true;}//// non-ERC20 functionality//// Rouge tokens and ETH withdrawalfunction 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-amountfunction bulkTransfer(address[] calldata to, uint256[] calldata amount)externalreturns (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-amountfunction 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 addressesfunction bulkTransfer(address[] calldata to, uint256 amount)externalreturns (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 allowancefunction 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("",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)externalviewreturns (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

实战例子:Solidity代码小失误导致池子里60万U被盗空相关推荐

  1. solidity代码

    http://www.tryblockchain.org/ 教你如何舒服的看solidity代码 最近智能合约随着区块链技术的发展越发收到广大技术人员的重视! 其中最被看好的以太坊就是一个提供智能合约 ...

  2. 整理了60个 Python 实战例子,拿来即用!

    人生苦短,我用 Python! 大家好,最近有一些朋友问我有没有一些 Python 实战小案例.今天我整理排版了一遍,给大家分享一下.喜欢记得点赞.收藏.关注. 整理了60个Python小例子,拿来即 ...

  3. Python打包工具Pyintealler打包py文件为windows exe文件过程及踩坑记录+实战例子

    Python打包工具Pyintealler打包py文件为windows exe文件过程及踩坑记录+实战例子 目录 Python打包工具Pyintealler打包py文件为windows exe文件过程 ...

  4. 这套1600赞的NLP课程已开放,面向实战,视频代码都有丨资源

    铜灵 发自 凹非寺 量子位 出品 | 公众号 QbitAI 纸上得来终觉浅,决胜NLP要躬行. 一套面向实战.号称"代码优先"的NLP课程来了,名字为A Code-First In ...

  5. 一套代码小程序WebNative运行的探索02

    接上文:一套代码小程序&Web&Native运行的探索01,本文都是一些探索性为目的的研究学习,在最终版输出前,内中的内容可能会有点乱 参考: https://github.com/f ...

  6. apriori算法代码_资源 | 《机器学习实战》及代码(基于Python3)

    〇.<机器学习实战> 今天推荐给大家的是<机器学习实战>这本书. 机器学习作为人工智能研究领域中一个极其重要的研究方向(一文章看懂人工智能.机器学习和深度学习),在当下极其热门 ...

  7. 记录一下:在菜单上添加自绘图形的例子(VB6代码)

    不复杂,记录在这里以备用 效果图: 代码如下: Option Explicit '在菜单上添加自绘图形的例子 '窗体上添加一个Picture1,一个Command1,一个至少带一个下级菜单的顶级菜单. ...

  8. 【一套代码小程序NativeWeb阶段总结篇】可以这样阅读Vue源码

    前言 前面我们对微信小程序进行了研究:[微信小程序项目实践总结]30分钟从陌生到熟悉 在实际代码过程中我们发现,我们可能又要做H5站又要做小程序同时还要做个APP,这里会造成很大的资源浪费,如果设定一 ...

  9. [机器学习]-K近邻-最简单的入门实战例子

    本篇文章分为两个部分,前一部分主要简单介绍K近邻,后一部分是一个例子 第一部分--K近邻简介 从字面意思就可以容易看出,所谓的K近邻,就是找到某个样本距离(这里的距离可以是欧式距离,曼哈顿距离,切比雪 ...

  10. tensorflow 语义slam_研究《视觉SLAM十四讲从理论到实践第2版》PDF代码+《OpenCV+TensorFlow深度学习与计算机视觉实战》PDF代码笔记...

    我们知道随着人工神经网络和深度学习的发展,通过模拟视觉所构建的卷积神经网络模型在图像识别和分类上取得了非常好的效果,借助于深度学习技术的发展,使用人工智能去处理常规劳动,理解语音语义,帮助医学诊断和支 ...

最新文章

  1. Java技术分享:集群环境下的定时任务
  2. HTML 5 全局属性
  3. 阿帕奇跨域_阿帕奇骆驼备忘单
  4. Mybatis输入映射和输出映射
  5. 陶陶摘苹果(信息学奥赛一本通-T1103)
  6. 内存映射与DMA笔记
  7. iOS开发:为什么你的学习效率如此低,为什么你很迷茫?
  8. pytorch之学习率变化策略之LambdaLR
  9. 图像局部特征(十八)--BOW
  10. vue axios配置 发起请求加载loading请求结束关闭loading
  11. mysql中的like查询能否用的到索引
  12. 计算机基础高一知识点,计算机基础全部知识点_.doc
  13. 【Godot】行为树(一)了解与设计行为树代码
  14. java获取中文拼音或拼音首字母
  15. JavaScript事件与JQuery事件
  16. vivo APEX 2019 概念机亮相:全屏幕指纹 + 无开孔,支持 5G
  17. 如何使用winrar压缩工具实现:文件打包为自解压EXE类型
  18. python中if brthon环境安装包_python-模块系列
  19. 2022第四届长安杯wp
  20. 关于注册Github不能通过验证的解决方法(easy,一定过)

热门文章

  1. 搭建 WordPress 博客教程
  2. Verilog学习之路(7)— 数字加法器
  3. 服务器多网卡同一网段
  4. 我想开发一个小程序,大概需要多少钱?
  5. 阿里p9就三分钟。。。。。
  6. vs安卓开发发布_开始取代安卓系统?华为Mate系列新产品曝光:运行鸿蒙操作系统!...
  7. 利用for循环生成由ABCDEFG...XYZ,26个大写字母与26个小写字母组成的数组
  8. nginx 配置https 443端口配置
  9. mysql 事件计划区别_【转】mysql 计划事件
  10. 魅族MX5 如何进入开发者模式