成功调用 ctf 函数, 函数参数 target 是你部署的合约地址, 且实现了 IBoolGiver 接口。
在 ctf 函数中
function ctf(address target) external view returns (bool) {
bool p = IBoolGiver(target).giveBool();
bool q = IBoolGiver(target).giveBool();
require((p && q) != (p || q), "bad bools");
require(msg.sender == tx.origin, "bad sender");
return true;
}在条件中要求 (p && q) != (p || q), 即前后调用 giveBool() 应返回不同的布尔值。
注意到 giveBool 有 view 修饰符, 意味着不能通过全局变量的方式修改。只能读。
唯一变化的是在通过合约调用 view 方法时, gas 的变化。
可以记录两次调用 giveBool 方法的 gasleft()
function giveBool() external view override returns (bool) {
uint gasLeft = gasleft();
console.log(gasLeft); // 1040414411 | 1040408946
return gasLeft < threshold;
}设置阈值 threshold 处于这两个值中间, 例如设置为 1040412000
第一次调用时 gasLeft 大于 threshold, 返回 false
第一次调用时 gasLeft 小于于 threshold, 返回 true
contract TrueXORAttacker is IBoolGiver {
uint public threshold = 1040412000;
function giveBool() external view override returns (bool) {
uint gasLeft = gasleft();
console.log(gasLeft); // 1040414411 | 1040408946
return gasLeft < threshold;
}
}
contract TrueXORTest is Test {
TrueXOR public trueXOR;
TrueXORAttacker public trueXORAttacker;
address public deployer;
function setUp() public {
deployer = vm.addr(1);
vm.startPrank(deployer);
trueXOR = new TrueXOR();
trueXORAttacker = new TrueXORAttacker();
vm.stopPrank();
}
function testCallCTF() public {
vm.startPrank(deployer, deployer);
bool res = trueXOR.ctf(address(trueXORAttacker));
assertEq(res, true);
vm.stopPrank();
}
}