Skip to content

Instantly share code, notes, and snippets.

@nathan-websculpt
Created September 22, 2021 15:55
Show Gist options
  • Select an option

  • Save nathan-websculpt/eafd85362f0969814cc1e5060fbb5c2d to your computer and use it in GitHub Desktop.

Select an option

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
Copy Markdown
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