CTF-Merkle
题目原代码:
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.13;
library MerkleProof { function verify( bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool) { return processProof(proof, leaf) == root; }
function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) { bytes32 computedHash = leaf; for (uint256 i = 0; i < proof.length; i++) { bytes32 proofElement = proof[i]; if (computedHash <= proofElement) { // Hash(current computed hash + current element of the proof) computedHash = keccak256(abi.encodePacked(computedHash, proofElement)); } else { // Hash(current element of the proof + current computed hash) computedHash = keccak256(abi.encodePacked(proofElement, computedHash)); } } return computedHash; } }
contract Merkle { uint public amount = 1; address public owner; bytes20 mask = hex"ff00000000000000000000000000000000000000"; bytes32 public merkleRoot; // 一开始合约有1ether constructor(bytes32 root) payable { require(msg.value == 1 ether); owner = msg.sender; merkleRoot = root; }
// 只要调用者地址的第一个高字节和owner一样即可 modifier onlyOwner() { require(mask & bytes20(msg.sender) == mask & bytes20(owner)); _; }
// 获取a,b两个值的大值 function min(uint a,uint b) public view returns(uint){ return a > b ? a : b; } // 取钱:需要通过merkle树验证,可以发给任何地址,一次最多取1wei function withdraw(bytes32[] memory proof,address to) public returns(bool){ bytes32 leaf = keccak256(abi.encodePacked(msg.sender)); require(MerkleProof.verify(proof, merkleRoot, leaf), "Merkle Proof Verification failed"); uint balance = address(this).balance; // 这里的amount没啥用,因为balnace一定是大于amount的,将本合约中的所有钱给到to地址 payable(to).transfer(min(amount,balance)); }
function balanceOf() public view returns(uint){ return address(this).balance; } function setMerkleroot(bytes32 _merkleroot) external onlyOwner { merkleRoot = _merkleroot; }
// 任务是将合约中的余额归零 function Complete() external { require(address(this).balance == 0); } }
|
要求让合约的余额变为零
这里先扩展一下,&,|,^,~,的操作,都是比较二进制
&:俩个数相同为1,不同为0
|:俩个数只少有一个为1,就为1.
^:俩个不同就为1,俩个相同就为0.
~:全部变为相反的数字
这个题的思路就很简单,就是要将自己成为白名单上的,然后就可以更改root,调用withdraw函数,撤回所有的资金,然后用create2来创建合约地址就可以了