7

I understand that if theDAO contract has a withdrawal function that sends money to contract X - contract X can be malicious and use the fallback function to call the withdrawal function again. However - in the case of theDAO contract X was another copy of theDAO so it did not had this malicious behaviour.

So how exactly was the recursive send possible?

5

This is the problematic line of code in the withdrawRewardFor function:

    if (!rewardAccount.payOut(_account, reward)) <-- reentrant exploit
         throw;
    paidOut[_account] += reward;

The payOut will call the recipient payout function:

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

If _recipient is a contract this will call the contract's fallback function. This recipient in turn can call TheDao contract again. Since withdrawRewardFor was not protected against reentrancy it was allowed again. This meant continuous payout before the code was allowed to continue with paidOut[_account] += reward; and beyond.

The article More Ethereum Attacks: Race-To-Empty is the Real Deal, which was written one week before the attack, has a more detailed analysis of this type of hack, and proposed solutions.

1

To answer your question, you need to differentiate between Contracts and Proposals.

The DAO is a Contract that codifies rules to make funds available via Proposals.

A proposal could be a request for investment, or a request to withdraw your own funds (this is called Split Proposal). When a split proposal is approved, it calls splitDAO API to create a child DAO (child contract). The code of this child contract is indeed identical to the original DAO.

The splitDAO function transfers the requested funds to the child DAO. But it also calls a default function provided by the proposal, ostensibly to handle the funds being transferred. And this function is called right after the fund-transfer operation, but before the funds are deducted from the total balance of DAO and before user balance is set to zero.

The recursive exploit was embedded in this default function. It simply called splitDAO again.

In reality, the transfer of funds, reduction of total balance and setting user balance to zero should have been an atomic operation. Other methods (locks, mutexes) could also have been implemented to ensure the entire splitting operation is completed before any external, user-provided code is executed.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.