code4rena-2023-12-shell-protocol-l02

[L-02] Interactions is susceptible to read-only reentrancy

보고서

Summary

인터렉션이 끝난 후에야 Ocean 토큰을 소각하기 때문에 read-only 재진입이 가능하다.

Keyword

read-only reentrancy

Vulnerability

인터렉션이 끝난 후에야 Ocean 토큰을 소각 또는 민팅하기 때문에, 재진입의 여지가 있다.

@>      (inputToken, inputAmount, outputToken, outputAmount) = _executeInteraction(
                interaction, interactionType, externalContract, specifiedToken, interaction.specifiedAmount, userAddress
            );
        }
 
        // if _executeInteraction returned a positive value for inputAmount,
        // this amount must be deducted from the user's Ocean balance
        if (inputAmount > 0) {
            // since uint, same as (inputAmount != 0)
@>          _burn(userAddress, inputToken, inputAmount);
        }
 
        // if _executeInteraction returned a positive value for outputAmount,
        // this amount must be credited to the user's Ocean balance
        if (outputAmount > 0) {
            // since uint, same as (outputAmount != 0)
@>          _mint(userAddress, outputToken, outputAmount);
        }

ERC721 토큰을 unwrap 하는 상황을 생각해보자. 먼저 _executeInteraction 에서 유저에게 ERC721을 돌려준다. 이 때 safeTransferFrom 를 사용하므로 토큰 수신자가 컨트랙트라면 리시브 훅이 실행될 것이다. 아직 인터렉션이 끝나지 않았으므로, 리시브 훅에서는 ERC721과 shERC721을 둘 다 가진 상태가 된다. shERC721의 소각은 인터렉션이 끝난 후 실행되기 때문이다.

    function _erc721Unwrap(address tokenAddress, uint256 tokenId, address userAddress, uint256 oceanId) private {
@>      IERC721(tokenAddress).safeTransferFrom(address(this), userAddress, tokenId);
        emit Erc721Unwrap(tokenAddress, tokenId, userAddress, oceanId);
    }

향후 대출/차입같은 상호작용이 더 많아진다면 read-only 재진입으로 인한 이슈가 발생할 수 있다.

Impact

read-only 재진입이 가능하다.

Mitigation

소각은 먼저 하는 게 좋다.


tags: bughunting, shell protocol, smart contract, solidity, reentrancy, severity low