1

Hello everyone i am new to solidity coding, and i want to improve my security skill regarding smart contracts and evm. In order to accomplish this goal i tried a reentrancy attack on a simple contract.

So i modified the code of the function confirmReceived(), to make it vulnerable to reentrancy.

function confirmReceived()
    external
    onlyBuyer
    inState(State.Locked)
{
    emit ItemReceived();

    buyer.transfer(value);

    state = State.Release; // changed the state after transfer on purpose
}

Then i deployed the attack contract.

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;
import "../contracts/Purchase.sol";
contract Attacker {

    Purchase public purchase;

    constructor(address _purchaseaddress) {
        purchase = Purchase(_purchaseaddress);
    }


    function attack () public payable {

        if (address(purchase).balance > 1) {
            purchase.confirmReceived();
        }
    }
    receive() external payable {
            attack();
    }

    function fundPurchase() external payable {
        purchase.confirmPurchase{value: msg.value}();
    }
}

Then i migrated everything on the local ganache blockchain, and put the code to work. However when i try on the truffle console to invoke the attack function, i get a revert from the EVM, without any information of what went wrong.

truffle(ganache)> let a = await Attacker.deployed()
undefined
truffle(ganache)> a.fundPurchase({value: web3.utils.toWei('20'), from: '0x4950BbA09D1031e34402Ed2e392B2c715a9Beb23'})
{
  tx: '0x2f6f84b4b2fe36a580ffae1ed4ab134352bda7e6f7963be8e491113a6e8a8d50',
  receipt: {
    transactionHash: '0x2f6f84b4b2fe36a580ffae1ed4ab134352bda7e6f7963be8e491113a6e8a8d50',
    transactionIndex: 0,
    blockNumber: 3,
    blockHash: '0x0f9de1629180488614d37ed1a5b3d26599dca6cd2efd957d3edaf4c539ccb78b',
    from: '0x4950bba09d1031e34402ed2e392b2c715a9beb23',
    to: '0xbf77e92e3a1cd9beb3696d97892bd9d19f96cae8',
    cumulativeGasUsed: 58993,
    gasUsed: 58993,
    contractAddress: null,
    logs: [],
    logsBloom: '0x00000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000',
    status: true,
    effectiveGasPrice: 3193906734,
    type: '0x2',
    rawLogs: [ [Object] ]
  },
  logs: []
}
truffle(ganache)> a.attack()
Uncaught Error: VM Exception while processing transaction: revert
    at evalmachine.<anonymous>
    at sigintHandlersWrap (node:vm:270:12)
    at Script.runInContext (node:vm:139:14)
    at runScript (C:\Users\Art\AppData\Roaming\nvm\v18.14.2\node_modules\truffle\build\webpack:\packages\core\lib\console.js:505:1)
    at Console.interpret (C:\Users\Art\AppData\Roaming\nvm\v18.14.2\node_modules\truffle\build\webpack:\packages\core\lib\console.js:520:1)
    at bound (node:domain:433:15)
    at REPLServer.runBound [as eval] (node:domain:444:12)
    at REPLServer.onLine (node:repl:902:10)
    at REPLServer.emit (node:events:513:28)
    at REPLServer.emit (node:domain:489:12)
    at REPLServer.[_onLine] [as _onLine] (node:internal/readline/interface:422:12)
    at REPLServer.[_line] [as _line] (node:internal/readline/interface:892:18)
    at REPLServer.[_ttyWrite] [as _ttyWrite] (node:internal/readline/interface:1270:22)
    at REPLServer.self._ttyWrite (node:repl:997:9)
    at ReadStream.onkeypress (node:internal/readline/interface:270:20)
    at ReadStream.emit (node:events:513:28)
    at ReadStream.emit (node:domain:489:12)
    at emitKeys (node:internal/readline/utils:357:14)
    at emitKeys.next (<anonymous>)
    at ReadStream.onData (node:internal/readline/emitKeypressEvents:64:36) {
  code: -32000,
  data: {
    hash: null,
    programCounter: 340,
    result: '0x',
    reason: null,
    message: 'revert'
  },
  reason: undefined,
  hijackedStack: 'Error: VM Exception while processing transaction: revert\n' +
    '    at C:\\Users\\Art\\AppData\\Roaming\\nvm\\v18.14.2\\node_modules\\truffle\\build\\webpack:\\packages\\provider\\wrapper.js:25:1\n' +
    '    at C:\\Users\\Art\\AppData\\Roaming\\nvm\\v18.14.2\\node_modules\\truffle\\build\\webpack:\\packages\\provider\\wrapper.js:165:1\n' +
    '    at C:\\Users\\Art\\AppData\\Roaming\\nvm\\v18.14.2\\node_modules\\truffle\\build\\webpack:\\node_modules\\web3-providers-http\\lib\\index.js:127:1\n' +
    '    at processTicksAndRejections (node:internal/process/task_queues:95:5)'
}
truffle(ganache)>

I tried searching for solutions, but i did not find any, except maybe for the fact that the receive() function is asynchronous, but then how would I suppose to do the reeentrancy?

Thanks a lot guys, any help is appreciated.

1
  • Try increasing the transaction gas, the gas used 58993 seems too low. Another thing you could try is to exit if gas is low.
    – Ismael
    Commented Mar 22, 2023 at 20:08

1 Answer 1

1

To send Ether to other contracts, you can use these three methods:

  1. transfer (2300 gas, throws an error)
  2. send (2300 gas, returns bool)
  3. call (forward all gas or set gas, returns bool)

To ensure successful execution, it's recommended to use call, as transfer and send do not allow you to forward gas, causing the execution to stop when most of the gas is used.

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.