整数溢出:
漏洞简介:
简单来说,就是Solidity整形变量被赋值高于或者低于可以表示的范围时 值会发生改变 一般会溢出为2的uint类型次方 -1 或者 0:
**上溢:会溢出为0
下溢:会溢为2*n-1 如果是uint256 即为:2的256次方 -1
漏洞通常出现地方:
1.条件检测的地方容易出现
2.任何计算的地方都可能出现
规避方法:
1.在solidity中运算之前 必须对输入和输出进行有效性认证
在进行任何计算之前,务必对操作数进行可能溢出与否的预判,或者用safemath库来编写计算逻辑,否则就可能会出现溢出问题;
实际案例:
Beauty Chain中出现的整数溢出漏洞:
eth address: 0xC5d105E63711398aF9bbff092d4B6769C82F793D
源码搜索此地址:
https://etherscan.io/address/0xC5d105E63711398aF9bbff092d4B6769C82F793D#code
整数溢出部分代码:
function batchTransfer(address[] _reveivers,uint256 _value) public whenNotPaused returns(bool) {
//在这里只讨论存在溢出的部分的代码 其余部分省略 有兴趣可以在上述网址查看源码进行审计
uint cnt = _reveivers.length;
uint256 amount = uint256(cnt) * _value;
require(cnt >0 && cnt <= 20);
requitre(_value >0 && balances[msg.sender]>=amount);
(接下来是一些转账运算)
}
代码逻辑分析:
在这里 代码逻辑主要是检测交易发起人的余额是否大于要转账的总余额(转账人数 * 转给每个人的钱) 如果大于 就转账
漏洞利用:
注意该合约在进行乘法运算的时候,直接用cnt强转uint256然后乘以_value, 这个时候如果乘积溢出uint256最大值,那么就可以绕过require中的要求,并且进行非法请求
具体操作:
将_value 传值 2**256 +1 / 2
2为address数组长度 即两个收款人地址 这个具体是几无所谓 只要保证溢出条件即可(即 2 * (2的256次方+1)/2 = 2的256次方 +1 > uint256最大值)
那么 amount就溢出为0 那么就绕过了下面的require 从而进行非法操作
P.S.
python生成的数 方便审计检测使用:
unsigned int range:
Unsigned int(uint) 最大表示数 超过此数会上溢为0:
uint8 最高为: 255
uint16 最高为: 65535
uint24 最高为: 16777215
uint32 最高为: 4294967295
uint40 最高为: 1099511627775
uint48 最高为: 281474976710655
uint56 最高为: 72057594037927935
uint64 最高为: 18446744073709551615
uint72 最高为: 4722366482869645213695
uint80 最高为: 1208925819614629174706175
uint88 最高为: 309485009821345068724781055
uint96 最高为: 79228162514264337593543950335
uint104 最高为: 20282409603651670423947251286015
uint112 最高为: 5192296858534827628530496329220095
uint120 最高为: 1329227995784915872903807060280344575
uint128 最高为: 340282366920938463463374607431768211455
uint136 最高为: 87112285931760246646623899502532662132735
uint144 最高为: 22300745198530623141535718272648361505980415
uint152 最高为: 5708990770823839524233143877797980545530986495
uint160 最高为: 1461501637330902918203684832716283019655932542975
uint168 最高为: 374144419156711147060143317175368453031918731001855
uint176 最高为: 95780971304118053647396689196894323976171195136475135
uint184 最高为: 24519928653854221733733552434404946937899825954937634815
uint192 最高为: 6277101735386680763835789423207666416102355444464034512895
uint200 最高为: 1606938044258990275541962092341162602522202993782792835301375
uint208 最高为: 411376139330301510538742295639337626245683966408394965837152255
uint216 最高为: 105312291668557186697918027683670432318895095400549111254310977535
uint224 最高为: 26959946667150639794667015087019630673637144422540572481103610249215
uint232 最高为: 6901746346790563787434755862277025452451108972170386555162524223799295
uint240 最高为: 1766847064778384329583297500742918515827483896875618958121606201292619775
uint248 最高为: 452312848583266388373324160190187140051835877600158453279131187530910662655
uint256 最高为: 115792089237316195423570985008687907853269984665640564039457584007913129639935
访问控制缺陷漏洞:
漏洞简介:
即某些对权限有要求的方法的修饰符逻辑错误造成合约中的某些私有函数可以被非法调用
常出现的地方:
在function修饰符modifier上 或者访问权限 private public internal external 调用方法:call delegatecall中
防范方法:
1.在编写合约的时候 务必检查好函数调用权限 调用逻辑一定要清晰 否则一旦部署到区块链上 则不可更改 容易造成经济损失
2.避免disable enable在合约逻辑中存在
3.敏感变量必须通过函数修饰符进行权限控制 对可以操纵合约内部敏感变量的函数 应该用assert if-else等进行权限限制
漏洞举例:
IcxToken 合约中的
modifier onlyFromWallet {
require(msg.sender != walletAddress);
_;
}
function disableTokenTransfer()
external
onlyFromWallet {
tokenTransfer = false;
TokenTransfer();
}
function IcxToken( uint initial_balance, address wallet) {
require(wallet != 0);
require(initial_balance != 0);
_balances[msg.sender] = initial_balance;
_supply = initial_balance;
walletAddress = wallet;
}
在 disableTokenTransfer方法中 关闭合约交易权限应该只能由wallet执行
否则 如果被恶意调用disableTokenTransfer函数 那么该合约中被isTokenTransfer修饰的函数均不可正常使用
即这里的msg.sender != walletAddress 应该为 msg.sender == walletAddress
利用方法:
只要调用disableTokenTransfer的地址不是walletaddress即可
在remix实验时,可以直接点击函数进行调用
智能合约
跨合约调用漏洞:
漏洞简介:
由call系列函数引起的外部合约注入,即外部合约A调用B合约中的私有 || 具有权限限制的函数
原理解释:
solidity中 合约相互调用有两种:
对象:合约地址当作合约对象适用 然后调用
用call() delegatecall() callcode()
方法解释:
call函数与delegatecall函数:
比如:
B中的function名字为 Bfunc
如果 A合约中以call方式调用B合约的Bfunc 那么Bfunc会在B合约上下文中执行 结果返回给A合约
如果用delegatecall调用Bfunc 那么会将Bfunc方法以“复制粘贴”的方式放在A合约中(A中需要包含Bfunc所需函数与变量),然后在A合约中调用
安全漏洞主要是由call()方法调用引起的:
call():
调用方法:
address.call(function_name, args[])
|| address.call(bytes)
漏洞代码:
contract sample{
function a(byte data) {
this.call(data)
}
function secret public{
require(this == msg.sender)
//code
}
}
在这个合约中 secret函数要求调用方必须为合约自己
如果在函数a中 合约byte码指向的合约构造了一个调用:调用secret函数 那么根据call函数机制 会将此代码“粘贴”到secret函数中
那么通过a函数 就可以调用secret函数 达到注入攻击目的
关于callcode的漏洞:
EVM中,对callcode方法:传参时,不会验证参数的个数,只要找到了需要的参数,其他参数就会忽略 不会产生影响
漏洞地址(之后补上):
防范方法:
出现这类漏洞的根本在于滥用call系列方法,防范自然是减少此类方法使用 比如交易可以用transfer()实现
实例:
漏洞代码:
contract sample{
function a(byte data) {
this.call(data)
}
function secret public{
require(this == msg.sender)
//code
}
}
在这个合约中 secret函数要求调用方必须为合约自己 如果在函数a中 合约byte码指向的合约构造了一个调用:调用secret函数 那么根据call函数机制 会将此代码“粘贴”到secret函数中 那么通过a函数 就可以调用secret函数 达到注入攻击目的
关于callcode的漏洞:EVM中,对callcode方法:传参时,不会验证参数的个数,只要找到了需要的参数,其他参数就会忽略 不会产生影响
漏洞地址:https://etherscan.io/address/0x461733c17b0755ca5649b6db08b3e213fcf22546#code
漏洞处代码:
function transferFrom(address _from, address _to, uint256 _amount, bytes _data, string _custom_fallback)
public
returns (bool success)
{
// Alerts the token controller of the transfer
if (isContract(controller)) {
if (!TokenController(controller).onTransfer(_from, _to, _amount))
throw;
}
require(super.transferFrom(_from, _to, _amount));
if (isContract(_to)) {
ERC223ReceivingContract receiver = ERC223ReceivingContract(_to);
receiver.call.value(0)(bytes4(keccak256(_custom_fallback)), _from, _amount, _data);
}
ERC223Transfer(_from, _to, _amount, _data);
return true;
}
代码解释:漏洞核心部分为
receiver.call.value(0)(bytes4(keccak256(_custom_fallback)), _from, _amount, _data);
在这里 如果目标地址为合约 就调用_custom_fallback 回退函数 并且依次填入from amount data
漏洞利用:如果将_to的地址写为该合约本身,那么就可以实现以owner身份,即该合约自身的权限调用该合约,那么就可以调用合约中的setOwner方法,那么就可以将任意address设置为owner,进而进行其他非法操作。
P.S. 跨合约调用漏洞代码:
```typescript
```typescript
/**
*Submitted for verification at Etherscan.io on 2017-11-17
*/
pragma solidity ^0.4.13;
contract DSAuthority {
function canCall(
address src, address dst, bytes4 sig
) public view returns (bool);
}
contract DSAuthEvents {
event LogSetAuthority (address indexed authority);
event LogSetOwner (address indexed owner);
}
contract DSAuth is DSAuthEvents {
DSAuthority public authority;
address public owner;
function DSAuth() public {
owner = msg.sender;
LogSetOwner(msg.sender);
}
function setOwner(address owner_)
public
auth
{
owner = owner_;
LogSetOwner(owner);
}
function setAuthority(DSAuthority authority_)
public
auth
{
authority = authority_;
LogSetAuthority(authority);
}
modifier auth {
require(isAuthorized(msg.sender, msg.sig));
_;
}
function isAuthorized(address src, bytes4 sig) internal view returns (bool) {
if (src == address(this)) {
return true;
} else if (src == owner) {
return true;
} else if (authority == DSAuthority(0)) {
return false;
} else {
return authority.canCall(src, this, sig);
}
}
}
contract DSNote {
event LogNote(
bytes4 indexed sig,
address indexed guy,
bytes32 indexed foo,
bytes32 indexed bar,
uint wad,
bytes fax
) anonymous;
modifier note {
bytes32 foo;
bytes32 bar;
assembly {
foo := calldataload(4)
bar := calldataload(36)
}
LogNote(msg.sig, msg.sender, foo, bar, msg.value, msg.data);
_;
}
}
contract DSStop is DSNote, DSAuth {
bool public stopped;
modifier stoppable {
require(!stopped);
_;
}
function stop() public auth note {
stopped = true;
}
function start() public auth note {
stopped = false;
}
}
contract ERC20 {
function totalSupply() public view returns (uint supply);
function balanceOf( address who ) public view returns (uint value);
function allowance( address owner, address spender ) public view returns (uint _allowance);
function transfer( address to, uint value) public returns (bool ok);
function transferFrom( address from, address to, uint value) public returns (bool ok);
function approve( address spender, uint value ) public returns (bool ok);
event Transfer( address indexed from, address indexed to, uint value);
event Approval( address indexed owner, address indexed spender, uint value);
}
contract DSMath {
function add(uint x, uint y) internal pure returns (uint z) {
require((z = x + y) >= x);
}
function sub(uint x, uint y) internal pure returns (uint z) {
require((z = x - y) <= x);
}
function mul(uint x, uint y) internal pure returns (uint z) {
require(y == 0 || (z = x * y) / y == x);
}
function min(uint x, uint y) internal pure returns (uint z) {
return x <= y ? x : y;
}
function max(uint x, uint y) internal pure returns (uint z) {
return x >= y ? x : y;
}
function imin(int x, int y) internal pure returns (int z) {
return x <= y ? x : y;
}
function imax(int x, int y) internal pure returns (int z) {
return x >= y ? x : y;
}
uint constant WAD = 10 ** 18;
uint constant RAY = 10 ** 27;
function wmul(uint x, uint y) internal pure returns (uint z) {
z = add(mul(x, y), WAD / 2) / WAD;
}
function rmul(uint x, uint y) internal pure returns (uint z) {
z = add(mul(x, y), RAY / 2) / RAY;
}
function wdiv(uint x, uint y) internal pure returns (uint z) {
z = add(mul(x, WAD), y / 2) / y;
}
function rdiv(uint x, uint y) internal pure returns (uint z) {
z = add(mul(x, RAY), y / 2) / y;
}
// This famous algorithm is called "exponentiation by squaring"
// and calculates x^n with x as fixed-point and n as regular unsigned.
//
// It's O(log n), instead of O(n) for naive repeated multiplication.
//
// These facts are why it works:
//
// If n is even, then x^n = (x^2)^(n/2).
// If n is odd, then x^n = x * x^(n-1),
// and applying the equation for even x gives
// x^n = x * (x^2)^((n-1) / 2).
//
// Also, EVM division is flooring and
// floor[(n-1) / 2] = floor[n / 2].
//
function rpow(uint x, uint n) internal pure returns (uint z) {
z = n % 2 != 0 ? x : RAY;
for (n /= 2; n != 0; n /= 2) {
x = rmul(x, x);
if (n % 2 != 0) {
z = rmul(z, x);
}
}
}
}
contract DSTokenBase is ERC20, DSMath {
uint256 _supply;
mapping (address => uint256) _balances;
mapping (address => mapping (address => uint256)) _approvals;
function DSTokenBase(uint supply) public {
_balances[msg.sender] = supply;
_supply = supply;
}
function totalSupply() public view returns (uint) {
return _supply;
}
function balanceOf(address src) public view returns (uint) {
return _balances[src];
}
function allowance(address src, address guy) public view returns (uint) {
return _approvals[src][guy];
}
function transfer(address dst, uint wad) public returns (bool) {
return transferFrom(msg.sender, dst, wad);
}
function transferFrom(address src, address dst, uint wad)
public
returns (bool)
{
if (src != msg.sender) {
_approvals[src][msg.sender] = sub(_approvals[src][msg.sender], wad);
}
_balances[src] = sub(_balances[src], wad);
_balances[dst] = add(_balances[dst], wad);
Transfer(src, dst, wad);
return true;
}
function approve(address guy, uint wad) public returns (bool) {
_approvals[msg.sender][guy] = wad;
Approval(msg.sender, guy, wad);
return true;
}
}
contract DSToken is DSTokenBase(0), DSStop {
mapping (address => mapping (address => bool)) _trusted;
bytes32 public symbol;
uint256 public decimals = 18; // standard token precision. override to customize
function DSToken(bytes32 symbol_) public {
symbol = symbol_;
}
event Trust(address indexed src, address indexed guy, bool wat);
event Mint(address indexed guy, uint wad);
event Burn(address indexed guy, uint wad);
function trusted(address src, address guy) public view returns (bool) {
return _trusted[src][guy];
}
function trust(address guy, bool wat) public stoppable {
_trusted[msg.sender][guy] = wat;
Trust(msg.sender, guy, wat);
}
function approve(address guy, uint wad) public stoppable returns (bool) {
return super.approve(guy, wad);
}
function transferFrom(address src, address dst, uint wad)
public
stoppable
returns (bool)
{
if (src != msg.sender && !_trusted[src][msg.sender]) {
_approvals[src][msg.sender] = sub(_approvals[src][msg.sender], wad);
}
_balances[src] = sub(_balances[src], wad);
_balances[dst] = add(_balances[dst], wad);
Transfer(src, dst, wad);
return true;
}
function push(address dst, uint wad) public {
transferFrom(msg.sender, dst, wad);
}
function pull(address src, uint wad) public {
transferFrom(src, msg.sender, wad);
}
function move(address src, address dst, uint wad) public {
transferFrom(src, dst, wad);
}
function mint(uint wad) public {
mint(msg.sender, wad);
}
function burn(uint wad) public {
burn(msg.sender, wad);
}
function mint(address guy, uint wad) public auth stoppable {
_balances[guy] = add(_balances[guy], wad);
_supply = add(_supply, wad);
Mint(guy, wad);
}
function burn(address guy, uint wad) public auth stoppable {
if (guy != msg.sender && !_trusted[guy][msg.sender]) {
_approvals[guy][msg.sender] = sub(_approvals[guy][msg.sender], wad);
}
_balances[guy] = sub(_balances[guy], wad);
_supply = sub(_supply, wad);
Burn(guy, wad);
}
// Optional token name
bytes32 public name = "";
function setName(bytes32 name_) public auth {
name = name_;
}
}
/// @title ERC223ReceivingContract - Standard contract implementation for compatibility with ERC223 tokens.
contract ERC223ReceivingContract {
/// @dev Function that is called when a user or another contract wants to transfer funds.
/// @param _from Transaction initiator, analogue of msg.sender
/// @param _value Number of tokens to transfer.
/// @param _data Data containig a function signature and/or parameters
function tokenFallback(address _from, uint256 _value, bytes _data) public;
/// @dev For ERC20 backward compatibility, same with above tokenFallback but without data.
/// The function execution could fail, but do not influence the token transfer.
/// @param _from Transaction initiator, analogue of msg.sender
/// @param _value Number of tokens to transfer.
// function tokenFallback(address _from, uint256 _value) public;
}
/// @dev The token controller contract must implement these functions
contract TokenController {
/// @notice Called when `_owner` sends ether to the MiniMe Token contract
/// @param _owner The address that sent the ether to create tokens
/// @return True if the ether is accepted, false if it throws
function proxyPayment(address _owner) payable public returns(bool);
/// @notice Notifies the controller about a token transfer allowing the
/// controller to react if desired
/// @param _from The origin of the transfer
/// @param _to The destination of the transfer
/// @param _amount The amount of the transfer
/// @return False if the controller does not authorize the transfer
function onTransfer(address _from, address _to, uint _amount) public returns(bool);
/// @notice Notifies the controller about an approval allowing the
/// controller to react if desired
/// @param _owner The address that calls `approve()`
/// @param _spender The spender in the `approve()` call
/// @param _amount The amount in the `approve()` call
/// @return False if the controller does not authorize the approval
function onApprove(address _owner, address _spender, uint _amount) public returns(bool);
}
contract Controlled {
/// @notice The address of the controller is the only address that can call
/// a function with this modifier
modifier onlyController { if (msg.sender != controller) throw; _; }
address public controller;
function Controlled() { controller = msg.sender;}
/// @notice Changes the controller of the contract
/// @param _newController The new controller of the contract
function changeController(address _newController) onlyController {
controller = _newController;
}
}
contract ApproveAndCallFallBack {
function receiveApproval(address from, uint256 _amount, address _token, bytes _data);
}
contract ERC223 {
function transfer(address to, uint amount, bytes data) public returns (bool ok);
function transferFrom(address from, address to, uint256 amount, bytes data) public returns (bool ok);
function transfer(address to, uint amount, bytes data, string custom_fallback) public returns (bool ok);
function transferFrom(address from, address to, uint256 amount, bytes data, string custom_fallback) public returns (bool ok);
event ERC223Transfer(address indexed from, address indexed to, uint amount, bytes data);
event ReceivingContractTokenFallbackFailed(address indexed from, address indexed to, uint amount);
}
contract ATN is DSToken("ATN"), ERC223, Controlled {
function ATN() {
setName("AT Network Token");
}
/// @notice Send `_amount` tokens to `_to` from `_from` on the condition it
/// is approved by `_from`
/// @param _from The address holding the tokens being transferred
/// @param _to The address of the recipient
/// @param _amount The amount of tokens to be transferred
/// @return True if the transfer was successful
function transferFrom(address _from, address _to, uint256 _amount
) public returns (bool success) {
// Alerts the token controller of the transfer
if (isContract(controller)) {
if (!TokenController(controller).onTransfer(_from, _to, _amount))
throw;
}
success = super.transferFrom(_from, _to, _amount);
if (success && isContract(_to))
{
// ERC20 backward compatiability
if(!_to.call(bytes4(keccak256("tokenFallback(address,uint256)")), _from, _amount)) {
// do nothing when error in call in case that the _to contract is not inherited from ERC223ReceivingContract
// revert();
// bytes memory empty;
ReceivingContractTokenFallbackFailed(_from, _to, _amount);
// Even the fallback failed if there is such one, the transfer will not be revert since "revert()" is not called.
}
}
}
/*
* ERC 223
* Added support for the ERC 223 "tokenFallback" method in a "transfer" function with a payload.
*/
function transferFrom(address _from, address _to, uint256 _amount, bytes _data)
public
returns (bool success)
{
// Alerts the token controller of the transfer
if (isContract(controller)) {
if (!TokenController(controller).onTransfer(_from, _to, _amount))
throw;
}
require(super.transferFrom(_from, _to, _amount));
if (isContract(_to)) {
ERC223ReceivingContract receiver = ERC223ReceivingContract(_to);
receiver.tokenFallback(_from, _amount, _data);
}
ERC223Transfer(_from, _to, _amount, _data);
return true;
}
/*
* ERC 223
* Added support for the ERC 223 "tokenFallback" method in a "transfer" function with a payload.
* https://github.com/ethereum/EIPs/issues/223
* function transfer(address _to, uint256 _value, bytes _data) public returns (bool success);
*/
/// @notice Send `_value` tokens to `_to` from `msg.sender` and trigger
/// tokenFallback if sender is a contract.
/// @dev Function that is called when a user or another contract wants to transfer funds.
/// @param _to Address of token receiver.
/// @param _amount Number of tokens to transfer.
/// @param _data Data to be sent to tokenFallback
/// @return Returns success of function call.
function transfer(
address _to,
uint256 _amount,
bytes _data)
public
returns (bool success)
{
return transferFrom(msg.sender, _to, _amount, _data);
}
/*
* ERC 223
* Added support for the ERC 223 "tokenFallback" method in a "transfer" function with a payload.
*/
function transferFrom(address _from, address _to, uint256 _amount, bytes _data, string _custom_fallback)
public
returns (bool success)
{
// Alerts the token controller of the transfer
if (isContract(controller)) {
if (!TokenController(controller).onTransfer(_from, _to, _amount))
throw;
}
require(super.transferFrom(_from, _to, _amount));
if (isContract(_to)) {
ERC223ReceivingContract receiver = ERC223ReceivingContract(_to);
receiver.call.value(0)(bytes4(keccak256(_custom_fallback)), _from, _amount, _data);
}
ERC223Transfer(_from, _to, _amount, _data);
return true;
}
/*
* ERC 223
* Added support for the ERC 223 "tokenFallback" method in a "transfer" function with a payload.
*/
function transfer(
address _to,
uint _amount,
bytes _data,
string _custom_fallback)
public
returns (bool success)
{
return transferFrom(msg.sender, _to, _amount, _data, _custom_fallback);
}
/// @notice `msg.sender` approves `_spender` to spend `_amount` tokens on
/// its behalf. This is a modified version of the ERC20 approve function
/// to be a little bit safer
/// @param _spender The address of the account able to transfer the tokens
/// @param _amount The amount of tokens to be approved for transfer
/// @return True if the approval was successful
function approve(address _spender, uint256 _amount) returns (bool success) {
// Alerts the token controller of the approve function call
if (isContract(controller)) {
if (!TokenController(controller).onApprove(msg.sender, _spender, _amount))
throw;
}
return super.approve(_spender, _amount);
}
function mint(address _guy, uint _wad) auth stoppable {
super.mint(_guy, _wad);
Transfer(0, _guy, _wad);
}
function burn(address _guy, uint _wad) auth stoppable {
super.burn(_guy, _wad);
Transfer(_guy, 0, _wad);
}
/// @notice `msg.sender` approves `_spender` to send `_amount` tokens on
/// its behalf, and then a function is triggered in the contract that is
/// being approved, `_spender`. This allows users to use their tokens to
/// interact with contracts in one function call instead of two
/// @param _spender The address of the contract able to transfer the tokens
/// @param _amount The amount of tokens to be approved for transfer
/// @return True if the function call was successful
function approveAndCall(address _spender, uint256 _amount, bytes _extraData
) returns (bool success) {
if (!approve(_spender, _amount)) throw;
ApproveAndCallFallBack(_spender).receiveApproval(
msg.sender,
_amount,
this,
_extraData
);
return true;
}
/// @dev Internal function to determine if an address is a contract
/// @param _addr The address being queried
/// @return True if `_addr` is a contract
function isContract(address _addr) constant internal returns(bool) {
uint size;
if (_addr == 0) return false;
assembly {
size := extcodesize(_addr)
}
return size>0;
}
/// @notice The fallback function: If the contract's controller has not been
/// set to 0, then the `proxyPayment` method is called which relays the
/// ether and creates tokens as described in the token controller contract
function () payable {
if (isContract(controller)) {
if (! TokenController(controller).proxyPayment.value(msg.value)(msg.sender))
throw;
} else {
throw;
}
}
//////////
// Safety Methods
//////////
/// @notice This method can be used by the controller to extract mistakenly
/// sent tokens to this contract.
/// @param _token The address of the token contract that you want to recover
/// set to 0 in case you want to extract ether.
function claimTokens(address _token) onlyController {
if (_token == 0x0) {
controller.transfer(this.balance);
return;
}
ERC20 token = ERC20(_token);
uint balance = token.balanceOf(this);
token.transfer(controller, balance);
ClaimedTokens(_token, controller, balance);
}
////////////////
// Events
////////////////
event ClaimedTokens(address indexed _token, address indexed _controller, uint _amount);
}
招新小广告
ChaMd5 Venom 招收大佬入圈
新成立组IOT+工控+样本分析 长期招新
原文始发于微信公众号(ChaMd5安全团队):智能合约:整数溢出、访问控制缺陷漏洞与跨合约调用漏洞