Skip to content

Instantly share code, notes, and snippets.

@nathan-websculpt
Created September 22, 2021 15:55
Show Gist options
  • Save nathan-websculpt/eafd85362f0969814cc1e5060fbb5c2d to your computer and use it in GitHub Desktop.
Save nathan-websculpt/eafd85362f0969814cc1e5060fbb5c2d to your computer and use it in GitHub Desktop.
This example shows a simple Reentrancy Guard in action. Even though the balance is not zero-ed out until after the call, this reentrancy guard stops the attacker's receive() from completing the attack. For learning purposes only.
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
contract ReentrancyGuard {
bool private guardLocked;
modifier noReentry() {
require(!guardLocked, "Prevented by noReentry in ReentrancyGuard");
guardLocked = true;
_;
guardLocked = false;
}
}
contract Attackee is ReentrancyGuard {
mapping(address => uint) public attackeeBalances;
function depositIntoAttackee() external payable {
attackeeBalances[msg.sender] += msg.value;
}
function withdrawFromAttackee() external noReentry {
uint senderBalance = attackeeBalances[msg.sender];
require(senderBalance > 0);
(bool success, ) = address(msg.sender).call{ value: senderBalance }("");
require(success, "withdrawFromAttackee failed to send");
attackeeBalances[msg.sender] = 0;
}
function getBalanceFromAttackee() external view returns (uint) {
return address(this).balance;
}
}
contract Attacker {
Attackee public contractToAttack;
constructor(address _contractToAttackAddress) {
contractToAttack = Attackee(_contractToAttackAddress);
}
//this is called when Attackee sends Ether to this contract (Attacker)
receive() external payable {
//comment this out to allow the withdrawal
if(address(contractToAttack).balance >= 1 ether) {
contractToAttack.withdrawFromAttackee();
}
}
function depositIntoAttackee() external payable {
require(msg.value >= 1 ether);
contractToAttack.depositIntoAttackee{value: msg.value}();
}
function performAttack() external {
contractToAttack.withdrawFromAttackee();
}
function getBalanceFromAttacker() external view returns (uint) {
return address(this).balance;
}
}
@nathan-websculpt
Copy link
Author

Used as an example in This Blog Post

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment