智能合约:Call注入攻击

2018-06-22  本文已影响0人  安福院长

基础知识

Call是一个底层的接口,用来向第三方合约发送消息以此完成第三方合约中内部函数的调用,调用的方式大致如下

方式一:call(方法选择器, arg1, arg2, …) 方式二:call(bytes)

第一种通过参数传递的方式调用,将方法选择器,参数进行传递,其中方法选择器是4个字节,通过bytes4(keccak256(func()))生成。第二种方式直接调用,bytes数据由自己来构建,标准场景如下:

pragma solidity ^0.4.10;

contract ContractA{

    event Result(bool);

    function extCall(address _sc) {

        bool ret = _sc.call(bytes(keccak256("func()")));

        Result(ret);

    }

}

contract ContractB {

    function func() { revert();}

}

攻击场景

注入漏洞可以从三个方向进行攻击

1. 参数列表

2. 方法选择器

3. bytes

下面我们将进行bytes注入方式模拟攻击

function approveAndCallCode(address _spender, uint256 _value, bytes _extraData) public returns(bool) {

    ...

    if(!_spender.call(_extraData)) { revert();}

    ...

}

function transfre(address _to, uint256 _value) public returns (bool) {

    ...

}

在合约代码函数 approveAndCallCode中,通过_spender.call 调用_spender合约的某些方法并传递一些数据。

如果_spender为合约自身的地址,那么就可以调用本合约内部的方法,比如调用transfer方法,通过构造bytes数据,可以将_to 地址指向本身账户地址,通过这种方式就可以将合约账户中的代币轻而易举转到自己账户中。

ERC223标准为了解决ERC20中的一些潜在问题而出的升级版,但很多ERC223的标准实现中就带入了Call注入问题

总结

针对call本身所存在的一些潜在风险,在合约中尽量避免使用call的方式调用,如果一定要执行的话,则可以对方法选择器的字符串进行强制的限制。

参考

http://solidity.readthedocs.io/en/v0.4.21/units-and-global-variables.html#special-variables-and-functions

上一篇 下一篇

猜你喜欢

热点阅读