返回论坛

干货 | Solidity 安全:已知攻击方法和常见防御模式综合列表,Part-1

查找币 漏洞披露 安全研究 Web3安全 区块链安全

查找币安全研究院

钱包恢复评估 | 链上取证分析 | Web3 事件响应
以合法授权、证据保全、隐私保护和可复核流程为前提,不要求用户在线提交完整私钥或助记词。

查看研究院 研究报告中心
## 干货 | Solidity 安全:已知攻击方法和常见防御模式综合列表,Part-1 本文由查找币安全团队基于安全研究整理发布,旨在分享Web3安全技术,帮助用户提高安全意识。 --- 原文链接: https://blog.sigmaprime.io/solidity-security.html 作者: Dr Adrian Manning 翻译&校对: 爱上平顶山@查找币安全团队 & keywolf@查找币安全团队 致谢(校对):yudan、阿剑@EthFans 本文由查找币安全团队翻译,这里是最新译文的 GitHub 地址:。 虽然处于起步阶段,但是 Solidity 已被广泛采用,并被用于编译我们今天看到的许多以太坊智能合约中的字节码。相应地,开发者和用户也获得许多严酷的教训,例如发现语言和EVM的细微差别。这篇文章旨在作为一个相对深入和最新的介绍性文章,详述 Solidity 开发人员曾经踩过的坑,避免后续开发者重蹈覆辙。 重入漏洞 以太坊智能合约的特点之一是能够调用和利用其他外部合约的代码。合约通常也处理 Ether,因此通常会将 Ether 发送给各种外部用户地址。调用外部合约或将以太网发送到地址的操作需要合约提交外部调用。这些外部调用可能被攻击者劫持,迫使合约执行进一步的代码(即通过回退函数),包括回调自身。因此代码执行“重新进入”合约。这种攻击被用于臭名昭著的 DAO 攻击。 有关重入攻击的进一步阅读,请参阅对智能合约的重入式攻击和 Consensus - 以太坊智能合约最佳实践(译者注:中译本见文末超链接)。 漏洞 当合约将 Ether 发送到未知地址时,可能会发生此攻击。攻击者可以在 Fallback 函数中的外部地址处构建一个包含恶意代码的合约。因此,当合约向此地址发送 Ether 时,它将调用恶意代码。通常,恶意代码会在易受攻击的合约上执行一个函数、该函数会运行一项开发人员不希望的操作。“重入”这个名称来源于外部恶意合约回复了易受攻击合约的功能,并在易受攻击的合约的任意位置“重新输入”了代码执行。 为了澄清这一点,请考虑简单易受伤害的合约,该合约充当以太坊保险库,允许存款人每周只提取 1 个 Ether。 EtherStore.sol: contract EtherStore {    uint256 public withdrawalLimit = 1 ether;    mapping(address => uint256) public lastWithdrawTime;    mapping(address => uint256) public balances;    function depositFunds() public payable {        balances[msg.sender] += msg.value;    }    function withdrawFunds (uint256 _weiToWithdraw) public {        require(balances[msg.sender] >= _weiToWithdraw);        // limit the withdrawal        require(_weiToWithdraw <= withdrawalLimit);        // limit the time allowed to withdraw        require(now >= lastWithdrawTime[msg.sender] + 1 weeks);        require(msg.sender.call.value(_weiToWithdraw)());        balances[msg.sender] -= _weiToWithdraw;        lastWithdrawTime[msg.sender] = now;    } } 该合约有两个公共职能。 depositFunds() 和 withdrawFunds() 。该 depositFunds() 功能只是增加发件人余额。该 withdrawFunds() 功能允许发件人指定要撤回的 wei 的数量。如果所要求的退出金额小于 1Ether 并且在上周没有发生撤回,它才会成功。额,真会是这样吗?... 该漏洞出现在 [17] 行,我们向用户发送他们所要求的以太数量。考虑一个恶意攻击者创建下列合约, Attack.sol: import "EtherStore.sol"; contract Attack {  EtherStore public etherStore;  // intialise the eth [...内容已精简...] msg.sender] = balances[msg.sender].add(msg.value);        lockTime[msg.sender] = now.add(1 weeks);    }    function increaseLockTime(uint256 _secondsToIncrease) public {        lockTime[msg.sender] = lockTime[msg.sender].add(_secondsToIncrease);    }    function withdraw() public {        require(balances[msg.sender] > 0);        require(now > lockTime[msg.sender]);        balances[msg.sender] = 0;        msg.sender.transfer(balances[msg.sender]);    } } 请注意,所有标准的数学运算已被 SafeMath 库中定义的数学运算所取代。该 TimeLock 合约不会再执行任何能够导致下溢/上溢的操作。 实际示例:PoWHC 和批量传输溢出(CVE-2018-10299) 一个 4chan 小组认为,用 Solidity 在 Ethereum上 构建一个庞氏骗局是个好主意。他们称它为弱手硬币证明(PoWHC)。不幸的是,似乎合约的作者之前没有看到上溢/下溢问题,因此,866Ether 从合约中解放出来。Eric Banisadar 的文章对下溢是如何发生的作出了很好的概述(这与上面的 Ethernaut 挑战不太相似)。 一些开发人员还为一些 ERC20 Token 合约实施了一项 batchTransfer() 函数。该实现包含溢出。这篇文章对此进行了解释,但是我认为标题有误导性,因为它与 ERC20 标准无关,而是一些 ERC20 Token 合约实现了易受攻击的 batchTransfer() 函数。 --- *本文由查找币安全团队整理,来源:安全研究。*
在论坛中查看和回复