3分钟Solidity: 11.9 用外部合约隐藏恶意代码

28 阅读1分钟

欢迎订阅专栏3分钟Solidity--智能合约--Web3区块链技术必学

如需获取本内容的最新版本,请参见 Cyfrin.io 上“隐藏带有外部合同的恶意代码(代码示例)”

漏洞

在Solidity中,任何地址都可以被强制转换为特定合约类型,即使该地址上的合约并非目标合约。

这一特性可被利用来隐藏恶意代码。下面我们来看看具体是如何实现的。

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;

/*
假设Alice能看到Foo和Bar的代码,但看不到Mal的代码。
对Alice来说,显然Foo.callBar()会执行Bar.log()中的代码。
然而Eve部署Foo时使用了Mal的地址,因此调用Foo.callBar()
实际上会执行Mal中的代码。
*/

/*
1.  Eve部署了恶意程序Mal
2.  Eve以Mal的地址部署了Foo
3.  Alice阅读代码后判定调用安全,调用了Foo.callBar()
4.  虽然Alice预期会执行Bar.log(),但实际执行的是Mal.log()
*/

contract Foo {
    Bar bar;

    constructor(address _bar) {
        bar = Bar(_bar);
    }

    function callBar() public {
        bar.log();
    }
}

contract Bar {
    event Log(string message);

    function log() public {
        emit Log("Bar was called");
    }
}

// 这段代码隐藏在一个单独的文件中
contract Mal {
    event Log(string message);

    // function () external {
    //     emit Log("Mal was called");
    // }

    // 实际上,即使这个函数不存在,我们也可以通过使用回退机制来执行相同的攻击
    function log() public {
        emit Log("Mal was called");
    }
}

预防性技术

  • 在构造函数内初始化新合约
  • 将外部合约的地址设为public,以便审查外部合约的代码
Bar public bar;

constructor() public {
    bar = new Bar();
}

Try on Remix试用混音版