漏洞原理

以太坊智能合约的特点之一是能够调用和使用其他外部合约的代码。这些合约通常会操作以太币,经常将以太发送到各种外部用户地址。这种调用外部合约或向外部地址发送以太币的操作,需要合约提交外部调用。这些外部调用可能被攻击者劫持,比如,通过一个回退函数,强迫合约执行进一步的代码,包括对自身的调用。这样代码可以重复进入合约,这就是“重入” (Re-Entrancy) 的来源。著名的 DAO 黑客攻击事件中就是利用了这种类型的漏洞。

以下 Solidity 知识点能帮助我们更好的理解重入攻击的内在原因。

Fallback函数

合约可以有一个未命名的函数。这个函数不能有参数也不能有返回值。 如果在一个到合约的调用中,没有其他函数与给定的函数标识符匹配(或没有提供调用数据),那么这个函数(fallback 函数)会被执行。

除此之外,每当合约收到以太币(没有任何数据),这个函数就会执行。此外,为了接收以太币,fallback 函数必须标记为 payable。 如果不存在这样的函数,则合约不能通过常规交易接收以太币。

一个没有定义 fallback 函数的合约,直接接收以太币(没有函数调用,即使用 sendtransfer)会抛出一个异常, 并返还以太币。所以如果你想让你的合约接收以太币,必须实现 fallback 函数。

而且,一个合约不能对这种以太币转移做出反应,因此也不能拒绝它们。这是 EVM 在设计时就决定好的,而且 Solidity 无法绕过这个问题。

Call 函数调用

在 Solidity 中,call 函数簇