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来创建合约地址就可以了