Skip to content

Lucky Faucet

code / Description

function setBounds(int64 _newLowerBound, int64 _newUpperBound) public {
    require(_newUpperBound <= 100_000_000, "100M wei is the max upperBound sry");
    require(_newLowerBound <=  50_000_000,  "50M wei is the max lowerBound sry");
    require(_newLowerBound <= _newUpperBound);
    upperBound = _newUpperBound;
    lowerBound = _newLowerBound;
}
function sendRandomETH() public returns (bool, uint64) {
    int256 randomInt = int256(blockhash(block.number - 1));
    uint64 amountToSend = uint64(randomInt % (upperBound - lowerBound + 1) + lowerBound); 
    bool sent = msg.sender.send(amountToSend);
    return (sent, amountToSend);
}

Challenge Analysis

The "Lucky Faucet" challenge involves a smart contract designed to send a random amount of ETH based on a pseudo-random number derived from the blockhash and the set bounds. The critical flaw lies in the handling of integer underflow when setting the bounds, allowing for unexpected behavior when calculating the amount of ETH to send.

Solution

The solution exploits the type casting vulnerability by setting the upperBound and lowerBound such that the calculation randomInt % (upperBound - lowerBound + 1) + lowerBound results in a negative value. When this negative value is cast to an unsigned integer (uint64), it becomes a very large positive number, thereby exploiting the contract to send a large amount of ETH. This is achieved by calling setBounds with values that lead to a negative outcome for the amount to send, and then invoking sendRandomETH to trigger the flawed logic and cast the negative result to an unexpectedly large positive value.

Adjust both upperBound and lowerBound to -1, ensuring that the expression randomInt % (upperBound - lowerBound + 1) consistently equals zero. Consequently, the amountToSend will always be equal to lowerBound.

Final Exploit

cast send --rpc-url <RPC_URL> --private-key <PRIVATE_KEY> <TARGET_CONTRACT_ADDRESS> "setBounds(int64,int64)" -- -1 -1 
cast send --rpc-url <RPC_URL> --private-key <PRIVATE_KEY> <TARGET_CONTRACT_ADDRESS> "sendRandomETH()"

AUTHOR:

Mohammad2024 / Pr1m3d Team