以太坊智能合约的特点之一是能够调用和利用来自其他外部合约的代码。 合约通常也处理以太,并且经常将以太发送到各种外部用户地址。这些操作要求合约提交外部调用。这些外部调用可能会被攻击者劫持,攻击者可以强制合约执行进一步的代码(通过一个回退函数),包括对自身的调用。 这类攻击被用于臭名昭著的DAO攻击。 了解漏洞这种类型的攻击可能发生在合约将以太发送到未知地址时。攻击者可以在回退函数中小心地在包含恶意代码的外部地址上构造合约。 因此,当一个合约将以太发送到这个地址时,它将调用恶意代码。通常,恶意代码会在易受攻击的合约上执行一个函数,执行开发人员意想不到的操作。 术语“可重入性”源于此:外部恶意合约调用了易受攻击的合约上的一个函数,代码执行的路径“重新进入”了它。 为了澄清这一点,考虑一下易受攻击的EtherStore.sol,作为一个以太坊金库,存款人每周只能提取1个以太: EtherStore.sol 这个合约有两个公共功能,depositFunds和withdrawFunds。 depositFunds函数只是增加发送方的余额。 withdrawFunds函数允许发送者指定要取款的wei。 只有当请求提取的金额小于1 个以太,且上周没有发生提取时,此函数才会成功。 漏洞在第17行,合约向用户发送了他们想要的以太的数量。 考虑一个在Attack.sol中创建合约的攻击者: Attack.sol 漏洞可能如何发生? 首先,攻击者会用EtherStore的合约地址作为唯一的构造函数参数来创建恶意合约(假设地址是0x0…123)。这将初始化并将公共变量etherStore指向要被攻击的合约。 然后攻击者会调用attackEtherStore函数,使用一些大于或等于1的以太——让我们暂时假设是1个以太。 在这个例子中,我们还假设许多其他用户已经将以太存入了这个合约,因此它的当前余额是10 以太。然后将发生以下情况:
|