Home Blockchain Solidity漏洞 拒绝服务攻击
Post
Cancel

Blockchain Solidity漏洞 拒绝服务攻击

这个类别非常宽泛,但从根本上来说,它的本质是,让用户可以在一小段时间内,或者在某些情况下永久性地无法使用合约。这可能会永远困住这些合约中的以太币,就像第二次Parity MultiSig黑客攻击那样。

坑点分析

我们知道,智能合约可以通过多种手段使其变得不可操作。在这里,我将只强调一些可能在区块链中不太明显的Solidity编码方式,这些模式可能导致攻击者发起DOS攻击。

主要包括以下几种。

  1. 通过外部操作的映射或数组循环。在我的经验中,这种方式的攻击见得太多了。通常情况下,它出现在一个owner希望向他们的投资者分发代币的时候,并且使用了一个与distribute()类似的函数。参见下面代码: image

在这个合约中,它的循环在一个可以被人为放大的数组上运行。攻击者可以创建许多个用户的账户,从而使investor数组更大。攻击者可以通过这样操作做,使执行for循环所需gas超过区块的gas限制,从而使distribute()函数变得不可操作。

  1. 所有者操作。所有者在合约中享有特殊特权,并且必须执行一些任务,以便合约进入到下一个状态。一个例子就是一个ICO合约,它要求所有者通过finalize()函数进行操作,使代币可以转让。例如: image

在这种情况下,如果一个特权用户丢失了他们的密钥,或者变得不活跃,则整个合约就会变得不可操作。而且,如果owner无法调用finalize ()函数,就没有可以转移的代币;也就是说,代币生态系统的整个运行都取决于一个单一的地址。

  1. 基于外部调用的进度状态。合约有时是这样写的,为了进入一个新的状态,需要将以太发币送到一个地址,或者等待外部来源的一些输入。当外部调用失败时,或者由于外部原因而被阻止的时候,这些模式可能导致DOS攻击。

在发送以太币的例子中,用户可以创建一个不接受以太币的合约。如果一份合约需要将以太币送到这个地址,以便进入一个新的状态的话,那么合约永远不会达到这一新状态,因为以太币永远不可能被送到合约中。

避坑技巧

在第一个例子中,合约不应该在由外部用户人为操纵的数据结构中循环。可以使用withdrawal,即每个投资者都调用一个撤回函数来独立地声明代币。

在上面的第二个例子中,要求特权用户更改合约状态。在这个例子中,当owner丧失能力时,可以使用故障保护装置。一个解决方案是将owner设置为一个多重签名合约。

另一个解决方案是使用一个时间锁,其中需要在第13行代码中,包括一个基于时间的机制,比如

require(msg.sender == owner   now > unlockTime)

这允许任何用户在一段时间之后最终确认,该时间由unlockTime指定。这种方法也可以用在第三个例子中。

如果需要外部调用才能进入一个新状态的话,则要考虑到它们可能出现的故障,并可能增加一个基于时间的状态进程,否则所希望的调用可能永远不会出现。

真实案例:GovernMental

GovernMental是一个老式的庞氏骗局,积累了大量的以太币。不幸的是,它很容易受到本节中提到的DOS漏洞的影响。

一个 Reddit 帖子描述了合约是如何要求删除一个大的映射,这种映射的删除导致当时的gas成本超过了区块gas的限制,因此无法取回以太币。

合约地址是:

0xF45717552f12Ef7cb65e95476F217Ea008167Ae3

可以从

0x0d80d67202bd9cb6773df8dd2020e7190a1b0793e8ec4fc105257e8128f0506b

中看到交易,最终得到所有以太币共使用了2.5M gas。

This post is licensed under CC BY 4.0 by the author.