code4rena-2021-06-pooltogether-m07

[M-07] Using transferFrom on ERC721 tokens

보고서

Summary

CA에게 ERC721을 transferFrom로 보내는 경우 컨트랙트에 ERC721을 꺼내는 기능이 없다면 영원히 꺼낼 수 없으므로 safeTransferFrom로 ERC721을 받을 준비가 된 CA에게만 리워드를 주도록 하자.

Keyword

erc721, safeTransferFrom

Vulnerability

PrizePool.awardExternalERC721 함수는 ControlledToken이 아닌 외부 토큰 중, ERC721을 이용하여 복권 당첨 리워드를 제공하는 함수이다. ERC721 토큰을 이동할 때 safeTransferFrom 대신 transferFrom 함수를 이용했다. 만약 당첨자 주소가 CA이고, 이 컨트랙트에서 ERC721 리시브 훅을 구현하지 않았다면 받은 ERC721을 꺼낼 수 없을 것이다.

  function awardExternalERC721(
    address to,
    address externalToken,
    uint256[] calldata tokenIds
  )
    external override
    onlyPrizeStrategy
  {
    ...
    for (uint256 i = 0; i < tokenIds.length; i++) {
      IERC721Upgradeable(externalToken).transferFrom(address(this), to, tokenIds[i]);
    }
    ...
  }

Impact

리워드로 받은 ERC721을 꺼낼 수 없어 lock된다.

Mitigation

ERC721 이동 시 transferFrom 대신 safeTransferFrom를 사용한다. 다만 당첨자가 악의적으로 ERC721을 받기를 거부하는 DoS가 발생할 수 있으므로, try-catch문으로 완화하자.

Memo

주최자측은 low 심각도라 했지만 심판이 medium으로 동의했다.


tags: bughunting, pooltogether, smart contract, solidity, erc721, severity medium