The DAO hack and recursive calling vulnerability in Ethereum

It’s been more than a year since an attacker drained 3.5 million Ether from The DAO, which was an Ethereum-based autonomous organization formed with the purpose of funding projects in a decentralized way.

What is a decentralized autonomous organization (DAO)?

In short, a DAO is just what it sounds like. It takes jobs that are traditionally done by laws, contracts, and employees within a company and encodes them on the blockchain. A DAO allows for decentralized governance, distribution of funds, trust-less relationships between members, and anonymous participation.

The particular DAO that was hacked last year was, at the time, the largest crowdfunding event ever. By mid-May 2016 The DAO had raised over $100 million and was making daily headline news.

One unique thing to point out about this particular DAO is that it allowed token holders to “split” it, and this could happen for one of two reasons:

  1. The token holder disagreed with the current system of governance, or
  2. The token holder wanted to raise funds for a project

Essentially the intent was to allow token holders to vote on a split – after a successful split those who voted YES are granted their portion of DAO tokens in the form of Ether to the new child DAO. From https://github.com/slockit/DAO

This process will destroy all his tokens and move his portion of the Ether (note: the extraBalance is not part of that) owned by the original DAO and his portion of the rewardTokens (used to retrieve his portion of the future rewards) to the new DAO.

The attack that happened last year occurred because of a vulnerability within this splitting mechanism.

The DAO hack – recursive calling vulnerability

function splitDAO(uint _proposalID,address _newCurator) noEther onlyTokenholders returns (bool _success) {

As mentioned above, the entry point for this attack within the DAO contract was the above function, which essentially allowed a token holder (noteonlyTokenholders) to place their support for a particular_proposalID.

No particular amount is specified when requesting to split the DAO, however the beginning of the function does a series of checks to determine the amount of DAO tokens held, and whether or not to proceed with the split. These details can be omitted.

  withdrawRewardFor(msg.sender); // A
  totalSupply -= balances[msg.sender]; // B
  balances[msg.sender] = 0; // C

The code snippet above is an important piece of the attack, and is the part of splitDAO that contributed to the hack on The DAO. Note that the line marked with B and C are adjusting token balances as a result of the call to withdrawRewardFor.  The security-minded reader may have noticed that, if bad things happen in this call, there is a chance that B and C may not be called after a semi-successful A. Let’s take a look at withdrawRewardFor.

    function withdrawRewardFor(address _account) noEther internal returns (bool _success) {
        ...
        uint reward = ...
        if (!rewardAccount.payOut(_account, reward))
            throw;
        paidOut[_account] += reward;
        return true;
    }

Ok, let’s step intopayOut:

    function payOut(address _recipient, uint _amount) returns (bool) {
        ...
        if (_recipient.call.value(_amount)()) {
            ...
        }
        ...
    } 

So it’s important to understand the behavior of call in order to see how we might construct an attack around this contract. You can read an overview of call here, but a good recommendation from this blog post is:

Do not call arbitrary contract code in your contract using Solidity’s call construct, ever if you can avoid it.  If you can’t, do it last and understand that you lose guarantees as to the program flow of your contract at that point.

The DAO did exactly this, and as a result we can construct a pretty simple attack wallet with the following fallback function:

function () {
   // Note that the following statement can only be called recursively
   // a limited number of times to prevent running out of gas or
   // exceeding the call stack
   call TheDAO.splitDAO(...)
}

From the Solidity FAQ:

[The fallback function] is called when someone just sent Ether to the contract without providing any data or if someone messed up the types so that they tried to call a function that does not exist.

BAM.

_recipient.call.value(_amount)() is returning execution to the calling contract, which is the attacker’s wallet. At this point, execution is entirely in the hands of the attacker, who has mischievously called splitDAO right from within the fallback function. Because _recipient.call.value(_amount)() is not providing any data, the fallback function is called.

Issues leading to The DAO hack

There were really two problems here:

  1. Funds were actually moved before accounts were balanced. This led to confusion as to amount and distribution of existing tokens.
  2. Misuse of the call function. This took execution out of the control of the The DAO contract, allowing for the arbitrary execution of code. In this case, the split was able to happen time and time again, while the actual account balance adjustments never took place.

Aftermath of The DAO hack

The debate that The DAO hack sparked is out of the scope of this article, but those who are interested might want to look into the motivation behind Ethereum Classic. But this is a post for another day…

Happy coding, and stay safe out there!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s