Hey, why not become the Keeper of the Donation? 😉
How to Submit a Solution:
Use the below submission form to submit the solution: https://quillaudits.typeform.com/QuillCTF
Objective of CTF
Initially, you are a hacker. Not the owner or the keeper of Donate contract.
The purpose is to call keeperCheck()
Function and get true;
Note: You can create POCs using Foundry/Hardhat. Without proper POC, your submissions will not be accepted.
Contract Code:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
contract Donate {
event t1(bytes _sig);
address payable public keeper;
address public owner;
event newDonate(address indexed, uint amount);
modifier onlyOwner() {
require(
msg.sender == owner || msg.sender == address(this),
"You are not Owner"
);
_;
}
constructor(address _keeper) {
keeper = payable(_keeper);
owner = msg.sender;
}
function pay() external payable {
keeper.transfer(msg.value);
emit newDonate(msg.sender, msg.value);
}
function changeKeeper(address _newKeeper) external onlyOwner {
keeper = payable(_newKeeper);
}
function secretFunction(string memory f) external {
require(
keccak256(bytes(f)) !=
0x097798381ee91bee7e3420f37298fe723a9eedeade5440d4b2b5ca3192da2428,
"invalid"
);
(bool success, ) = address(this).call(
abi.encodeWithSignature(f, msg.sender)
);
require(success, "call fail");
}
function keeperCheck() external view returns (bool) {
return (msg.sender == keeper);
}
}
Foundry setUp:
(You can also use other frameworks like Hardhat or Brownie)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.7;
import "forge-std/Test.sol";
import "../src/donate.sol";
contract donateHack is Test {
Donate donate;
address keeper = makeAddr("keeper");
address owner = makeAddr("owner");
address hacker = makeAddr("hacker");
function setUp() public {
vm.prank(owner);
donate = new Donate(keeper);
}
function testhack() public {
vm.startPrank(hacker);
// Hack Time
}
}