智能合约之短地址攻击

在了解以太坊智能合约短地址攻击之前,先要简单了解一下以太坊代币ERC-20 TOKEN 的一些基础知识。ERC(EthereumRequest for Comment)即以太坊通用征求意见协议,开发者可以通过提交EIP(Ethereum Improvement Proposal以太坊改进建议),向以太坊社区提交新的ERC标准提案。ERC-20是整个加密社区中的所有标准中名气最大的,而且大多数基于以太坊平台发布的token都基于ERC-20协议。ERC-20 TOKEN标准中,提供了一些基础函数,如下:

// Abstract contract for the full ERC 20 Token standard
// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md
pragma solidity ^0.4.21;


contract EIP20Interface {
    /* This is a slight change to the ERC20 base standard.
    function totalSupply() constant returns (uint256 supply);
    is replaced with:
    uint256 public totalSupply;
    This automatically creates a getter function for the totalSupply.
    This is moved to the base contract since public getter functions are not
    currently recognised as an implementation of the matching abstract
    function by the compiler.
    */
    /// total amount of tokens
    uint256 public totalSupply;

    /// @param _owner The address from which the balance will be retrieved
    /// @return The balance
    function balanceOf(address _owner) public view returns (uint256 balance);

    /// @notice send `_value` token to `_to` from `msg.sender`
    /// @param _to The address of the recipient
    /// @param _value The amount of token to be transferred
    /// @return Whether the transfer was successful or not
    function transfer(address _to, uint256 _value) public returns (bool success);

    /// @notice send `_value` token to `_to` from `_from` on the condition it is approved by `_from`
    /// @param _from The address of the sender
    /// @param _to The address of the recipient
    /// @param _value The amount of token to be transferred
    /// @return Whether the transfer was successful or not
    function transferFrom(address _from, address _to, uint256 _value) public returns (bool success);

    /// @notice `msg.sender` approves `_spender` to spend `_value` tokens
    /// @param _spender The address of the account able to transfer the tokens
    /// @param _value The amount of tokens to be approved for transfer
    /// @return Whether the approval was successful or not
    function approve(address _spender, uint256 _value) public returns (bool success);

    /// @param _owner The address of the account owning tokens
    /// @param _spender The address of the account able to transfer the tokens
    /// @return Amount of remaining tokens allowed to spent
    function allowance(address _owner, address _spender) public view returns (uint256 remaining);

    // solhint-disable-next-line no-simple-event-func-name
    event Transfer(address indexed _from, address indexed _to, uint256 _value);
    event Approval(address indexed _owner, address indexed _spender, uint256 _value);
}

下面来简单介绍一下各个函数的功能:
balanceOf() :查询_owner地址持有的Token数量
transfer() :从msg.sender地址发送_value Token到_to地址
transferFrom():从_from的地址发送_value Token到_to地址
approve():Token所有者可以调用这个函数授权spender代表它使用value数量的token
allowance():用来查看owner给spender的token剩余额度

以上是ERC-20 TOKEN实现的一些基础函数,在进行Token转账时,最常用到的是 transfer() 函数,下面将举个例子讲解该函数实现Token转账的方法。比如向0x15022eCbc4Fc993d1Fd179A41F7b985fA9C0b787地址发送一个Token,其最终向EVM提交的数据制作过程如下:
function transfer(address to, uint tokens) public returns (bool success);
其sha3的前4个字节数据为:a9059cbb

Token转账的地址为32字节,高位用0填充:
00000000000000000000000015022eCbc4Fc993d1Fd179A41F7b985fA9C0b787

转账代币的数量为32字节,1个TOKEN:
00000000000000000000000000000000000000000000000000000000000000001

最终向EVM移交的数据为:

a9059cbb00000000000000000000000015022eCbc4Fc993d1Fd179A41F7b985fA9C0b78700000000000000000000000000000000000000000000000000000000000000001

以上是对ERC-20协议的TOKEN以及转账数据生成过程的介绍,接下里就来介绍一下重点,短地址攻击的过程。先看一个简单的示例代码:

pragma solidity ^0.4.21;

contract Short AddressAttack{
	 mapping(address => uint) public balances;
	 event transfer(address indexed _from,address indexed  _to, uint256 _value);
	
	function AddressAttack() {
		balances[msg.sender] = 1000;
	}
	
	function transfer(address _to, uint256 _value) public returns (bool success){
		if(balances[msg.sender] <  _value)  return false;
		if(_value <  0)  return false;
		
		balances[msg.sender]  -=  _value;
		balances[ _to]  +=  _value;
		event transfer(msg.sender,_to,_value);
		return ture;
	}
}

其实短地址攻击,就是转账接受方的地址最后一个字节为0(其实最后结束以字节0结尾的字节数越多越好),在转账的时候,恶意去掉接收方地址最后的0字节数据,让EVM自己自动去补全,攻击过程如下:
调用函数前4个字节:a9059cbb
转账地址:00000000000000000000000015022eCbc4Fc993d1Fd179A41F7b985fA9C0b700
转账数额:00000000000000000000000000000000000000000000000000000000000000001

如果恶意将转账地址的最后一个字节0去掉,其数据如下:
调用函数前4个字节:a9059cbb
转账地址:00000000000000000000000015022eCbc4Fc993d1Fd179A41F7b985fA9C0b7
转账数额:00000000000000000000000000000000000000000000000000000000000000001
生成的交易数据:

a9059cbb00000000000000000000000015022eCbc4Fc993d1Fd179A41F7b985fA9C0b700000000000000000000000000000000000000000000000000000000000000001

数据到EVM中解析进行数据还原:

调用函数前4个字节:a9059cbb
转账地址32字节:00000000000000000000000015022eCbc4Fc993d1Fd179A41F7b985fA9C0b700
转账数额32字节:000000000000000000000000000000000000000000000000000000000000001
EVM会依据规则对数据进行解析,上述你会发现,转账地址最后两位由转账数额进行替补上,那么转账数额少一个字节怎么处理呢?
在EVM中有自动补全的机制,少多少字节全部填充0,j填充后的转账金额如下:
转账数额32字节:00000000000000000000000000000000000000000000000000000000000000100

到这里发现没有,本来仅仅转账1个TOEKN,经过攻击后转账256个TOKEN,这个就是短地址攻击的原理。

针对这个漏洞,说实话以太坊有不可推卸的责任,因为EVM并没有严格校验地址的位数,并且还擅自自动补充消失的位数。此外,交易所在提币的时候,需要严格校验用户输入的地址,这样可以尽早在前端就禁止掉恶意的短地址。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值